Novembre 2024 | Lun | Mar | Mer | Jeu | Ven | Sam | Dim |
---|
| | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | | Calendrier |
|
|
| Gestion de collisions entre sprites en 2D | |
| | |
Auteur | Message |
---|
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Gestion de collisions entre sprites en 2D Ven 19 Oct 2012 - 22:55 | |
| Suite à un échange de messages privés, je publie ici le résultat: un exemple de la gestion de collision entre sprites dans une scene2D. Remarques: 1. comme la commande COLOR ne fonctionne pas pour le moment pour une scene2d, je contourne le problème avec un picture qui sera coloré, sauvegardé dans un fichier BMP puis supprimé. Ce fichier sera ensuite chargé dans la scene2d comme couleur de fond. Et tant qu'on y est, on emploie la même astuce pour colorer les sprites. 2. la notion même de collusion entre sprites est vague. Un sprite est un rectangle, au départ de 200x200. Il peut être redimensionné par les commandes SCALE, dans une ou deux directions, pour obtenir des rectangles de tailles variés. Mais cela reste des rectangles. La collision entre rectangles se résume au fait que le haut de l'un touche le bas de l'autre ou inversement, ou que la gauche de l'un touche la droite de l'autre ou inversement. Dans l'exemple qui suit, j'ai fait exactement cela. Et bien que mes sprites soient des carrés, les formules sont réellement faites pour des rectangles, en respectant les largeurs et hauteurs. 3. un sprite peut recevoir une image par un fichier BMP dont la oouleur noire (RGB=0,0,0) sera traité comme couleur transparente (ces pixels ne sont tout simplement pas affichés). Maintenant, que veut dire "collision" pour un tel sprité ? Qu'un pixel non-noir d'un sprite touche un pixel non-noir d'un autre sprite ? Très complexe. Malheureusement, nous n'avons pas de moyen simple de faire cela en Panoramic. Donc, on revient à l'idée de la collusion entre 2 rectangles, et voici le code (Panoramic V0.9.24i4): - Code:
-
' collisions_en_scene2d.bas
dim i%, choc% dim larg1%, haut1%, larg2%, haut2%
picture 100 : height 100,200 : width 100,200 color 100,0,0,255 : file_save 100,"sprite_1.bmp" color 100,255,0,0 : file_save 100,"sprite_2.bmp" delete 100
picture 100 : full_space 100 : color 100,220,220,220 file_save 100,"vide_2D.bmp" delete 100
scene2d 100 : full_space 100 : file_load 100,"vide_2d.bmp" : file_delete "vide_2d.bmp"
sprite 1 : sprite_file_load 1,"sprite_1.bmp" : file_delete "sprite_1.bmp" sprite_position 1,10,100 : sprite_scale 1,1/4,1/4 larg1% = 200/4 : haut1% = 200/4 sprite 2 : sprite_file_load 2,"sprite_2.bmp" : file_delete "sprite_2.bmp" sprite_position 2,300,150 : sprite_scale 2,1/3,1/3 larg2% = int(200/3+0.5) : haut2% = int(200/3+0.5)
for i%=10 to 400 sprite_position 1,i%,10+int(140*i%/400) collision(1,2) if choc%=1 message "Collision !" exit_for end_if pause 10 next i%
end
sub collision(s1%,s2%) dim_local x1%,y1%, x2%,y2% choc% = 1 x1% = sprite_x_position(1) y1% = sprite_y_position(1) x2% = sprite_x_position(2) y2% = sprite_y_position(2) ' le bas du sprite 1 touche le haut du sprite 2 if (y1%+haut1%-1)=y2% if (x1%<=x2%) and ((x1%+larg1%-1)>x2%) then exit_sub if (x1%>x2%) and (x1%<=(x2%+larg2%-1)) then exit_sub end_if ' le haut du sprite 1 touche le bas du sprite 2 if y1%=(y2%+haut2%-1) if (x1%<=x2%) and ((x1%+larg1%-1)>x2%) then exit_sub if (x1%>x2%) and (x1%<=(x2%+larg2%-1)) then exit_sub end_if ' la gauche du sprite 1 touche la droite du sprite 2 if (x1%+larg1%-1)=x2% if (y1%<=y2%) and ((y1%+haut1%-1)>y2%) then exit_sub if (y1%>y2%) and (y1%<=(y2%+haut2%-1)) then exit_sub end_if ' la droite du sprite 1 touche la gauche du sprite 2 if x1%=(x2%+larg2%-1) if (y1%<=y2%) and ((y1%+haut1%-1)>y2%) then exit_sub if (y1%>y2%) and (y1%<=(y2%+haut2%-1)) then exit_sub end_if choc% = 0 end_sub
J'espère que cela vous inspirera. J'avais posté un exemple de collusion 3D dans un autre fil de discussion...
Dernière édition par Klaus le Sam 20 Oct 2012 - 10:59, édité 1 fois | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 0:23 | |
| Je me suis permis de modifier un peu l'exemple de Klaus et de rajouter quelques commentaires, le principe de la collision utilisé est le recouvrement et non le touché du sprite. Tout simplement par ce qu'il peut y avoir un "pas" qui fait que le bord du sprite 1 ne touche jamais l'un des bord du sprite2 mais se retrouve directement "dedans" en fonction du pas de déplacement choisi. Ca donne ça: Pour la procédure, j'aurais voulu éviter de mettre la taille des sprites, mais width(sprite1) et height(sprite1) ne semblent pas fonctionner, du coup ils sont passés en paramètres - Code:
-
' collisions_en_scene2d.bas
dim i%, choc%,d_choc%
' Création des 2 sprites de test picture 100 : height 100,200 : width 100,200 color 100,0,0,255 : file_save 100,"sprite_1.bmp" color 100,255,0,0 : file_save 100,"sprite_2.bmp"
' Création d'une image vide pour le fond full_space 100 : color 100,220,220,220 :file_save 100,"vide_2D.bmp": delete 100
' Creation de l'air de déplacement des sprites scene2d 100 : full_space 100 : file_load 100,"vide_2d.bmp"
' Création et chargement des sprites sprite 1 : sprite_file_load 1,"sprite_1.bmp" : sprite_position 1,10,100 : sprite_scale 1,1/4,1/4 sprite 2 : sprite_file_load 2,"sprite_2.bmp" : sprite_position 2,300,150 : sprite_scale 2,1/3,1/3
' Boucle de déplacement quelconque for i%=10 to 4000 sprite_position 1,i%,10+int(140*i%/400) : ' On bouge le sprite collision(1,50,50,2,66,66) : ' On teste la collision su sprite1 et du sprite 2 : ' Paramètres N°sprite, Largeur, hauteur et pareil pour le second if choc%=1 : ' Si la procédure retourne qu'il y a collision message "Collision !" : ' on traite l'événement (on pourrait changer le sens, supprimer un sprite, ... exit_for : ' Ici on affiche un message et on sort de la boucle end_if pause 5 : ' Attente avant déplacement du sprite next i%
end
sub collision(s1%,larg1%,haut1%,s2%,larg2%,haut2%) dim_local x1%,y1%, x2%,y2% x1% = sprite_x_position(s1%): y1% = sprite_y_position(s1%) x2% = sprite_x_position(s2%): y2% = sprite_y_position(s2%) ' le bas du sprite 1 touche le haut du sprite 2 if (((y1%+haut1%) >= y2%) and (y1% <= (y2%+haut2%)) and ((x1%+larg1%) >= x2%) and (x1% <= (x2%+larg2%))) choc% = 1 : ' Si le rectangle du sprite 1 recouvre partiellement celui du sprite 2, il y a collision else choc% = 0 : ' Sinon, on retourne qu'ils ne se touchent pas end_if end_sub
| |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 0:32 | |
| Merci, Jicehel. Voici un autre exemple sur lequel tu peux t'exercer: je fais bouger les deux sprites avec des vitesses verticales et horizontales différentes, et le programme s'arrête lorsqu'ils se touchent. - Code:
-
' collisions_en_scene2d.bas
caption 0,"Interrompre par Echap"
dim i%, choc% dim larg%(2), haut%(2) dim delta_x%(2), delta_y%(2) dim dir_x%(2), dir_y%(2)
delta_x%(1) = 2 : delta_y%(1) = 4 delta_x%(2) = 2 : delta_y%(2) = 1 dir_x%(1) = 1 : dir_y%(1) = 1 dir_x%(2) = 1 : dir_y%(2) = 1
picture 100 : height 100,200 : width 100,200 color 100,0,0,255 : file_save 100,"sprite_1.bmp" color 100,255,0,0 : file_save 100,"sprite_2.bmp" delete 100
picture 100 : full_space 100 : color 100,220,220,220 file_save 100,"vide_2D.bmp" delete 100
scene2d 100 : full_space 100 : file_load 100,"vide_2d.bmp" : file_delete "vide_2D.bmp"
sprite 1 : sprite_file_load 1,"sprite_1.bmp" : file_delete "sprite_1.bmp" sprite_position 1,10,100 : sprite_scale 1,1/4,1/4 larg%(1) = 200/4 : haut%(1) = 200/4 sprite 2 : sprite_file_load 2,"sprite_2.bmp" : file_delete "sprite_2.bmp" sprite_position 2,300,150 : sprite_scale 2,1/3,1/3 larg%(2) = int(200/3+0.5) : haut%(2) = int(200/3+0.5)
repeat move(1) if choc%=0 then move(2) pause 5 until (choc%=1) or scancode=27
end
sub move(s%) dim_local i% ' déplacer horizontalement if dir_x%(s%)>0 : ' à droite if (sprite_x_position(s%)+larg%(s%)-1)>=(width(100)-1) dir_x%(s%) = 0 - dir_x%(s%) end_if else : ' à gauche if sprite_x_position(s%)<=0 dir_x%(s%) = 0 - dir_x%(s%) end_if end_if for i%=1 to delta_x%(s%) sprite_x_position s%,sprite_x_position(s%) + dir_x%(s%) collision(1,2) if choc%=1 then exit_sub next i% ' déplacer verticalement if dir_y%(s%)>0 : ' en bas if (sprite_y_position(s%)+haut%(s%)-1)>=(height(100)-1) dir_y%(s%) = 0 - dir_y%(s%) end_if else : ' en haut if sprite_y_position(s%)<=0 dir_y%(s%) = 0 - dir_y%(s%) end_if end_if for i%=1 to delta_y%(s%) sprite_y_position s%,sprite_y_position(s%) + dir_y%(s%) collision(1,2) if choc%=1 then exit_sub next i% end_sub
sub collision(s1%,s2%) dim_local x1%,y1%, x2%,y2% choc% = 1 x1% = sprite_x_position(s1%) y1% = sprite_y_position(s1%) x2% = sprite_x_position(s2%) y2% = sprite_y_position(s2%) ' le bas du sprite 1 touche le haut du sprite 2 if (y1%+haut%(1)-1)=y2% if (x1%<=x2%) and ((x1%+larg%(1)-1)>x2%) then exit_sub if (x1%>x2%) and (x1%<=(x2%+larg%(2)-1)) then exit_sub end_if ' le haut du sprite 1 touche le bas du sprite 2 if y1%=(y2%+haut%(2)-1) if (x1%<=x2%) and ((x1%+larg%(1)-1)>x2%) then exit_sub if (x1%>x2%) and (x1%<=(x2%+larg%(2)-1)) then exit_sub end_if ' la droite du sprite 1 touche la gauche du sprite 2 if (x1%+larg%(1)-1)=x2% if (y1%<=y2%) and ((y1%+haut%(1)-1)>y2%) then exit_sub if (y1%>y2%) and (y1%<=(y2%+haut%(2)-1)) then exit_sub end_if ' la gauche du sprite 1 touche la droite du sprite 2 if x1%=(x2%+larg%(2)-1) if (y1%<=y2%) and ((y1%+haut%(1)-1)>y2%) then exit_sub if (y1%>y2%) and (y1%<=(y2%+haut%(2)-1)) then exit_sub end_if choc% = 0 end_sub
Dernière édition par Klaus le Sam 20 Oct 2012 - 10:58, édité 2 fois | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 1:43 | |
| Encore une variante du programme de Klaus, la collision entre les 2 sprites fait changer le sens des 2 sprites, mais il faudrait tester comment s'effectue la colilsion pour n'inverser le mouvement que dans certaines directions en fonction du sens de la collision. mais bon il est tard et c'est l'heure d'aller dormir ... Bonne nuit - Code:
-
' collisions_en_scene2d.bas
caption 0,"Interrompre par Echap"
dim i%, choc% dim larg%(2), haut%(2) dim delta_x%(2), delta_y%(2) dim dir_x%(2), dir_y%(2)
delta_x%(1) = 2 : delta_y%(1) = 4 : delta_x%(2) = 2 : delta_y%(2) = 1 dir_x%(1) = 1 : dir_y%(1) = 1 : dir_x%(2) = 1 : dir_y%(2) = 1
' Création des 2 sprites de test picture 100 : height 100,200 : width 100,200 color 100,0,0,255 : file_save 100,"sprite_1.bmp" color 100,255,0,0 : file_save 100,"sprite_2.bmp"
' Création d'une image vide pour le fond full_space 100 : color 100,220,220,220 :file_save 100,"vide_2D.bmp": delete 100
' Creation de l'air de déplacement des sprites scene2d 100 : full_space 100 : file_load 100,"vide_2d.bmp"
' Création et chargement des 2 sprites sprite 1 : sprite_file_load 1,"sprite_1.bmp" sprite_position 1,10,100 : sprite_scale 1,1/4,1/4 : larg%(1) = 200/4 : haut%(1) = 200/4 sprite 2 : sprite_file_load 2,"sprite_2.bmp" sprite_position 2,300,150 : sprite_scale 2,1/3,1/3 : larg%(2) = int((200/3)+0.5) : haut%(2) = int((200/3)+0.5)
' Boucle de déplacement repeat move(1,2) move(2,1) pause 5 until scancode=27
end
' Procédure de déplacement sub move(s1%,s2%) dim_local i%, delta% ' déplacer horizontalement if dir_x%(s1%)>0 : ' à droite if (sprite_x_position(s1%)+larg%(s1%))>=(width(100)) dir_x%(s1%) = 0 - dir_x%(s1%) end_if else : ' à gauche if sprite_x_position(s1%)<=0 dir_x%(s1%) = 0 - dir_x%(s1%) end_if end_if ' déplacer verticalement if dir_y%(s1%)>0 : ' en bas if (sprite_y_position(s1%)+haut%(s1%))>=(height(100)) dir_y%(s1%) = 0 - dir_y%(s1%) end_if else : ' en haut if sprite_y_position(s1%)<=0 dir_y%(s1%) = 0 - dir_y%(s1%) end_if end_if if abs(delta_x%(s1%))> abs(delta_y%(s1%)) delta%=abs(delta_x%(s1%)) else delta%=abs(delta_y%(s1%)) end_if for i%=0 to delta% sprite_position s1%,sprite_x_position(s1%) + dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)),sprite_y_position(s1%) + dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) collision(s1%,s2%) if choc%=1 then exit_for next i% if choc%=1 then change_dir(s1%,s2%) for i%=0 to delta% sprite_position s1%,sprite_x_position(s1%) + dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)),sprite_y_position(s1%) + dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) next i% end_sub
sub change_dir(s1%,s2%) dir_x%(s1%) = 0-dir_x%(s1%): dir_y%(s1%) = 0-dir_y%(s1%) dir_x%(s2%) = 0-dir_x%(s2%): dir_y%(s2%) = 0-dir_y%(s2%) end_sub
sub collision(s1%,s2%) dim_local x1%,y1%, x2%,y2% x1% = sprite_x_position(s1%): y1% = sprite_y_position(s1%) x2% = sprite_x_position(s2%): y2% = sprite_y_position(s2%) ' le bas du sprite 1 touche le haut du sprite 2 if (((y1%+haut%(1)) >= y2%) and (y1% <= (y2%+haut%(2))) and ((x1%+larg%(1)) >= x2%) and (x1% <= (x2%+larg%(2)))) choc% = 1 : ' Si le rectangle du sprite 1 recouvre partiellement celui du sprite 2, il y a collision else choc% = 0 : ' Sinon, on retourne qu'ils ne se touchent pas end_if end_sub | |
| | | Nardo26
Nombre de messages : 2294 Age : 56 Localisation : Valence Date d'inscription : 02/07/2010
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 10:44 | |
| Juste une petite remarque en passant que j'ai déjà faite à ygeronimi : Vos programme génèrent des fichier, ok... c'est nécessaire mais quand le programme se termine, cela serait bien de faire le ménage... ) Car ça devient vite un foutoir sur les disques !!! | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 10:59 | |
| Tu as raison, Nardo26. J'ai corrigé mes modules dans ce sens. | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 13:05 | |
| Klaus dans mon programme d'hier, je ne sais pas ce que tu en penses, mais l'idée dans la boucle de déplacement c'est de faire les 2 mouvements en même temps pour ne pas avoir un déplacement en escalier (qui ne se voit pas avec des petites valeurs et une vitesse importante mais qui pourrait se voir avec un delta plus grand ou un déplacement plus lent). Que penses tu de la méthode de déplacement Klaus ? | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 13:40 | |
| C'est ce que j'ai essayé de faire au début. Mais comme dans le cas général, les composantes horizontales et verticales du vecteur de déplacement ne sont pas identiques, il y a forcément une gymnastique à faire au niveau de la boucle de positionnement. Et même pire: si tu fais le déplacement d'un seul coup pour tester la collision après déplacement, le sprite en mouvement a probablement déjà dépassé la limite de l'autre sprite, et la détection de collision selon ma formule ne marche plus. Il faudrait alors sophistiquer les équations de critère de collision.
S'il y a des amateurs pour cela, tant mieux. Mon but était simplement de présenter les difficultés dans la gestion des collisions dans un scene2d et de montrer une possibilité de gesrion de ces collisions, suite à un échange par MP avec un panoramicien, et je voulais faire profiter tout le monde du résultat.
L'idéal serait bien sûr que Jack transpose la fonction 3d_collision à une fonction 2d_collision...
Ceci dit, j'ai une autre idée. Je n'ai pas essayé, mais on pourrait peut-être utiliser la scene3d avec des objets 3d_plane pour simuler les sprites. On laisserait les coordonnées z à zéro et on ne travaillerait que dans le plan x-y. Et du coup, on a une simulation de scene2d avec la collision gérée de façon native par Panoramic. Qu'est-ce que tu en penses ? | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 18:57 | |
| Je mets une variante fait vite fait, mais il y avait une grosse erreur dans mon précédent source (des 1 et 2 étaient resté en fixe à la place de s1% et s2% dans les procédures ...) Comme il y a plus de sprites, je trouve la démo plus visuelle et j'espère qu'elle reste simple d'accès. Klaus et Nardo, j'ai repris le principe de Klaus pour nettoyer les images temporaire Vous avez raison puisque l'on fait un programme autonome, autant laisser la place propre après usage Les nouveaux, pourquoi ne faites vous pas de commentaire, c'est pour vous que Klaus a fait ce programme d'exemple. Est-ce que ça vous guide ? Est-ce que cela vous permet de comprendre les collisions ? Arrivez-vous à l'adapter à vos programmes ? - Code:
-
' collisions_en_scene2d.bas
caption 0,"Interrompre par Echap"
dim i%, choc% : ' i% compteur temporaire et choc% variable globale permettant de savoir s'il y a collision ou non dim nb_sprites : nb_sprites = 15 : ' Constante indiquant le nombre de sprites utilisés dim larg%(nb_sprites), haut%(nb_sprites) : ' tableau contenant les dimensions des sprites dim delta_x%(nb_sprites), delta_y%(nb_sprites) : ' vitesses horizontales et verticales des sprites dim dir_x%(nb_sprites), dir_y%(nb_sprites) : ' directions horizontales et verticales des sprites dim c% : c% = 255/nb_sprites : ' diviseur pour le calcul des couleurs
' Initialisation du sprite 1 delta_x%(1) = 2 : delta_y%(1) = 2 : dir_x%(1) = 1 : dir_y%(1) = 1
' Initialisation des autres sprites for i%=2 to nb_sprites delta_x%(i%) = 4 : delta_y%(i%) = 3 dir_x%(i%) = 1 : dir_y%(i%) = 1 next i%
' Création des images pour les sprites de test picture 100 : height 100,200 : width 100,200 color 100,0,0,255 : file_save 100,"sprite_1.bmp" for i%=2 to nb_sprites color 100,255 - i%*c%,i%*c%,0 : file_save 100,"sprite_"+str$(i%)+".bmp" next i%
' Création d'une image vide pour le fond full_space 100 : color 100,220,220,220 :file_save 100,"vide_2D.bmp": delete 100
' Creation de l'air de déplacement des sprites et supression du fond temporaire scene2d 100 : hide 100 : full_space 100 : file_load 100,"vide_2d.bmp" : file_delete "vide_2D.bmp"
' Création et chargement des sprites et suppression des images temporaires sprite 1 : sprite_file_load 1,"sprite_1.bmp" : file_delete "sprite_1.bmp" sprite_position 1,180,120 : sprite_scale 1,1/4,1/4 : larg%(1) = int(200/4) : haut%(1) = int(200/4)
for i%=2 to nb_sprites sprite i% : sprite_file_load i%,"sprite_"+str$(i%)+".bmp" : file_delete "sprite_"+str$(i%)+".bmp" sprite_position i%,400-rnd(400),300 - rnd(300) : sprite_scale i%,1/3,1/3 : larg%(i%) = int(200/3) : haut%(i%) = int(200/3) test_recouvrement(i%,1) : ' procédure pour empécher que le sprite 1 ne soit recouvert par un autre sprite au démarrage next i%
show 100 : ' On montre la scene
' Boucle de déplacement repeat for i%=2 to nb_sprites move(i%,1) next i% until scancode=27
end
' Procédure de déplacement sub move(s1%,s2%) dim_local i%, delta% ' déplacer horizontalement if dir_x%(s1%)>0 : ' à droite if (sprite_x_position(s1%)+larg%(s1%))>=(width(100)) dir_x%(s1%) = 0 - dir_x%(s1%) end_if else : ' à gauche if sprite_x_position(s1%)<=0 dir_x%(s1%) = 0 - dir_x%(s1%) end_if end_if ' déplacer verticalement if dir_y%(s1%)>0 : ' en bas if (sprite_y_position(s1%)+haut%(s1%))>=(height(100)) dir_y%(s1%) = 0 - dir_y%(s1%) end_if else : ' en haut if sprite_y_position(s1%)<=0 dir_y%(s1%) = 0 - dir_y%(s1%) end_if end_if if abs(delta_x%(s1%))> abs(delta_y%(s1%)) delta%=abs(delta_x%(s1%)) else delta%=abs(delta_y%(s1%)) end_if for i%=0 to delta% sprite_position s1%,sprite_x_position(s1%) + dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)),sprite_y_position(s1%) + dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) collision(s1%,s2%) if choc%=1 then exit_for next i% if choc%=1 then change_dir(s1%,s2%) for i%=0 to delta% sprite_position s1%,sprite_x_position(s1%) + dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)),sprite_y_position(s1%) + dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) next i% end_sub
' Inverse les directions sub change_dir(s1%,s2%) dir_x%(s1%) = 0-dir_x%(s1%): dir_y%(s1%) = 0-dir_y%(s1%) dir_x%(s2%) = 0-dir_x%(s2%): dir_y%(s2%) = 0-dir_y%(s2%) end_sub
' Test s'il y a collision sub collision(s1%,s2%) dim_local x1%,y1%, x2%,y2% x1% = sprite_x_position(s1%): y1% = sprite_y_position(s1%) x2% = sprite_x_position(s2%): y2% = sprite_y_position(s2%) ' le bas du sprite 1 touche le haut du sprite 2 if (((y1%+haut%(s1%)) >= y2%) and (y1% <= (y2%+haut%(s2%))) and ((x1%+larg%(s1%)) >= x2%) and (x1% <= (x2%+larg%(s2%)))) choc% = 1 : ' Si le rectangle du sprite 1 recouvre partiellement celui du sprite 2, il y a collision else choc% = 0 : ' Sinon, on retourne qu'ils ne se touchent pas end_if end_sub
' Test s'il y a recouvrement entre 2 sprites sub test_recouvrement(s1%,s2%) dim_local x1%,y1%, x2%,y2% x1% = sprite_x_position(s1%): y1% = sprite_y_position(s1%) x2% = sprite_x_position(s2%): y2% = sprite_y_position(s2%) ' le bas du sprite 1 touche le haut du sprite 2 while (((y1%+haut%(s1%)) >= y2%) and (y1% <= (y2%+haut%(s2%))) and ((x1%+larg%(s1%)) >= x2%) and (x1% <= (x2%+larg%(s2%)))) sprite_position s1%,400-rnd(400),300 - rnd(300) x1% = sprite_x_position(s1%): y1% = sprite_y_position(s1%) end_while end_sub | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 19:17 | |
| C'est très parlant ce que tu as fait. Mais, sans plonger dans le code: tu as certainement fait le test de collision après avoir effectué le déplacement du sprite, en non pas pixel par pixel comme je l'avais fait. Certes, c'est plus rapide, mais tu vous souvent des sprites "rentrer" dans le sprite bleu avant de faire demi-tour. Si c'étaient des voitures - que de tôle froissée ! | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 19:25 | |
| En fait c'est par ce que j'ai voulu garder la structure de ton programme pour ne pas compliquer, car là on travaille directement sur les sprites. Normalement, ce que je ferais, ce serait travailler sur les coordonnées des sprites sans les déplacer. Puis si il y a collision, on affiche le sprite avec la collision et on change les directions. Sinon on affiche le sprite avec ses nouvelles coordonnées. Je vais coder ça pour illustrer, mais ça change un peu le code et les fonctions | |
| | | Nardo26
Nombre de messages : 2294 Age : 56 Localisation : Valence Date d'inscription : 02/07/2010
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 19:59 | |
| Perso c'est ce que j’aurais fait : anticiper la collision avant l'affichage... | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 20:27 | |
| Voilà, les sprites ne se recouvre plus. Par contre, ils devraient se toucher, mais je pense que le fait qu'il ne se touchent pas est perfectible je pense, mais bon, je n’ai pas trop envie de chercher pourquoi. Il doit y avoir une petite idée ou une petite correction à faire quelque part. - Code:
-
' collisions_en_scene2d.bas
caption 0,"Interrompre par Echap"
dim i%, choc% : ' i% compteur temporaire et choc% variable globale permettant de savoir s'il y a collision ou non dim nb_sprites : nb_sprites = 15 : ' Constante indiquant le nombre de sprites utilisés dim larg%(nb_sprites), haut%(nb_sprites) : ' tableau contenant les dimensions des sprites dim delta_x%(nb_sprites), delta_y%(nb_sprites) : ' vitesses horizontales et verticales des sprites dim dir_x%(nb_sprites), dir_y%(nb_sprites) : ' directions horizontales et verticales des sprites dim pos_x%(nb_sprites), pos_y%(nb_sprites) : ' coordonnées logiques des sprites dim c% : c% = 255/nb_sprites : ' diviseur pour le calcul des couleurs
' Initialisation du sprite 1 delta_x%(1) = 2 : delta_y%(1) = 2 : dir_x%(1) = 1 : dir_y%(1) = 1
' Initialisation des autres sprites for i%=2 to nb_sprites delta_x%(i%) = 4 : delta_y%(i%) = 3 dir_x%(i%) = 1 : dir_y%(i%) = 1 next i%
' Création des images pour les sprites de test picture 100 : height 100,200 : width 100,200 color 100,0,0,255 : file_save 100,"sprite_1.bmp" for i%=2 to nb_sprites color 100,255 - i%*c%,i%*c%,0 : file_save 100,"sprite_"+str$(i%)+".bmp" next i%
' Création d'une image vide pour le fond full_space 100 : color 100,220,220,220 :file_save 100,"vide_2D.bmp": delete 100
' Creation de l'air de déplacement des sprites et supression du fond temporaire scene2d 100 : hide 100 : full_space 100 : file_load 100,"vide_2d.bmp" : file_delete "vide_2D.bmp"
' Création et chargement des sprites et suppression des images temporaires sprite 1 : sprite_file_load 1,"sprite_1.bmp" : file_delete "sprite_1.bmp" pos_x%(1) = 180: pos_y%(1) = 120 sprite_scale 1,1/4,1/4 : larg%(1) = int(200/4) : haut%(1) = int(200/4) sprite_position 1,pos_x%(1),pos_y%(1)
for i%=2 to nb_sprites sprite i% : sprite_file_load i%,"sprite_"+str$(i%)+".bmp" : file_delete "sprite_"+str$(i%)+".bmp" sprite_scale i%,1/5,1/5 : larg%(i%) = int(200/5) : haut%(i%) = int(200/5) pos_x%(i%) = 400-rnd(400): pos_y%(i%) = 300 - rnd(300) test_recouvrement(i%,1) : ' procédure pour empécher que le sprite 1 ne soit recouvert par un autre sprite au démarrage sprite_position i%,pos_x%(i%),pos_y%(i%) next i%
show 100 : ' On montre la scene
' Boucle de déplacement repeat for i%=2 to nb_sprites move(i%,1) next i% until scancode=27
end
' Procédure de déplacement sub move(s1%,s2%) dim_local i%, delta% ' déplacer horizontalement if dir_x%(s1%)>0 : ' à droite if (sprite_x_position(s1%)+larg%(s1%))>=(width(100)) dir_x%(s1%) = 0 - dir_x%(s1%) end_if else : ' à gauche if sprite_x_position(s1%)<=0 dir_x%(s1%) = 0 - dir_x%(s1%) end_if end_if ' déplacer verticalement if dir_y%(s1%)>0 : ' en bas if (sprite_y_position(s1%)+haut%(s1%))>=(height(100)) dir_y%(s1%) = 0 - dir_y%(s1%) end_if else : ' en haut if sprite_y_position(s1%)<=0 dir_y%(s1%) = 0 - dir_y%(s1%) end_if end_if if abs(delta_x%(s1%))> abs(delta_y%(s1%)) delta%=abs(delta_x%(s1%)) else delta%=abs(delta_y%(s1%)) end_if for i%=0 to delta% pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)) pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) collision(s1%,s2%) if choc%=1 then exit_for sprite_position s1%,pos_x%(s1%),pos_y%(s1%) next i% if choc%=1 change_dir(s1%) for i%=0 to delta% pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)) pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) next i% end_if end_sub
' Inverse les directions sub change_dir(s1%) dir_x%(s1%) = 0-dir_x%(s1%): dir_y%(s1%) = 0-dir_y%(s1%) end_sub
' Test s'il y a collision sub collision(s1%,s2%) if (((pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) and ((pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)))) choc% = 1 : ' Si le rectangle du sprite 1 recouvre partiellement celui du sprite 2, il y a collision else choc% = 0 : ' Sinon, on retourne qu'ils ne se touchent pas end_if end_sub
' Test s'il y a recouvrement entre 2 sprites sub test_recouvrement(s1%,s2%) while (((pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) and ((pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)))) pos_x%(s1%) = 400-rnd(400): pos_y%(s1%) = 300 - rnd(300) end_while end_sub | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 21:09 | |
| C'est justement parce que tu ne fais pas le test pixel par pixel, comme dans mon deuxième code. Dans ta technique, il faudrait réduire le déplacement dans les directions x et y s'il y avait dépassement de limite, puis effectuer la collision. C'est ce que j'évite en faisant les déplacements pixel par pixel. | |
| | | Yannick
Nombre de messages : 8635 Age : 53 Localisation : Bretagne Date d'inscription : 15/02/2010
| Sujet: re Sam 20 Oct 2012 - 21:11 | |
| @ Nardo26, Promis, je vais étudier une procédure "Conchita()" | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Gestion de collisions entre sprites en 2D Sam 20 Oct 2012 - 23:01 | |
| Non Klaus, justement, le déplacement se fait normalement au maximum de 1 - Code:
-
for i%=0 to delta% pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)) pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) collision(s1%,s2%) if choc%=1 then exit_for sprite_position s1%,pos_x%(s1%),pos_y%(s1%) next i%
on rajoute comme dans le tient dir_x à chaque boucle Par contre j'ai trouvé pourquoi j'avais laissé des référence fixe dans ma proc ... c'était par ce que j'étais parti de ton programme. Il y a des erreurs dedans. Le programme ne fonctionne que par ce que tu as 2 sprites. En effet, tu fait référence dans collision soit au sprite transmis en paramètre (S1% ou s2%) soit directement à l'indice du sprite dans le tableau (1 ou 2). Ca marche dans la démo puisqu'il ne sont que 2 mais le comportement serait hiératique si la procédure était employée avec d'autres sprites. Je pense que le code est améliorable, mais je mets une petite amélioration telle qu'elle m'ait venu. Si quelqu'un voit une solution plus satisfaisante ou des amélioration, il est le bienvenu ... - Code:
-
' collisions_en_scene2d.bas
caption 0,"Interrompre par Echap"
dim i%, choc% : ' i% compteur temporaire et choc% variable globale permettant de savoir s'il y a collision ou non dim nb_sprites : nb_sprites = 15 : ' Constante indiquant le nombre de sprites utilisés dim larg%(nb_sprites), haut%(nb_sprites) : ' tableau contenant les dimensions des sprites dim delta_x%(nb_sprites), delta_y%(nb_sprites) : ' vitesses horizontales et verticales des sprites dim dir_x%(nb_sprites), dir_y%(nb_sprites) : ' directions horizontales et verticales des sprites dim pos_x%(nb_sprites), pos_y%(nb_sprites) : ' coordonnées logiques des sprites dim c% : c% = 255/nb_sprites : ' diviseur pour le calcul des couleurs
' Initialisation du sprite 1 delta_x%(1) = 2 : delta_y%(1) = 2 : dir_x%(1) = 1 : dir_y%(1) = 1
' Initialisation des autres sprites for i%=2 to nb_sprites delta_x%(i%) = 4 : delta_y%(i%) = 3 dir_x%(i%) = 1 : dir_y%(i%) = 1 next i%
' Création des images pour les sprites de test picture 100 : height 100,200 : width 100,200 color 100,0,0,255 : file_save 100,"sprite_1.bmp" for i%=2 to nb_sprites color 100,255 - i%*c%,i%*c%,0 : file_save 100,"sprite_"+str$(i%)+".bmp" next i%
' Création d'une image vide pour le fond full_space 100 : color 100,220,220,220 :file_save 100,"vide_2D.bmp": delete 100
' Creation de l'air de déplacement des sprites et supression du fond temporaire scene2d 100 : hide 100 : full_space 100 : file_load 100,"vide_2d.bmp" : file_delete "vide_2D.bmp"
' Création et chargement des sprites et suppression des images temporaires sprite 1 : sprite_file_load 1,"sprite_1.bmp" : file_delete "sprite_1.bmp" pos_x%(1) = 180: pos_y%(1) = 120 sprite_scale 1,1/4,1/4 : larg%(1) = int(200/4) : haut%(1) = int(200/4) sprite_position 1,pos_x%(1),pos_y%(1)
for i%=2 to nb_sprites sprite i% : sprite_file_load i%,"sprite_"+str$(i%)+".bmp" : file_delete "sprite_"+str$(i%)+".bmp" sprite_scale i%,1/5,1/5 : larg%(i%) = int(200/5) : haut%(i%) = int(200/5) pos_x%(i%) = 400-rnd(400): pos_y%(i%) = 300 - rnd(300) test_recouvrement(i%,1) : ' procédure pour empécher que le sprite 1 ne soit recouvert par un autre sprite au démarrage sprite_position i%,pos_x%(i%),pos_y%(i%) next i%
show 100 : ' On montre la scene
' Boucle de déplacement repeat for i%=2 to nb_sprites move(i%,1) next i% until scancode=27
end
' Procédure de déplacement sub move(s1%,s2%) dim_local i%, delta% ' déplacer horizontalement if dir_x%(s1%)>0 : ' à droite if (sprite_x_position(s1%)+larg%(s1%))>=(width(100)) dir_x%(s1%) = 0 - dir_x%(s1%) end_if else : ' à gauche if sprite_x_position(s1%)<=0 dir_x%(s1%) = 0 - dir_x%(s1%) end_if end_if ' déplacer verticalement if dir_y%(s1%)>0 : ' en bas if (sprite_y_position(s1%)+haut%(s1%))>=(height(100)) dir_y%(s1%) = 0 - dir_y%(s1%) end_if else : ' en haut if sprite_y_position(s1%)<=0 dir_y%(s1%) = 0 - dir_y%(s1%) end_if end_if if abs(delta_x%(s1%))> abs(delta_y%(s1%)) delta%=abs(delta_x%(s1%)) else delta%=abs(delta_y%(s1%)) end_if for i%=0 to delta% pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)) pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) collision(s1%,s2%) if choc%=1 affiche_contact(s1%,s2%) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) exit_for else sprite_position s1%,pos_x%(s1%),pos_y%(s1%) end_if next i% if choc%=1 change_dir(s1%) for i%=0 to delta% pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)) pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) next i% end_if end_sub
' Inverse les directions sub change_dir(s1%) dir_x%(s1%) = 0-dir_x%(s1%): dir_y%(s1%) = 0-dir_y%(s1%) end_sub
' Test s'il y a collision sub collision(s1%,s2%) if (((pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) and ((pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)))) choc% = 1 : ' Si le rectangle du sprite 1 recouvre partiellement celui du sprite 2, il y a collision else choc% = 0 : ' Sinon, on retourne qu'ils ne se touchent pas end_if end_sub
' Test s'il y a recouvrement entre 2 sprites sub test_recouvrement(s1%,s2%) while (((pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) and ((pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)))) pos_x%(s1%) = 400-rnd(400): pos_y%(s1%) = 300 - rnd(300) end_while end_sub
' Arrète le mouvement sur la position du contact sub affiche_contact(s1%,s2%) dim_local x,y : x=0 : y=0 if (pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%) if (pos_x%(s1%) < pos_x%(s2%)) if (pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%) if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)) then x = pos_x%(s2%) - larg%(s1%) -1 end_if end_if else if (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)) if pos_x%(s1%) > pos_x%(s2%) if (((pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) then x = pos_x%(s2%) + larg%(s2%) end_if end_if end_if
if (pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%) if pos_y%(s1%) < pos_y%(s2%) if (pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%) if pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)) then y = pos_y%(s2%) - haut%(s1%)-1 end_if end_if else if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)) if pos_y%(s1%) > pos_y%(s2%) if (((pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%))) then y = pos_y%(s2%) + haut%(s2%) end_if end_if end_if if x > 0 then pos_x%(s1%) = x if y > 0 then pos_y%(s1%) = y end_sub | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Gestion de collisions entre sprites en 2D Dim 21 Oct 2012 - 11:15 | |
| Qu'est-ce que tun penses de cette version ? J'ai corrigé quelques indices, et j'ai rétabli les vitesses différentes selon les deux axes- tu avais gommé cet aspect en ramenant tout à ta variable locale delta%. J'ai commencé aussi à faire le rebond "façon billard" sur le sprite bleu. cela ne marche pas encore pour les coins, mais le début y est. Et les sprites mobiles s'arrêtent bien au ras du sprite bleu, maintenant, sans rentrer dedans. - Code:
-
' collisions_en_scene2d.bas
caption 0,"Interrompre par Echap"
dim i%, choc% : ' i% compteur temporaire et choc% variable globale permettant de savoir s'il y a collision ou non dim nb_sprites : nb_sprites = 15 : ' Constante indiquant le nombre de sprites utilisés dim larg%(nb_sprites), haut%(nb_sprites) : ' tableau contenant les dimensions des sprites dim delta_x%(nb_sprites), delta_y%(nb_sprites) : ' vitesses horizontales et verticales des sprites dim dir_x%(nb_sprites), dir_y%(nb_sprites) : ' directions horizontales et verticales des sprites dim pos_x%(nb_sprites), pos_y%(nb_sprites) : ' coordonnées logiques des sprites dim c% : c% = 255/nb_sprites : ' diviseur pour le calcul des couleurs
' Initialisation du sprite 1 delta_x%(1) = 2 : delta_y%(1) = 2 : dir_x%(1) = 1 : dir_y%(1) = 1
' Initialisation des autres sprites for i%=2 to nb_sprites delta_x%(i%) = int(rnd(8)+0.5) + 1 delta_y%(i%) = int(rnd(8)+0.5) + 1 dir_x%(i%) = 1 : dir_y%(i%) = 1 next i%
' Création des images pour les sprites de test picture 100 : height 100,200 : width 100,200 color 100,0,0,255 : file_save 100,"sprite_1.bmp" for i%=2 to nb_sprites color 100,255 - i%*c%,i%*c%,0 : file_save 100,"sprite_"+str$(i%)+".bmp" next i%
' Création d'une image vide pour le fond full_space 100 : color 100,220,220,220 :file_save 100,"vide_2D.bmp": delete 100
' Creation de l'air de déplacement des sprites et supression du fond temporaire scene2d 100 : hide 100 : full_space 100 : file_load 100,"vide_2d.bmp" : file_delete "vide_2D.bmp"
' Création et chargement des sprites et suppression des images temporaires sprite 1 : sprite_file_load 1,"sprite_1.bmp" : file_delete "sprite_1.bmp" pos_x%(1) = 180: pos_y%(1) = 120 sprite_scale 1,1/4,1/4 : larg%(1) = int(200/4) : haut%(1) = int(200/4) sprite_position 1,pos_x%(1),pos_y%(1)
for i%=2 to nb_sprites sprite i% : sprite_file_load i%,"sprite_"+str$(i%)+".bmp" : file_delete "sprite_"+str$(i%)+".bmp" sprite_scale i%,1/5,1/5 : larg%(i%) = int(200/5) : haut%(i%) = int(200/5) pos_x%(i%) = 400-rnd(400): pos_y%(i%) = 300 - rnd(300) test_recouvrement(i%,1) : ' procédure pour empécher que le sprite 1 ne soit recouvert par un autre sprite au démarrage sprite_position i%,pos_x%(i%),pos_y%(i%) next i%
show 100 : ' On montre la scene
' Boucle de déplacement repeat for i%=2 to nb_sprites move(i%,1) next i% until scancode=27
end
' Procédure de déplacement sub move(s1%,s2%) dim_local i%, delta% dim_local dx%, dy% ' déplacer horizontalement if dir_x%(s1%)>0 : ' à droite if (sprite_x_position(s1%)+larg%(s1%))>=(width(100)) dir_x%(s1%) = 0 - dir_x%(s1%) end_if else : ' à gauche if sprite_x_position(s1%)<=0 dir_x%(s1%) = 0 - dir_x%(s1%) end_if end_if ' déplacer verticalement if dir_y%(s1%)>0 : ' en bas if (sprite_y_position(s1%)+haut%(s1%))>=(height(100)) dir_y%(s1%) = 0 - dir_y%(s1%) end_if else : ' en haut if sprite_y_position(s1%)<=0 dir_y%(s1%) = 0 - dir_y%(s1%) end_if end_if dx% = abs(delta_x%(s1%)) dy% = abs(delta_y%(s1%)) delta% = max(dx%,dy%) for i%=0 to delta% if i%<=dx% then pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/dx%)) if i%<=dy% then pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/dy%)) collision(s1%,s2%) if choc%>0 affiche_contact(s1%,s2%) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) exit_for else sprite_position s1%,pos_x%(s1%),pos_y%(s1%) end_if next i% if choc%>0 change_dir(s1%) i% = 1 repeat pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)) pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) collision(s1%,s2%) until choc%=0 end_if end_sub
' Inverse les directions sub change_dir(s1%) select choc% case 1 dir_x%(s1%) = 0-dir_x%(s1%) dir_y%(s1%) = 0-dir_y%(s1%) case 2 dir_x%(s1%) = 0-dir_x%(s1%) case 3 dir_y%(s1%) = 0-dir_y%(s1%) end_select end_sub
' Test s'il y a collision sub collision(s1%,s2%) choc% = 0 if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)-1) if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) choc% = 1 : ' Si le rectangle du sprite 1 recouvre partiellement celui du sprite 2, il y a collision if pos_x%(s1%)>=pos_x%(s2%) if (pos_x%(s1%)+larg%(s1%)-1)<(pos_x%(s2%)+larg%(s2%)-1) then choc% = 2 end_if if pos_y%(s1%)>=pos_y%(s2%) if (pos_y%(s1%)+haut%(s1%)-1)<(pos_y%(s2%)+haut%(s2%)-1) then choc% = 3 end_if end_if end_if end_if end_if end_sub
' Test s'il y a recouvrement entre 2 sprites sub test_recouvrement(s1%,s2%) while (((pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) and ((pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)))) pos_x%(s1%) = 400-rnd(400): pos_y%(s1%) = 300 - rnd(300) end_while end_sub
' Arrète le mouvement sur la position du contact sub affiche_contact(s1%,s2%) dim_local x,y : x=0 : y=0 if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if (pos_x%(s1%) < pos_x%(s2%)) if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)) then x = pos_x%(s2%) - larg%(s1%) + 1 : ' -1 end_if end_if else if (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) if pos_x%(s1%) > pos_x%(s2%) if (((pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) then x = pos_x%(s2%) + larg%(s2%) - 1 : ' + 0 end_if end_if end_if
if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) < pos_y%(s2%) if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) then y = pos_y%(s2%) - haut%(s1%) + 1 : ' -1 end_if end_if else if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)-1) if pos_y%(s1%) > pos_y%(s2%) if (((pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%))) then y = pos_y%(s2%) + haut%(s2%) - 1 : + 0 end_if end_if end_if if x > 0 then pos_x%(s1%) = x if y > 0 then pos_y%(s1%) = y end_sub | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Gestion de collisions entre sprites en 2D Dim 21 Oct 2012 - 11:27 | |
| En effet Bon pour nos amis débutants qui se font toujours aussi discret, j'ai rajouté la gestion des touches pour bouger le sprite bleu. J'espère qu'ils suivent ce post pour ne pas être perdus. Je ne veux pas compliquer le programme plus que nécessaire, mais s'ils suivent la discussion, ils comprendront les problématique et l'utilité des ajouts. Les nouveaux, si vous ne comprenez pas quelque chose posez vos questions pendant que l'on est dedans... Klaus, je l'ais fais sans événement pour ne pas mélanger les sujets. Qu'est-ce que tu en pense ? - Code:
-
' collisions_en_scene2d.bas
caption 0,"Interrompre par Echap"
dim i%, choc% : ' i% compteur temporaire et choc% variable globale permettant de savoir s'il y a collision ou non dim nb_sprites : nb_sprites = 15 : ' Constante indiquant le nombre de sprites utilisés dim larg%(nb_sprites), haut%(nb_sprites) : ' tableau contenant les dimensions des sprites dim delta_x%(nb_sprites), delta_y%(nb_sprites) : ' vitesses horizontales et verticales des sprites dim dir_x%(nb_sprites), dir_y%(nb_sprites) : ' directions horizontales et verticales des sprites dim pos_x%(nb_sprites), pos_y%(nb_sprites) : ' coordonnées logiques des sprites dim c% : c% = 255/nb_sprites : ' diviseur pour le calcul des couleurs dim touche : ' on définit une variable qui contiendra la touche appuyée dim depl : ' definit une variable définissant si on doit déplacer le sprite
' Initialisation du sprite 1 delta_x%(1) = 2 : delta_y%(1) = 2 : dir_x%(1) = 0 : dir_y%(1) = 0
' Initialisation des autres sprites for i%=2 to nb_sprites delta_x%(i%) = int(rnd(8)+0.5) + 1 delta_y%(i%) = int(rnd(8)+0.5) + 1 dir_x%(i%) = 1 : dir_y%(i%) = 1 next i%
' Création des images pour les sprites de test picture 100 : height 100,200 : width 100,200 color 100,0,0,255 : file_save 100,"sprite_1.bmp" for i%=2 to nb_sprites color 100,255 - i%*c%,i%*c%,0 : file_save 100,"sprite_"+str$(i%)+".bmp" next i%
' Création d'une image vide pour le fond full_space 100 : color 100,220,220,220 :file_save 100,"vide_2D.bmp": delete 100
' Creation de l'air de déplacement des sprites et supression du fond temporaire scene2d 100 : hide 100 : full_space 100 : file_load 100,"vide_2d.bmp" : file_delete "vide_2D.bmp"
' Création et chargement des sprites et suppression des images temporaires sprite 1 : sprite_file_load 1,"sprite_1.bmp" : file_delete "sprite_1.bmp" pos_x%(1) = 180: pos_y%(1) = 120 sprite_scale 1,1/4,1/4 : larg%(1) = int(200/4) : haut%(1) = int(200/4) sprite_position 1,pos_x%(1),pos_y%(1)
for i%=2 to nb_sprites sprite i% : sprite_file_load i%,"sprite_"+str$(i%)+".bmp" : file_delete "sprite_"+str$(i%)+".bmp" sprite_scale i%,1/5,1/5 : larg%(i%) = int(200/5) : haut%(i%) = int(200/5) pos_x%(i%) = 400-rnd(400): pos_y%(i%) = 300 - rnd(300) test_recouvrement(i%,1) : ' procédure pour empécher que le sprite 1 ne soit recouvert par un autre sprite au démarrage sprite_position i%,pos_x%(i%),pos_y%(i%) next i%
show 100 : ' On montre la scene
' Boucle de déplacement repeat for i%=2 to nb_sprites move(i%,1) next i% touche = scancode : rem lecture du clavier, code mis dans touche depl=0 if touche = 37 then dir_x%(1) = -1 : dir_y%(1) = 0 : depl=1 : rem 37=code de FLECHE GAUCHE if touche = 38 then dir_y%(1) = -1 : dir_x%(1) = 0 : depl=1 : rem 38=code de FLECHE HAUT if touche = 39 then dir_x%(1) = 1 : dir_y%(1) = 0 : depl=1 : rem 39=code de FLECHE DROITE if touche = 40 then dir_y%(1) = 1 : dir_x%(1) = 0 : depl=1 : rem 40=code de FLECHE BAS if depl=1 for i%=2 to nb_sprites move(1,i%) depl=0 next i% end_if until scancode=27
end
' Procédure de déplacement sub move(s1%,s2%) dim_local i%, delta% dim_local dx%, dy% ' déplacer horizontalement if dir_x%(s1%)>0 : ' à droite if (sprite_x_position(s1%)+larg%(s1%))>=(width(100)) dir_x%(s1%) = 0 - dir_x%(s1%) end_if else : ' à gauche if sprite_x_position(s1%)<=0 dir_x%(s1%) = 0 - dir_x%(s1%) end_if end_if ' déplacer verticalement if dir_y%(s1%)>0 : ' en bas if (sprite_y_position(s1%)+haut%(s1%))>=(height(100)) dir_y%(s1%) = 0 - dir_y%(s1%) end_if else : ' en haut if sprite_y_position(s1%)<=0 dir_y%(s1%) = 0 - dir_y%(s1%) end_if end_if
dx% = abs(delta_x%(s1%)) dy% = abs(delta_y%(s1%)) delta% = max(dx%,dy%)
for i%=0 to delta% if i%<=dx% then pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/dx%)) if i%<=dy% then pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/dy%)) collision(s1%,s2%) if choc%>0 affiche_contact(s1%,s2%) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) exit_for else sprite_position s1%,pos_x%(s1%),pos_y%(s1%) end_if next i% if choc%>0 change_dir(s1%) i% = 1 repeat pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)) pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) collision(s1%,s2%) until choc%=0 end_if end_sub
' Inverse les directions sub change_dir(s1%) select choc% case 1 dir_x%(s1%) = 0-dir_x%(s1%) dir_y%(s1%) = 0-dir_y%(s1%) case 2 dir_x%(s1%) = 0-dir_x%(s1%) case 3 dir_y%(s1%) = 0-dir_y%(s1%) end_select end_sub
' Test s'il y a collision sub collision(s1%,s2%) choc% = 0 if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)-1) if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) choc% = 1 : ' Si le rectangle du sprite 1 recouvre partiellement celui du sprite 2, il y a collision if pos_x%(s1%)>=pos_x%(s2%) if (pos_x%(s1%)+larg%(s1%)-1)<(pos_x%(s2%)+larg%(s2%)-1) then choc% = 2 end_if if pos_y%(s1%)>=pos_y%(s2%) if (pos_y%(s1%)+haut%(s1%)-1)<(pos_y%(s2%)+haut%(s2%)-1) then choc% = 3 end_if end_if end_if end_if end_if end_sub
' Test s'il y a recouvrement entre 2 sprites sub test_recouvrement(s1%,s2%) while (((pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) and ((pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)))) pos_x%(s1%) = 400-rnd(400): pos_y%(s1%) = 300 - rnd(300) end_while end_sub
' Arrète le mouvement sur la position du contact sub affiche_contact(s1%,s2%) dim_local x,y : x=0 : y=0 if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if (pos_x%(s1%) < pos_x%(s2%)) if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)) then x = pos_x%(s2%) - larg%(s1%) + 1 : ' -1 end_if end_if else if (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) if pos_x%(s1%) > pos_x%(s2%) if (((pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) then x = pos_x%(s2%) + larg%(s2%) - 1 : ' + 0 end_if end_if end_if
if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) < pos_y%(s2%) if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) then y = pos_y%(s2%) - haut%(s1%) + 1 : ' -1 end_if end_if else if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)-1) if pos_y%(s1%) > pos_y%(s2%) if (((pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%))) then y = pos_y%(s2%) + haut%(s2%) - 1 : + 0 end_if end_if end_if if x > 0 then pos_x%(s1%) = x if y > 0 then pos_y%(s1%) = y end_sub | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Gestion de collisions entre sprites en 2D Dim 21 Oct 2012 - 11:37 | |
| Bonne idée. Mais curieusement, la vitesse du déplacement du sprite bleu est égale au nombre de sprites existants, à cause de ta boucle. Pourquoi tu ne fais pas comme ceci: - Code:
-
if depl=1 ' for i%=2 to nb_sprites ' move(1,i%) ' depl=0 ' next i% move(1,0) end_if quitte à modifier delta_x%(1) et delta_y%(1) pour choisir la vitesse que tu souhaites ? | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Gestion de collisions entre sprites en 2D Dim 21 Oct 2012 - 12:25 | |
| Absolument Klaus, tu as raison J'ai voulu faire simple et je n'ai pas pensé au 0. Bonne idée, je mets le code en dessous avec cette modif - Code:
-
' collisions_en_scene2d.bas ' Pour apprendre à gérer les collisions avec les sprites ' Le sprite 1 est déplacé avec le pavé directionnel ' Les autres sprites se déplacent et rebondissent
caption 0,"Interrompre par Echap"
dim i%, choc% : ' i% compteur temporaire et choc% variable globale permettant de savoir s'il y a collision ou non dim nb_sprites : nb_sprites = 15 : ' Constante indiquant le nombre de sprites utilisés dim larg%(nb_sprites), haut%(nb_sprites) : ' tableau contenant les dimensions des sprites dim delta_x%(nb_sprites), delta_y%(nb_sprites) : ' vitesses horizontales et verticales des sprites dim dir_x%(nb_sprites), dir_y%(nb_sprites) : ' directions horizontales et verticales des sprites dim pos_x%(nb_sprites), pos_y%(nb_sprites) : ' coordonnées logiques des sprites dim c% : c% = 255/nb_sprites : ' diviseur pour le calcul des couleurs dim touche : ' on définit une variable qui contiendra la touche appuyée dim depl : ' definit une variable définissant si on doit déplacer le sprite
' Initialisation du sprite 1 delta_x%(1) = 5 : delta_y%(1) = 5 : dir_x%(1) = 0 : dir_y%(1) = 0
' Initialisation des autres sprites for i%=2 to nb_sprites delta_x%(i%) = int(rnd(8)+0.5) + 1 delta_y%(i%) = int(rnd(8)+0.5) + 1 dir_x%(i%) = 1 : dir_y%(i%) = 1 next i%
' Création des images pour les sprites de test picture 100 : height 100,200 : width 100,200 color 100,0,0,255 : file_save 100,"sprite_1.bmp" for i%=2 to nb_sprites color 100,255 - i%*c%,i%*c%,0 : file_save 100,"sprite_"+str$(i%)+".bmp" next i%
' Création d'une image vide pour le fond full_space 100 : color 100,220,220,220 :file_save 100,"vide_2D.bmp": delete 100
' Creation de l'air de déplacement des sprites et supression du fond temporaire scene2d 100 : hide 100 : full_space 100 : file_load 100,"vide_2d.bmp" : file_delete "vide_2D.bmp"
' Création et chargement des sprites et suppression des images temporaires sprite 1 : sprite_file_load 1,"sprite_1.bmp" : file_delete "sprite_1.bmp" pos_x%(1) = 180: pos_y%(1) = 120 sprite_scale 1,1/4,1/4 : larg%(1) = int(200/4) : haut%(1) = int(200/4) sprite_position 1,pos_x%(1),pos_y%(1)
for i%=2 to nb_sprites sprite i% : sprite_file_load i%,"sprite_"+str$(i%)+".bmp" : file_delete "sprite_"+str$(i%)+".bmp" sprite_scale i%,1/5,1/5 : larg%(i%) = int(200/5) : haut%(i%) = int(200/5) pos_x%(i%) = 400-rnd(400): pos_y%(i%) = 300 - rnd(300) test_recouvrement(i%,1) : ' procédure pour empécher que le sprite 1 ne soit recouvert par un autre sprite au démarrage sprite_position i%,pos_x%(i%),pos_y%(i%) next i%
show 100 : ' On montre la scene
' Boucle de déplacement repeat for i%=2 to nb_sprites move(i%,1) next i% touche = scancode : rem lecture du clavier, code mis dans touche depl=0 if touche = 37 then dir_x%(1) = -1 : dir_y%(1) = 0 : depl=1 : rem 37=code de FLECHE GAUCHE if touche = 38 then dir_y%(1) = -1 : dir_x%(1) = 0 : depl=1 : rem 38=code de FLECHE HAUT if touche = 39 then dir_x%(1) = 1 : dir_y%(1) = 0 : depl=1 : rem 39=code de FLECHE DROITE if touche = 40 then dir_y%(1) = 1 : dir_x%(1) = 0 : depl=1 : rem 40=code de FLECHE BAS if depl=1 then move(1,0): depl=0 until scancode=27
end
' Procédure de déplacement sub move(s1%,s2%) dim_local i%, delta% dim_local dx%, dy% ' déplacer horizontalement if dir_x%(s1%)>0 : ' à droite if (sprite_x_position(s1%)+larg%(s1%))>=(width(100)) dir_x%(s1%) = 0 - dir_x%(s1%) end_if else : ' à gauche if sprite_x_position(s1%)<=0 dir_x%(s1%) = 0 - dir_x%(s1%) end_if end_if ' déplacer verticalement if dir_y%(s1%)>0 : ' en bas if (sprite_y_position(s1%)+haut%(s1%))>=(height(100)) dir_y%(s1%) = 0 - dir_y%(s1%) end_if else : ' en haut if sprite_y_position(s1%)<=0 dir_y%(s1%) = 0 - dir_y%(s1%) end_if end_if
dx% = abs(delta_x%(s1%)) dy% = abs(delta_y%(s1%)) delta% = max(dx%,dy%)
for i%=0 to delta% if i%<=dx% then pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/dx%)) if i%<=dy% then pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/dy%)) collision(s1%,s2%) if choc%>0 affiche_contact(s1%,s2%) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) exit_for else sprite_position s1%,pos_x%(s1%),pos_y%(s1%) end_if next i% if choc%>0 change_dir(s1%) i% = 1 repeat pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)) pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) collision(s1%,s2%) until choc%=0 end_if end_sub
' Inverse les directions sub change_dir(s1%) select choc% case 1 dir_x%(s1%) = 0-dir_x%(s1%) dir_y%(s1%) = 0-dir_y%(s1%) case 2 dir_x%(s1%) = 0-dir_x%(s1%) case 3 dir_y%(s1%) = 0-dir_y%(s1%) end_select end_sub
' Test s'il y a collision sub collision(s1%,s2%) choc% = 0 if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)-1) if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) choc% = 1 : ' Si le rectangle du sprite 1 recouvre partiellement celui du sprite 2, il y a collision if pos_x%(s1%)>=pos_x%(s2%) if (pos_x%(s1%)+larg%(s1%)-1)<(pos_x%(s2%)+larg%(s2%)-1) then choc% = 2 end_if if pos_y%(s1%)>=pos_y%(s2%) if (pos_y%(s1%)+haut%(s1%)-1)<(pos_y%(s2%)+haut%(s2%)-1) then choc% = 3 end_if end_if end_if end_if end_if end_sub
' Test s'il y a recouvrement entre 2 sprites sub test_recouvrement(s1%,s2%) while (((pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) and ((pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)))) pos_x%(s1%) = 400-rnd(400): pos_y%(s1%) = 300 - rnd(300) end_while end_sub
' Arrète le mouvement sur la position du contact sub affiche_contact(s1%,s2%) dim_local x,y : x=0 : y=0 if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if (pos_x%(s1%) < pos_x%(s2%)) if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)) then x = pos_x%(s2%) - larg%(s1%) + 1 : ' -1 end_if end_if else if (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) if pos_x%(s1%) > pos_x%(s2%) if (((pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) then x = pos_x%(s2%) + larg%(s2%) - 1 : ' + 0 end_if end_if end_if
if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) < pos_y%(s2%) if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) then y = pos_y%(s2%) - haut%(s1%) + 1 : ' -1 end_if end_if else if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)-1) if pos_y%(s1%) > pos_y%(s2%) if (((pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%))) then y = pos_y%(s2%) + haut%(s2%) - 1 : + 0 end_if end_if end_if if x > 0 then pos_x%(s1%) = x if y > 0 then pos_y%(s1%) = y end_sub | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Gestion de collisions entre sprites en 2D Dim 21 Oct 2012 - 13:40 | |
| C'est pas mal, comme ça. Ca donne une bonne idée comment gérer les collisions en 2d.
Mais il est vrai qu'une fonction 2d_collision() serait la bienvenue !
| |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Gestion de collisions entre sprites en 2D Dim 21 Oct 2012 - 14:21 | |
| C'est sûr C'est sans doute une des fonctions manquantes auxquelles Jack pensait quand il disait qu'il voulait pouvoir faire des jeux facilement avec Panoramic, mais bon on aura la surprise bientôt. Je fais preuve de patiente pour une fois | |
| | | Nardo26
Nombre de messages : 2294 Age : 56 Localisation : Valence Date d'inscription : 02/07/2010
| Sujet: Re: Gestion de collisions entre sprites en 2D Dim 21 Oct 2012 - 18:47 | |
| - Jicehel a écrit:
- En effet
Bon pour nos amis débutants qui se font toujours aussi discret,... C'est très bien jicehel ce que tu as fait mais : je viens de parcourir ton code, a moins d'être l'auteur où de bien comprendre le principe (auquel cas, la question ne se pose même pas sur le forum) je doute que Lucifor31 comprenne la moindre ligne de code à ton programme.... Perso, ton source ne me pose pas de problème mais pour un débutant, sans aucun commentaire, cela risque d'être un peu hard ! | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Gestion de collisions entre sprites en 2D Dim 21 Oct 2012 - 19:35 | |
| Et je vais rajouter une couche ! Je n'étais pas satisfait des conditions de rebond des sprites mobiles sur le sprite bleu. J'aurais aimé que le rebond se fasse comme sur les bords, façon "billard". J'ai donc essayé de réécrire la routine de test de collision, mais je me suis vite heurté à des monceaux de code en Panoramic, rien que pour pouvoir déterminer le type et l'endroit du recouvrement. Alors, et je m'en excuse, j'ai fait une fonction DLL qui détermine le type de recouvrement d'un rectangle par un autre. Du coup, KGF.dll passe à la version 1.79 21/10/2012 ajout fonction IsRectangleInRectangle Cette fonction retourne une valeur indiquant le type de recouvrement. Voici un extrait de la doc: - Citation :
- valeur indiquant l'état de recouvrement.
Elle est consituée du OR logique des valeurs suivantes: 0 = R1 ne touche pas R2 1 = le coin en haut à gauche de R1 est dans R2 2 = le coin en haut à droite de R1 est dans R2 4 = le coin en bas à gauche de R1 est dans R2 8 = le coin en bas à droite de R1 est dans R2 16 = R1 recouvre totalement R2 Cette nouvelle fonction est dans la section "Fonctions de la souris" de la doc. Bien sûr, la doc est à jour, et KGF_SUB suivra prochainement. J'ai utilisé cette fonction dans ce programme de sprites movants. Et j'ai ajouté un autre effet sympa: le programme démarre avec 2 sprites mobiles. il est prévu pour un maximum de 20 sprites au total. La barre d'espacement injecte un nouveau sprite n cours de fonctionnement, et la touche TAB supprime un sprite. On peut supprimer tous les sprites, y compris le sprite bleu. Et on les recrée aussitôt par la barre d'espacement. Voici le code: - Code:
-
' collisions_en_scene2d.bas ' Pour apprendre à gérer les collisions avec les sprites ' Le sprite 1 est déplacé avec le pavé directionnel ' Les autres sprites se déplacent et rebondissent
label sortie
caption 0,"Interrompre par Echap" on_close 0,sortie dll_on "KGF.dll"
dim i%, choc% : ' i% compteur temporaire et choc% variable globale permettant de savoir s'il y a collision ou non ' dim nb_sprites% : nb_sprites% = 15 : ' Constante indiquant le nombre de sprites utilisés dim nb_sprites% : nb_sprites% = 3 : ' Constante indiquant le nombre de sprites utilisés dim max_sprites% : max_sprites% = 20 dim larg%(max_sprites%), haut%(max_sprites%) : ' tableau contenant les dimensions des sprites dim delta_x%(max_sprites%), delta_y%(max_sprites%) : ' vitesses horizontales et verticales des sprites dim dir_x%(max_sprites%), dir_y%(max_sprites%) : ' directions horizontales et verticales des sprites dim pos_x%(max_sprites%), pos_y%(max_sprites%) : ' coordonnées logiques des sprites dim c% : c% = int(255/max_sprites%) : ' diviseur pour le calcul des couleurs dim touche : ' on définit une variable qui contiendra la touche appuyée dim depl : ' definit une variable définissant si on doit déplacer le sprite dim flag% : ' flag "un sprite a été supprimé"
' Initialisation du sprite 1 delta_x%(1) = 5 : delta_y%(1) = 5 : dir_x%(1) = 0 : dir_y%(1) = 0
' Initialisation des autres sprites for i%=2 to max_sprites% delta_x%(i%) = int(rnd(8)+0.5) + 1 delta_y%(i%) = int(rnd(8)+0.5) + 1 dir_x%(i%) = 1 : dir_y%(i%) = 1 next i%
' Création d'une image vide pour le fond picture 100 full_space 100 : color 100,220,220,220 :file_save 100,"vide_2D.bmp": delete 100
' Creation de l'air de déplacement des sprites et supression du fond temporaire scene2d 100 : hide 100 : full_space 100 : file_load 100,"vide_2d.bmp" : file_delete "vide_2D.bmp"
' Création et chargement des sprites et suppression des images temporaires create_sprite(1)
for i%=2 to nb_sprites% create_sprite(i%) next i%
show 100 : ' On montre la scene
' Boucle de déplacement repeat if flag%=1 pause 100 flag% = 0 end_if if nb_sprites%>1 for i%=2 to nb_sprites% move(i%,1) next i% end_if touche = scancode : rem lecture du clavier, code mis dans touche depl=0 select touche case 37: dir_x%(1) = -1 : dir_y%(1) = 0 : depl=1 : rem 37=code de FLECHE GAUCHE case 38: dir_y%(1) = -1 : dir_x%(1) = 0 : depl=1 : rem 38=code de FLECHE HAUT case 39: dir_x%(1) = 1 : dir_y%(1) = 0 : depl=1 : rem 39=code de FLECHE DROITE case 40: dir_y%(1) = 1 : dir_x%(1) = 0 : depl=1 : rem 40=code de FLECHE BAS case 32 if nb_sprites%<max_sprites% nb_sprites% = nb_sprites% + 1 create_sprite(nb_sprites%) end_if case 9 if nb_sprites%>0 sprite_delete nb_sprites% nb_sprites% = nb_sprites% - 1 flag% = 1 end_if end_select if depl=1 then move(1,0): depl=0 until scancode=27
end
sortie: dll_off return
' Procédure de déplacement sub move(s1%,s2%) if scancode=27 then end : ' terminate dim_local i%, delta% dim_local dx%, dy% ' déplacer horizontalement if dir_x%(s1%)>0 : ' à droite if (sprite_x_position(s1%)+larg%(s1%))>=(width(100)) dir_x%(s1%) = 0 - dir_x%(s1%) end_if else : ' à gauche if sprite_x_position(s1%)<=0 dir_x%(s1%) = 0 - dir_x%(s1%) end_if end_if ' déplacer verticalement if dir_y%(s1%)>0 : ' en bas if (sprite_y_position(s1%)+haut%(s1%))>=(height(100)) dir_y%(s1%) = 0 - dir_y%(s1%) end_if else : ' en haut if sprite_y_position(s1%)<=0 dir_y%(s1%) = 0 - dir_y%(s1%) end_if end_if
dx% = abs(delta_x%(s1%)) dy% = abs(delta_y%(s1%)) delta% = max(dx%,dy%)
for i%=0 to delta% ' if i%<=dx% then pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/dx%)) ' if i%<=dy% then pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/dy%)) if i%<=dx% then pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*delta_x%(s1%)/dx% if i%<=dy% then pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*delta_y%(s1%)/dy% collision(s1%,s2%) if choc%>0 affiche_contact(s1%,s2%) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) exit_for else sprite_position s1%,pos_x%(s1%),pos_y%(s1%) end_if next i% if choc%>0 change_dir(s1%,s2%) i% = 1 repeat pos_x%(s1%) = pos_x%(s1%)+ dir_x%(s1%)*(i%*(delta_x%(s1%)/delta%)) pos_y%(s1%) = pos_y%(s1%)+ dir_y%(s1%)*(i%*(delta_y%(s1%)/delta%)) sprite_position s1%,pos_x%(s1%),pos_y%(s1%) collision(s1%,s2%) until choc%=0 end_if end_sub
' Inverse les directions sub change_dir(s1%,s2%) select choc% case 1 : ' top left if pos_y%(s1%)<(pos_y%(s2%)+haut%(s2%)-1) dir_x%(s1%) = 0-dir_x%(s1%) else dir_y%(s1%) = 0-dir_y%(s1%) end_if case 2 : ' top right if pos_y%(s1%)<(pos_y%(s2%)+haut%(s2%)-1) dir_x%(s1%) = 0-dir_x%(s1%) else dir_y%(s1%) = 0-dir_y%(s1%) end_if case 3 : ' top left + top right dir_y%(s1%) = 0-dir_y%(s1%) case 4 : ' bottom left if (pos_y%(s1%)+haut%(s1%)-1)<pos_y%(s2%) dir_x%(s1%) = 0-dir_x%(s1%) else dir_y%(s1%) = 0-dir_y%(s1%) end_if case 5 : ' top left + bottom left dir_x%(s1%) = 0-dir_x%(s1%) case 6: ' top right + bottom left ==> impossible case 7: ' top left + top right + bottom left ==> impossible case 8: ' bottom right if (pos_y%(s1%)+haut%(s1%)-1)<pos_y%(s2%) dir_x%(s1%) = 0-dir_x%(s1%) else dir_y%(s1%) = 0-dir_y%(s1%) end_if case 9: ' top left + bottom right ==> impossible case 10: ' top right + bottom right ==> impossible dir_x%(s1%) = 0-dir_x%(s1%) case 11: ' top left + top right + bottom right ==> impossible case 12: ' bottom left + bottom right dir_y%(s1%) = 0-dir_y%(s1%) case 13: ' top left + bottom left + bottom right ==> impossible case 14: ' top right + bottom left + bottom right ==> impossible case 15: ' entièrement à l'intérieur dir_x%(s1%) = 0-dir_x%(s1%) dir_y%(s1%) = 0-dir_y%(s1%) if dir_x%(s1%)>0 pos_x%(s1%) = pos_x%(s2%)+larg%(s2%) + 1 else pos_x%(s1%) = pos_x(s2%) - larg%(s1%) - 1 end_if if dir_y%(s1%)>0 pos_y%(s1%) = pos_y%(s2%)+haut%(s2%) + 1 else pos_y%(s1%) = pos_y(s2%) - haut%(s1%) - 1 end_if case 16: ' recouvrement complet ==> impossible ici end_select end_sub
' Test s'il y a collision sub collision(s1%,s2%) dim_local top1%, dim1%, top2%, dim2% top1% = pos_y%(s1%) + pos_x%(s1%)*65536 dim1% = haut%(s1%) + larg%(s1%)*65536 top2% = pos_y%(s2%) + pos_x%(s2%)*65536 dim2% = haut%(s2%) + larg%(s2%)*65536 choc% = dll_call4("IsRectangleInRectangle",top1%,dim1%,top2%,dim2%) exit_sub end_sub
' Test s'il y a recouvrement entre 2 sprites sub test_recouvrement(s1%,s2%) while (((pos_y%(s1%)+haut%(s1%)) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) and ((pos_x%(s1%)+larg%(s1%)) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)))) pos_x%(s1%) = 400-rnd(400): pos_y%(s1%) = 300 - rnd(300) end_while end_sub
' Arrète le mouvement sur la position du contact sub affiche_contact(s1%,s2%) dim_local x,y : x=0 : y=0 if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if (pos_x%(s1%) < pos_x%(s2%)) if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)) then x = pos_x%(s2%) - larg%(s1%) + 1 : ' -1 end_if end_if else if (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) if pos_x%(s1%) > pos_x%(s2%) if (((pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%)) and (pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%))) then x = pos_x%(s2%) + larg%(s2%) - 1 : ' + 0 end_if end_if end_if
if (pos_y%(s1%)+haut%(s1%)-1) >= pos_y%(s2%) if pos_y%(s1%) < pos_y%(s2%) if (pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%) if pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%)-1) then y = pos_y%(s2%) - haut%(s1%) + 1 : ' -1 end_if end_if else if pos_y%(s1%) <= (pos_y%(s2%)+haut%(s2%)-1) if pos_y%(s1%) > pos_y%(s2%) if (((pos_x%(s1%)+larg%(s1%)-1) >= pos_x%(s2%)) and (pos_x%(s1%) <= (pos_x%(s2%)+larg%(s2%))) then y = pos_y%(s2%) + haut%(s2%) - 1 : + 0 end_if end_if end_if if x > 0 then pos_x%(s1%) = x if y > 0 then pos_y%(s1%) = y end_sub
' Création des sprites sub create_sprite(k%) picture 101 : height 101,200 : width 101,200 if k%=1 color 101,0,0,255 file_save 101,"sprite_x.bmp" else color 101,255 - k%*c%,k%*c%,0 file_save 101,"sprite_x.bmp" end_if delete 101 sprite k% : sprite_file_load k%,"sprite_x.bmp" : file_delete "sprite_x.bmp" if k%=1 pos_x%(1) = 180: pos_y%(1) = 120 sprite_scale 1,1/4,1/4 : larg%(1) = int(200/4) : haut%(1) = int(200/4) sprite_position 1,pos_x%(1),pos_y%(1) else sprite_scale k%,1/5,1/5 : larg%(k%) = int(200/5) : haut%(k%) = int(200/5) pos_x%(k%) = 400-rnd(400): pos_y%(k%) = 300 - rnd(300) test_recouvrement(k%,1) : ' procédure pour empécher que le sprite 1 ne soit recouvert par un autre sprite au démarrage sprite_position k%,pos_x%(k%),pos_y%(k%) end_if end_sub
| |
| | | Nardo26
Nombre de messages : 2294 Age : 56 Localisation : Valence Date d'inscription : 02/07/2010
| Sujet: Re: Gestion de collisions entre sprites en 2D Dim 21 Oct 2012 - 20:31 | |
| @Lucifor31 : comme tu peux le constater, la gestion de collision même en 2D n'est pas si évidente que ça... perso je préfère laisser la place à des matheux, car je bien peur que pour vraiment traiter correctement une collision, il faut passer par des calculs vectoriels et franchement cela fait vraiment trop longtemps que je n'y ai pas mis mon nez dedans... (Je sais pas quel système Klaus à mis en place dans sa DLL...) Peut être que jean debord aura quelque chose à proposer?... Ou attendre dans ce cas l'avis de Jack qui a certainement du réfléchir à la chose... Un gars (galmiza) a réalisé la chose en C++ ( voir ici), et je me permet de mettre ce schema pour te donner une idée du principe (pour par exemple une collision avec un rectangle): | |
| | | Contenu sponsorisé
| Sujet: Re: Gestion de collisions entre sprites en 2D | |
| |
| | | | Gestion de collisions entre sprites en 2D | |
|
Sujets similaires | |
|
| Permission de ce forum: | Vous ne pouvez pas répondre aux sujets dans ce forum
| |
| |
| |