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: Re: Gestion de collisions entre sprites en 2D Dim 21 Oct 2012 - 21:10 | |
| @Nardo26: Pour ma fonction, je me suis limité au constat statique de recouvrement partiel ou total d'un rectangle par un autre. ces rectangles peuvent avoir des dimensions différentes, bien sûr. J'avais déjà depuis longtemps une fonction IsPointInRectangle qui fait ce que son nom indique. Elle utilise un API standard pour réaliser le test. Voici le source: - Code:
-
// check if a point is in a rectangle Function IsPointInRectangle(xp,yp,xr,yr,wr,hr:integer):integer; stdcall; export; var pt: TPoint; rect: TRect; begin pt.X := xp; pt.Y := yp; rect.Left := xr; rect.Top := yr; rect.Right := xr + wr - 1; rect.Bottom := yr + hr - 1; if PtInRect(rect, pt) then result := 1 else result := 0; end;
J'au utilisé cette fonction pour tester les 4 coins du rectangle 1 par rapport au rectangle 2. La seule difficulté était la limitation de Panoramic à 6 paramètres pour l'appel d'une fonction DLL, alors que pour paramétrer deux rectangles, il eût fallu 8 paramètres. J'ai donc eu recours à un subterfuge pour coder les données deux par deux dans des entiers. Et voici le résultat: - Code:
-
// check if rectangle 1 is in rectangle 2 // informations top : y + 65536*x // informations dim : h + 65526*w // retour: OR logique des valeurs suivantes: // 0 = pas de points communs // 1 = top left dans rectangle // 2 = top right dans rectangle // 4 = bottom left dans rectangle // 8 = bottom right dans rectangle // 16 = R1 recouvre complètement R2 function IsRectangleInRectangle(R1Top,R1Dim,R2Top,R2Dim: integer):integer; stdcall; export; var R1,R2, R1D,R2D: TPoint; begin result := 0; R1.Y := R1Top and 65535; R1.X := R1Top shr 16; R1D.Y := R1Dim and 65535; R1D.X := R1Dim shr 16; R2.Y := R2Top and 65535; R2.X := R2Top shr 16; R2D.Y := R2Dim and 65535; R2D.X := R2Dim shr 16; result := result or IsPointInRectangle(R1.X,R1.Y, R2.X,R2.Y,R2D.X,R2D.Y)*1; result := result or IsPointInRectangle(R1.X+R1D.X-1,R1.Y, R2.X,R2.Y,R2D.X,R2D.Y)*2; result := result or IsPointInRectangle(R1.X, R1.Y+R1D.Y-1, R2.X,R2.Y,R2D.X,R2D.Y)*4; result := result or IsPointInRectangle(R1.X+R1D.X-1,R1.Y+R1D.Y-1, R2.X,R2.Y,R2D.X,R2D.Y)*8; if result=0 then begin if R1.X<R2.X then begin if R1.X+R1D.X>R2.X+R2D.X then begin if R1.Y<R2.Y then begin if R1.Y+R1D.Y>R2.Y+R2D.Y then result := 16; end; end; end; end; end;
Bien sûr, bientôt il y aura l'ajout dans le wrapper KGF_SUB.bas et on pourra passer les 8 paramètres sans problème. Comme tu vous, la fonction retourne une "photo" de la situation de recouvrement. Rien de dynamique dans cela. Et dans le programme de collision des sprites de mon précédent post, j'utilise cette valeur via un SELECT...CASE...AND_SELECT pour traiter chaque cas, afin de renverser ou non la direction horizontale er/ou la direction verticale. Une fois qu'on a ce status de recouvrement, c'est très simple, même s'il faut considérer un grand nombre de cas possibles. Mais chaque cas est extrêmement simple à traiter. | |
| | | 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 - 21:48 | |
| On peut dire que PtInRect a "save your life" ! Vu comme cela, cela fonctionne en effet... Comme tu l'as remarqué, la partie 2D est le parent pauvre dans panoramic. mais je suppose que l'on peut simuler un 2D avec du 3D et dans ce cas profiter des 3D_rotate, 3D_COLLISION_AS_FACE et autres fonctions sympa... | |
| | | 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 - 22:00 | |
| C'est ce que j'ai proposé hier après-midi. Utiliser un scene3d avec des 3d_plane à la place des sprite. Laisser la coordonnée z à zéro et utiliser uniquement le plan X-Y. Cela devient une simulation d'une scene2d, et on a la fonction collision() qui devrait marcher. | |
| | | 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 - 22:11 | |
| Là je laisse la place aux spécialistes 3D... J'ai pas vraiment encore compris comment cela fonctionnait cette affaire là. Dans ce domaine, il manque peut être un petit tuto de base (commenté de préférence ) | |
| | | 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 - 23:02 | |
| J'ai mis à jour "KGF_SUB.bas" et "demo_KGF_SUB avec FindArrayAddress.bas". On a maintenant accès au wrapper autour de la fonction DLL. Télé-chargez KGF.dll, KGF_SUB.bas et "demo_KGF_SUB avec FindArrayAddress.bas" et exécutez ce dernier programme. La toute dernière fonction du combo donne un exemple d'utilisation de la nouvelle fonction IsRectangleInRectangle - c'est assez parlant. Et dans le programme de collision, j'ai adapté le code à l'utilisation du wrapper KGF_SUB.bas. J'ai néanmoins tout mis en commentaire, avec des instructions pour activer la version "wrapper". - 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
' le commentaire "' wrapper" indique ce qu'il fait faire ' pour utiliser KGF_SUB à la place des appels directs à DLL_CALLx
label sortie
caption 0,"Interrompre par Echap" on_close 0,sortie dll_on "KGF.dll" : ' wrapper désactiver cette ligne ' wrapper activer la ligne suivante: ' KGF_initialize()
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%) ' wrapper désactiver les 6 lignes suivantes 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%) ' wrapper et activer les 2lignes suivantes ' IsRectangleInRectangle(pos_x%(s1%),pos_y%(s1%),larg%(s1%),haut%(s1%), pos_x%(s2%),pos_y%(s2%),larg%(s2%),haut%(s2%)) ' choc% = IsRectangleInRectangle% 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
' wrapper activer la ligne suivante: ' #INCLUDE "KGF_SUB.bas"
| |
| | | 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 - 23:15 | |
| Laissons un peu de temps à Jack, il a justement dit qu'il voulait reprendre cette partie du développement de Panoramic qu'il avait dû stopper pour aller dans d'autres directions. On peut utiliser la 3D bien sûr, mais en même temps, on utilise plus de ressource alors que cela n'est pas nécessaire. En plus on a les fonctions de Klaus pour pallier en attendant. A noter quand même la chute de performance quand on déplace de nombreux sprites. Il y a sans doute des choses optimisables à ce niveau là dans Panoramic. | |
| | | 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 - 23:26 | |
| | |
| | | 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 - 23:29 | |
| Par contre Klaus j'ai une erreur dans ta DLL quand je teste la fonction 185, j'obtiens: tableau_entier% is not a valid floatting point value, pour info, mais c'est peut être par ce que je ne fais pas quelque chose avant | |
| | | 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 - 23:47 | |
| Pour le moment, évite d'utiliser les fonctions de tableaux et adresses. Mais tu as sûrement une confusion de versions. Recharge KGF.dll, KGF_SUB.bas et "demo_KGF_SUB avec FindArrayAddress.bas" - ces modules vont ensemble. | |
| | | 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
| |
| |
| |