[DarkBasic] Moteur de collision 2D

Syltech Message lu Posté le 12 Déc 2008 à 21:41 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Voici un moteur de collision 2D que j'avais commencé il y a longtemps.
A l’aide des personnes présente sur le forum GameCorp, ce petit bout de code a subit pas mal d’améliorations, la dernière mise à jour date du 12 février.

Ce code fonctionne parfaitement bien ! Tout de même, il reste encore un bug mineur à corriger. Dès que je trouverai le temps, je m’en occuperai.

Un tutorial sur la collision 2D est aussi en cours de réalisation, encore une fois ce n’est qu’une question de temps libre avant qu’il soit fini et publié sur le site GameCorp. Il expliquera la mécanique de mon moteur de collision et vous expliquera les cas particulier d’un tel système.

Je n’ai mis pour l’instant que des commentaires en début de code, j’en rajouterais dès que possible.

Important : en exécutant ce programme, DarkBasic trouvera une erreur au niveau des symboles « && », vous n’avez qu’à faire revenir la ligne commençant par « && » à la ligne au dessus, je l'ai mise en dessous pour que mon code s'affiche proprement sur le forum.

Ce code est libre. Si vous avez une question n’hésitez pas à la poser dans ce même post.

Code :
` Création d'un Type de variable qui contient la structure des murs qui seront créés.
Type Tmur
ox as float
oy as float
dx as float
dy as float
lx as float
ly as float
l2 as float
l as float
EndType

` On régle la résolution d'écran en 1024x768, la résolution peut bien évidement être modifiée.
set display mode 1024,768,32,0

` On active le mode rafraichissement manuel à l'aide de la commande "sync on"
sync on

` On fixe le nombre d'images par seconde à 60
sync rate 60

` On cache la souris.
hide mouse

` On déclare la variable nWall_max en global et on l'initialise à 8.
` La variable "nWall_max" correspond au nombre de murs.
Global nWall_max as integer : nWall_max=8


` On créé un tableau contenant les informations de tous les murs.
` Ici 8 murs, sachant que le mur 0 existe, d'ou le "nWall_max-1".
Dim wallmap(nWall_max-1) as Tmur

` On créé une map de murs.
` La commande "Gosub" renvoie à l'étiquette "Map_2D"
` Dans cette étiquette, la fonction "add_wall" permet de créé de nouveaux murs.
Gosub Map_2D

` Les 2 premières variables permettent de stocker les coordonnées X,Y de la projection du joueur sur un mur.
Global wallx as float
Global wally as float

` Cette variable correspond à la distance la plus courte entre le joueur et le mur.
Global Dist as float

` Ces 2 variables correspondent au coéficient directeur qui va du mur au joueur.
Global nx as float
Global ny as float

` Ces variables stockent le numéro des 2 murs les plus proches.
Global nWall_A as integer
Global nWall_B as integer

` "testA" et "testB" contiennent les distances des murs "nWall_A" et "nWall_B" au joueur.
` Elle permettent des tests pour des cas particulier.
` Pour éviter les tremblement du joueur dans les angles par exemple.
testA as integer
testB as integer

` La variable "taille" correspond à la taille du joueur.
Global taille as integer : taille=30

` La variable "vitesse" correspond à la vitesse du joueur.
vitesse as integer : vitesse=8

` Ces variables contiennent les informations du joueur.
oldx as float : Joueur_x as float : Joueur_x=125
oldy as float : Joueur_y as float : Joueur_y=0

` Ici, on déclare la variable "Wall" de de type Tmur(la structure de nos murs)
` Cette variable permet d'effectuer tous les calculs de collision avec le mur le plus proche.
Wall as Tmur

do

   cls

   Gosub Deplacements

   mur_le_plus_proche(Joueur_x,Joueur_y)
   wall=wallmap(nWall_A)

   Position_et_Distance_de_Projection(Joueur_x,Joueur_y,wall)

   if abs(dist)<=taille
      hit=1
      CoeficientDirecteurInv(Joueur_x,Joueur_y,wallx,wally)
      Joueur_x=wallx+nx : Joueur_y=wally+ny
      testA=isUnder(Joueur_x,Joueur_y,Wall) : wall=wallmap(nWall_B) : testB=isUnder(Joueur_x,Joueur_y,Wall)
      if ((testA>0 && testB>0) || (testA<0 && testB<0)) || ((testA<0 && testB>0) || (testA>0 && testB<0) 
&& ((wallmap(nWall_A).ox<>wallmap(nWall_B).dx && wallmap(nWall_A).oy<>wallmap(nWall_B).dx)))
         if abs(testB)<=taille
            Joueur_x=oldx
            Joueur_y=oldy
            Position_et_Distance_de_Projection(Joueur_x,Joueur_y,wall)
            CoeficientDirecteurInv(Joueur_x,Joueur_y,wallx,wally)
            Joueur_x=wallx+nx : Joueur_y=wally+ny
         endif
      endif
   else
      hit=0
   endif

   old_f1_key=f1_key : f1_key=keystate(59)
   if f1_key=1 && old_f1_key=0
   if rate=60 : rate=0 : else : rate=60 : endif
   sync rate rate
   endif

   Gosub Affichage

   sync

loop


Deplacements:

   oldx=Joueur_x : oldy=Joueur_y
   if leftkey()=1  : a=a+3 : endif
   if rightkey()=1 : a=a-3 : endif
   if upkey()=1
   Joueur_x=Joueur_x+cos(a)*vitesse
   Joueur_y=Joueur_y-sin(a)*vitesse
   endif
   if downkey()=1
   Joueur_x=Joueur_x+cos(a)*((vitesse*-1)/2)
   Joueur_y=Joueur_y-sin(a)*((vitesse*-1)/2)
   endif

Return

Affichage:

   circle Joueur_x,Joueur_y,taille
   line Joueur_x,Joueur_y,Joueur_x+cos(a)*taille,Joueur_y-sin(a)*taille

   text 0,0,"Appuyez sur F1 pour changer le Fps."
   text 0,14,"FPS : "+str$(screen fps())
   text 0,28,"Hit : "+str$(hit)

Return


Map_2D:

nWall=0
add_wall(nWall,400,300,200,150)

nWall=1
add_wall(nWall,300,150,200,300)

nWall=2
add_wall(nWall,200,300,400,300)

nWall=3
add_wall(nWall,800,200,600,200)

nWall=4
add_wall(nWall,600,200,600,400)

nWall=5
add_wall(nWall,600,400,800,200)

nWall=6
add_wall(nWall,400,400,400,600)

nWall=7
add_wall(nWall,400,600,600,600)

Return

function add_wall(nWall as integer,ox as float,oy as float,dx as float,dy as float)
   wallmap(nWall).ox=ox
   wallmap(nWall).oy=oy
   wallmap(nWall).dx=dx
   wallmap(nWall).dy=dy
   wallmap(nWall).lx=wallmap(nWall).dx-wallmap(nWall).ox
   wallmap(nWall).ly=wallmap(nWall).dy-wallmap(nWall).oy
   wallmap(nWall).l2=wallmap(nWall).lx^2+wallmap(nWall).ly^2
   wallmap(nWall).l=sqrt(wallmap(nWall).l2)
endfunction

function Position_et_Distance_de_Projection(x as float, y as float, Wall as Tmur)
   coef as float : t as float
   coef = (x-Wall.ox)*Wall.lx+(y-Wall.oy)*Wall.ly
   t = coef/(Wall.lx*Wall.lx+ Wall.ly*Wall.ly)
   if t>=0 && t<=1
      wallx = Wall.ox + t*Wall.lx
      wally = Wall.oy + t*Wall.ly
      dist = Distance(x,y,wallx,wally)
   else
      if t<0
      wallx = Wall.ox
      wally = Wall.oy
      dist = Distance(x,y,Wall.ox,Wall.oy)
      endif
      if t>1
      wallx = Wall.dx
      wally = Wall.dy
      dist = Distance(x,y,Wall.dx,Wall.dy)
      endif
   endif
endfunction

function Distance_de_Projection(x as float, y as float, Wall as Tmur)
   coef as float : t as float : vdist as float : wx as float : wy as float
   coef = (x-Wall.ox)*Wall.lx+(y-Wall.oy)*Wall.ly
   t = coef/(Wall.lx*Wall.lx+ Wall.ly*Wall.ly)
   if t>=0 && t<=1
      wx = Wall.ox + t*Wall.lx
      wy = Wall.oy + t*Wall.ly
      vdist = Distance(x,y,wx,wy)
   else
      if t<0
      vdist = Distance(x,y,Wall.ox,Wall.oy)
      endif
      if t>1
      vdist = Distance(x,y,Wall.dx,Wall.dy)
      endif
   endif
endfunction vdist

function mur_le_plus_proche(x as float,y as float)
   Distance as float : wall as Tmur
   rayon_A as float : rayon_B as float
   rayon_A=9999 : rayon_B=9999
   for i=0 to nWall_max-1 : wall=wallmap(i)
      Distance=abs(Distance_de_Projection(x, y, wall))
      if Distance<rayon_A
         nWall_B=nWall_A
         rayon_B=rayon_A
         nWall_A=i
         rayon_A=Distance
      else
         if Distance<rayon_B
            nWall_B=i
            rayon_B=Distance
         endif
      endif
      draw(i)
   next i
endfunction

function Distance(x1 as float, y1 as float, x2 as float, y2 as float)
   result as float : result = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
endfunction result

function CoeficientDirecteurInv(x1 as float, y1 as float, x2 as float, y2 as float)
   Normalex as float : Normaley as float : MagnitudeInv as float
   Normalex=x1-x2
   Normaley=y1-y2
   MagnitudeInv = Taille / Sqrt(Normalex*Normalex+Normaley*Normaley)
   nx=Normalex * MagnitudeInv: ny=Normaley * MagnitudeInv
endfunction

function isUnder(x as float, y as float, Wall as Tmur)
   coef as float : t as float : vdist as float
   coef = (x-Wall.ox)*Wall.lx + (y-Wall.oy)*Wall.ly
   t = coef/(Wall.lx*Wall.lx + Wall.ly*Wall.ly)
   if t>=0 && t<=1
      vDist = ((x-Wall.ox)*Wall.ly - (y-Wall.oy)*Wall.lx) / wall.l
   endif
endfunction vDist

function draw(nWall as integer)
   line wallmap(nWall).ox,wallmap(nWall).oy,wallmap(nWall).dx,wallmap(nWall).dy
endfunction


J’espère que vous comprendrez comment ça fonctionne !
Bon courage !

Syltech
Dernière édition le 12 Fév 2009 à 11:32
Image
Darktib Message lu Posté le 12 Déc 2008 à 23:36 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Tres bon code, franchement il tourne bien et sans bug^^

D'autant plus qu'il est adaptable facilement a tout type de plan... Super utile :smile:

Mod Message lu Posté le 13 Déc 2008 à 10:53 Bulle
Avatar de Mod
Webmaster

Messages : 4954
GCPoints : 2100823
Excellent, ça marche parfaitement bien :smile: . Et ça pourrait bien m'éviter des recherches fastidieuses sur collisions (cf ce sujet, je travaille à l'occasion exactement sur ce genre de moteur : http://www.game-corp.net/topic-694.html).

Merci pour ce code ;).
Dernière édition le 13 Déc 2008 à 10:54
Syltech Message lu Posté le 13 Déc 2008 à 12:52 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Content que ca vous plaise :)

@Darktib, oui, à partir de ce code il y a moyen de faire beaucoup de jeu :).

@Mod, de rien ^^, si tu as besoin d'aide pour faire ton moteur de collision, s'il y a des choses que tu ne comprend pas n'hésite pas à demander surtout!
Moi je suis passé aux collisions 3D donc je maitrise parfaitement le sujet en 2D, quand j'ai commencé à programmer se moteur, il m'a fallu du temps avant de comprendre certaines chose qui ne sont pas expliqués sur le net, des cas particulier qui sont incontournable si on veut réussir un bon moteur.

Syltech
Image
Mod Message lu Posté le 13 Déc 2008 à 15:04 Bulle
Avatar de Mod
Webmaster

Messages : 4954
GCPoints : 2100823
A l'occasion, n'hésites pas à écrire un tutoriel, ce sera d'autant plus utile s'il n'existe pas de ressources sur le sujet sur le net :happy: .
Syltech Message lu Posté le 13 Déc 2008 à 18:05 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Hum si je trouve le temps je ferais ça :proud: en plus j'ai déjà tous les plans dans la tête :proud: manque plus qu'a écrire ça en bon français :rolleyes:
Dernière édition le 13 Déc 2008 à 18:06
Image
Syltech Message lu Posté le 14 Déc 2008 à 09:50 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
J'ai remarqué une erreur dans mon programme...

avec ma map d'exemple ça fonctionne bien, mais si l'on modifie ce mur là, de cette façon:

Code :
nWall=6
wallmap(nWall).ox=500  <--- avant on avait 400 avant
wallmap(nWall).oy=400
wallmap(nWall).dx=400
wallmap(nWall).dy=600
wallmap(nWall).lx=wallmap(nWall).dx-wallmap(nWall).ox
wallmap(nWall).ly=wallmap(nWall).dy-wallmap(nWall).oy
wallmap(nWall).l2=wallmap(nWall).lx^2+wallmap(nWall).ly^2
wallmap(nWall).l=sqrt(wallmap(nWall).l2)


On remarque que le joueur tremble dans l'angle entre les 2 murs c'est tout à fait normal enfaite, il manque quelque chose :rolleyes:

Juste 2 lignes à rajoutés:

Code :
      ` On refait un test de collision mais cette fois avec le mur_B
      testA=isUnder(x,y,Wall) : wall=wallmap(nWall_B) : testB=isUnder(x,y,Wall)
      ` Ce test permet de savoir si on se trouve dans un coin entre 2 murs ou pas
      ` sans cette condition le personnage se coincerait facilement aux extrémités des murs
      if testA<>0 && testB<>0 && ((testA>0 && testB>0) || (testA<0 && testB<0))
         if abs(testB)<taille
            x=oldx          <--- ici
            y=oldy          <--- et ici
            calcul_vectoriel(x,y,wall)
            normal(wallx,wally,x,y)
            normal(wallx,wally,wallx+nx,wally+ny)
            x=wallx+nx*-1 : y=wally+ny*-1
         endif
      endif


Sinon j'ai bien avancé mon tutoriel, mais je bloque pas mal pour l'explication de mes calculs.

Syltech
Dernière édition le 14 Déc 2008 à 09:52
Image
Darktib Message lu Posté le 14 Déc 2008 à 11:57 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Je ne vois pas de grosse différence, chez moi avec l'ancien code ca n'oscille pas ^^

Sinon sur quoi bloque tu pour tes calculs ?
Syltech Message lu Posté le 14 Déc 2008 à 12:18 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Ah! Enfaite, je me suis trompé... remplace plutôt mon 500 par un 600 est essaye dans tous les angles tu verra ;)

Bha enfaite c'était surtout pour expliqué comment fonctionne mon calcul de coefficient, pour obtenir la position x/y de la projection.
Mais c'est bon enfaite, j'ai décidé de ne pas l'expliquer :tongue: et de donner la formule toute faite.
La formule ne sera jamais modifié dans mon tutoriel donc...

Syltech
Image
Darktib Message lu Posté le 14 Déc 2008 à 12:22 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Je vois les tremblements mais la correction ne change rien, on dirait meme que ca tremble plus vite^^

Sinon je pense que la meilleure chose pour l'explication c'est la démonstration des résultats.
Mais ne pas l'expliquer est un bon choix tant qu'on sait a quoi correspond chaque variable^^
Syltech Message lu Posté le 14 Déc 2008 à 12:32 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Hum... c'est bizarre que tu ne vois pas de changement avec le rajout des lignes,

Code :
x=oldx 
y=oldy


J'ai bien repris tout le code que j'ai posté au départ, j'ai rajouté ces lignes juste après,

Code :
if abs(testB)<taille

Et je n'ai plus de tremblements.


Citation :

Sinon je pense que la meilleure chose pour l'explication c'est la démonstration des résultats.
Mais ne pas l'expliquer est un bon choix tant qu'on sait a quoi correspond chaque variable^^


Ok, ça me rassure par contre, j'ai une question...

Pour mon tutoriel, il vaut peut être mieux que je le poste sur le forum Partie par Partie pour voir avec vous si quelque chose cloche non? Plutot que de le posté directement en tant qu'article?
Image
Darktib Message lu Posté le 14 Déc 2008 à 12:48 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Tu peux montrer des parties pour que tout le monde puisse le corriger, mais si tu le poste directement il sera de toute facon validé avant de pouvoir etre visible. Pour l'instant c'est Mod le validateur^^

Sinon j'ai bien rajouté ces deux ligne dans la condition indiquée, mais ca ne fait que trembler plus vite...

Voici le code total :
Spoiler - Cliquez pour afficher
Code :
` Moteur de collision 2D
` Codé par Syltech

Type v2d
ox as float
oy as float
dx as float
dy as float
lx as float
ly as float
l2 as float
l as float
EndType

set display mode 1024,768,32,1
sync on

hide mouse

` nWall_max est le nombre de mur de la map
Global nWall_max as integer : nWall_max=8

` On cree un tableau qui va stocker l'information de chaque mur
Dim wallmap(nWall_max-1) as v2d

` Voici un exemple de map
nWall=0
wallmap(nWall).ox=600   REM <---- précédente valeur : 400
wallmap(nWall).oy=300
wallmap(nWall).dx=200
wallmap(nWall).dy=150
wallmap(nWall).lx=wallmap(nWall).dx-wallmap(nWall).ox
wallmap(nWall).ly=wallmap(nWall).dy-wallmap(nWall).oy
wallmap(nWall).l2=wallmap(nWall).lx^2+wallmap(nWall).ly^2
wallmap(nWall).l=sqrt(wallmap(nWall).l2)

nWall=1
wallmap(nWall).ox=200
wallmap(nWall).oy=150
wallmap(nWall).dx=200
wallmap(nWall).dy=300
wallmap(nWall).lx=wallmap(nWall).dx-wallmap(nWall).ox
wallmap(nWall).ly=wallmap(nWall).dy-wallmap(nWall).oy
wallmap(nWall).l2=wallmap(nWall).lx^2+wallmap(nWall).ly^2
wallmap(nWall).l=sqrt(wallmap(nWall).l2)

nWall=2
wallmap(nWall).ox=200
wallmap(nWall).oy=300
wallmap(nWall).dx=400
wallmap(nWall).dy=300
wallmap(nWall).lx=wallmap(nWall).dx-wallmap(nWall).ox
wallmap(nWall).ly=wallmap(nWall).dy-wallmap(nWall).oy
wallmap(nWall).l2=wallmap(nWall).lx^2+wallmap(nWall).ly^2
wallmap(nWall).l=sqrt(wallmap(nWall).l2)

nWall=3
wallmap(nWall).ox=800
wallmap(nWall).oy=200
wallmap(nWall).dx=600
wallmap(nWall).dy=200
wallmap(nWall).lx=wallmap(nWall).dx-wallmap(nWall).ox
wallmap(nWall).ly=wallmap(nWall).dy-wallmap(nWall).oy
wallmap(nWall).l2=wallmap(nWall).lx^2+wallmap(nWall).ly^2
wallmap(nWall).l=sqrt(wallmap(nWall).l2)

nWall=4
wallmap(nWall).ox=600
wallmap(nWall).oy=200
wallmap(nWall).dx=600
wallmap(nWall).dy=400
wallmap(nWall).lx=wallmap(nWall).dx-wallmap(nWall).ox
wallmap(nWall).ly=wallmap(nWall).dy-wallmap(nWall).oy
wallmap(nWall).l2=wallmap(nWall).lx^2+wallmap(nWall).ly^2
wallmap(nWall).l=sqrt(wallmap(nWall).l2)

nWall=5
wallmap(nWall).ox=600
wallmap(nWall).oy=400
wallmap(nWall).dx=800
wallmap(nWall).dy=200
wallmap(nWall).lx=wallmap(nWall).dx-wallmap(nWall).ox
wallmap(nWall).ly=wallmap(nWall).dy-wallmap(nWall).oy
wallmap(nWall).l2=wallmap(nWall).lx^2+wallmap(nWall).ly^2
wallmap(nWall).l=sqrt(wallmap(nWall).l2)

nWall=6
wallmap(nWall).ox=400
wallmap(nWall).oy=400
wallmap(nWall).dx=400
wallmap(nWall).dy=600
wallmap(nWall).lx=wallmap(nWall).dx-wallmap(nWall).ox
wallmap(nWall).ly=wallmap(nWall).dy-wallmap(nWall).oy
wallmap(nWall).l2=wallmap(nWall).lx^2+wallmap(nWall).ly^2
wallmap(nWall).l=sqrt(wallmap(nWall).l2)

nWall=7
wallmap(nWall).ox=400
wallmap(nWall).oy=600
wallmap(nWall).dx=600
wallmap(nWall).dy=600
wallmap(nWall).lx=wallmap(nWall).dx-wallmap(nWall).ox
wallmap(nWall).ly=wallmap(nWall).dy-wallmap(nWall).oy
wallmap(nWall).l2=wallmap(nWall).lx^2+wallmap(nWall).ly^2
wallmap(nWall).l=sqrt(wallmap(nWall).l2)

` Cette variable contient dans la boucle principale les informations du mur le plus proche.
wall as v2d

Global dist as float
Global wallx as float
Global wally as float
Global nx as float
Global ny as float

` 2 variables importantes qui permettent de régler la taille et la vitesse du joueur
Global taille as integer
taille=30
vitesse as integer
vitesse=8

` Position de départ du joueur
oldx as float : x as float : x=125
oldy as float : y as float : y=0

` Boucle principale
do

   ` On efface l'écran
   cls

   ` Deplacement du point avec les fleches
   oldx=x : oldy=y
   if leftkey()=1  : a=a+3 : endif
   if rightkey()=1 : a=a-3 : endif
   if upkey()=1
   x=x+cos(a)*vitesse
   y=y-sin(a)*vitesse
   endif
   if downkey()=1
   x=x+cos(a)*((vitesse*-1)/2)
   y=y-sin(a)*((vitesse*-1)/2)
   endif

   ` Calcul des 2 murs les plus proches(on peut largement optimiser la fonction mur_le_plus_proche)
   nWall_A=mur_le_plus_proche(x,y,nWall_max)
   nWall_B=mur_le_plus_proche(x,y,nWall_A)
   wall=wallmap(nWall_A)

   ` Calcul des collisions avec le mur le plus proche
   calcul_vectoriel(x,y,wall)
   ` Calcul de la normal du mur
   normal(wallx,wally,x,y)
   normal(wallx,wally,wallx+nx,wally+ny)

   ` Si la distance du point au mur_A est inférieur à la taille du joueur alors il y a collision
   if abs(dist)<=taille
      hit=1
      x=wallx+nx*-1 : y=wally+ny*-1

      ` On refait un test de collision mais cette fois avec le mur_B
      testA=isUnder(x,y,Wall) : wall=wallmap(nWall_B) : testB=isUnder(x,y,Wall)
      ` Ce test permet de savoir si on se trouve dans un coin entre 2 murs ou pas
      ` sans cette condition le personnage se coincerait facilement aux extrémités des murs
      if testA<>0 && testB<>0 && ((testA>0 && testB>0) || (testA<0 && testB<0))
         if abs(testB)<taille
rem /modif
            x=oldx
            y=oldy
rem modif/
            calcul_vectoriel(x,y,wall)
            normal(wallx,wally,x,y)
            normal(wallx,wally,wallx+nx,wally+ny)
            x=wallx+nx*-1 : y=wally+ny*-1
         endif
      endif

   else
      hit=0
   endif

   rem Affichage de la map
   for i=0 to nWall_max-1
      draw(i)
   next i

   rem Affichage du joueur
   circle x,y,taille
   line x,y,x+cos(a)*taille,y-sin(a)*taille

   rem Affichage d'informations
   text 0,0,str$(hit)
   text 0,20,"FPS : "+str$(screen fps())

   sync

loop

function calcul_vectoriel(x as float, y as float, Wall as v2d)
   coef as float
   coef = ((x-Wall.ox)*Wall.lx + (y-Wall.oy)*Wall.ly) / Wall.l2
   wallx = Wall.ox + Wall.lx*coef
   wally = Wall.oy + Wall.ly*coef
   if (wallx=>Wall.ox && wally=>Wall.oy && wallx<=Wall.dx && wally<=Wall.dy) or (wallx=<Wall.ox && wally=>Wall.oy && wallx>=Wall.dx && wally<=Wall.dy) or (wallx=>Wall.ox && wally=<Wall.oy && wallx<=Wall.dx && wally>=Wall.dy) or (wallx=<Wall.ox && wally=<Wall.oy && wallx>=Wall.dx && wally>=Wall.dy)
      dist = ((x-Wall.ox)*Wall.ly - (y-Wall.oy)*Wall.lx) / Wall.l
   else
         if distance(x,y,Wall.ox,Wall.oy)<distance(x,y,Wall.dx,Wall.dy)
            wallx = Wall.ox
            wally = Wall.oy
            dist = distance(x,y,Wall.ox,Wall.oy)
         else
            wallx = Wall.dx
            wally = Wall.dy
            dist = distance(x,y,Wall.dx,Wall.dy)
         endif
   endif
endfunction

function distance_vectoriel(x as float, y as float, Wall as v2d)
   vDist as float
   coef as float
   coef = ((x-Wall.ox)*Wall.lx + (y-Wall.oy)*Wall.ly) / Wall.l2
   wallx = Wall.ox + Wall.lx*coef
   wally = Wall.oy + Wall.ly*coef
   if (wallx=>Wall.ox && wally=>Wall.oy && wallx<=Wall.dx && wally<=Wall.dy) or (wallx=<Wall.ox && wally=>Wall.oy && wallx>=Wall.dx && wally<=Wall.dy) or (wallx=>Wall.ox && wally=<Wall.oy && wallx<=Wall.dx && wally>=Wall.dy) or (wallx=<Wall.ox && wally=<Wall.oy && wallx>=Wall.dx && wally>=Wall.dy)
      vDist = ((x-Wall.ox)*Wall.ly - (y-Wall.oy)*Wall.lx) / Wall.l
   else
         if distance(x,y,Wall.ox,Wall.oy)<distance(x,y,Wall.dx,Wall.dy)
            vDist = distance(x,y,Wall.ox,Wall.oy)
         else
            vDist = distance(x,y,Wall.dx,Wall.dy)
         endif
   endif
endfunction vDist

function mur_le_plus_proche(x as float,y as float,saut as integer)
vDist as float
rayon as float
nWall as integer
wall as v2d
rayon=9999
for i=0 to nWall_max-1
   wall=wallmap(i)
   vDist=abs(distance_vectoriel(x, y, wall))
   if i<>saut
   if vDist<rayon
      nWall=i
      rayon=vDist
   endif
   endif
next i
endfunction nWall

function distance(x1 as float, y1 as float, x2 as float, y2 as float)
   result as float
   result = sqrt((x2-x1)^2+(y2-y1)^2)
endfunction result

function normal(x1 as float,y1 as float,x2 as float,y2 as float)
   x3=x1             : y3=y1             : z3=10000
   Normalex as float : Normaley as float : Normalez as float
   Normalex=((y2-y1)*(z3-z1))-((z2-z1)*(y3-y1))
   Normaley=((z2-z1)*(x3-x1))-((x2-x1)*(z3-z1))
   Normalez=((x2-x1)*(y3-y1))-((y2-y1)*(x3-x1))
   Magnitude as float
   Magnitude=Sqrt(Normalex^2+Normaley^2+Normalez^2)
   nx=Normalex/Magnitude*taille : ny=Normaley/Magnitude*taille : nz=Normalez/Magnitude*taille
endfunction

function isUnder(x as float, y as float, Wall as v2d)
   coef as float
   coef = ((x-Wall.ox)*Wall.lx + (y-Wall.oy)*Wall.ly) / Wall.l2


   wallx = Wall.ox + Wall.lx*coef
   wally = Wall.oy + Wall.ly*coef
   if (wallx=>Wall.ox && wally=>Wall.oy && wallx<=Wall.dx && wally<=Wall.dy) or (wallx=<Wall.ox && wally=>Wall.oy && wallx>=Wall.dx && wally<=Wall.dy) or (wallx=>Wall.ox && wally=<Wall.oy && wallx<=Wall.dx && wally>=Wall.dy) or (wallx=<Wall.ox && wally=<Wall.oy && wallx>=Wall.dx && wally>=Wall.dy)
      vDist = ((x-Wall.ox)*Wall.ly - (y-Wall.oy)*Wall.lx) / Wall.l
   endif
endfunction vDist

function draw(nWall as integer)
   line wallmap(nWall).ox,wallmap(nWall).oy,wallmap(nWall).dx,wallmap(nWall).dy
endfunction


edit : désolé pour déformer le forum^^
Dernière édition le 14 Déc 2008 à 12:49
Syltech Message lu Posté le 14 Déc 2008 à 12:57 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Hehe, enfaite si on avait pas le même résultat c'est que moi je changeais la valeur du mur 6, je l'avais précisé nWall=6 ^^
Sinon oui tu viens de trouver un cas particulier que j'avais jamais vu, faudra que je m'occupe de se problème...
Ou alors la solution et de créer une map avec des mur tous reliés entre eux, le phénomène se produit quand on est a proximité d'un seul mur et d'une seule extrémité de mur si je ne me trompe pas.

Syltech
Image
Darktib Message lu Posté le 14 Déc 2008 à 13:04 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
En effet ca marche pour le mur 6 :smile:

Sinon oui la cas particulier c'est bien ce que tu as dit, maintenat reste a le gérer^^
Mod Message lu Posté le 14 Déc 2008 à 13:19 Bulle
Avatar de Mod
Webmaster

Messages : 4954
GCPoints : 2100823
Problème réglé pour la première partie du bug, aucun soucis remarqué.

Pour le second bug, il faudrait à mon avis tester si la nouvelle position calculée après collision glissante ne rentre pas dans un autre mur, auquel cas réajuster une nouvelle fois les coordonnées.

Je ne saisis pas encore bien le code pour pouvoir faire la modification, mais je pense que ça suffirait à résoudre le problème.
SEB Message lu Posté le 14 Déc 2008 à 13:24 Bulle
Avatar de SEB
Membre Evolué

Messages : 554
GCPoints : 103313
Une petite récursion alors peut-etre? si on a une collision on résoud le glissement et on retest le tout. Avec une profondeur limit au cas ou... c'est souvent comme ca qu'on ajuste les réaction au collision avec un systeme incrémental plus ou moins précis.

NextGine : 3D games engine
Nombre de lignes actuel : 77683
Syltech Message lu Posté le 14 Déc 2008 à 13:54 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266

Citation :

Pour le second bug, il faudrait à mon avis tester si la nouvelle position calculée après collision glissante ne rentre pas dans un autre mur, auquel cas réajuster une nouvelle fois les coordonnées.



Mod, c'est tout a fait ce que je fait dans mon programme, tu peut même testé juste avec ça:

Code :
      ` On refait un test de collision mais cette fois avec le mur_B
      testA=isUnder(x,y,Wall) : wall=wallmap(nWall_B) : testB=isUnder(x,y,Wall)
      ` Ce test permet de savoir si on se trouve dans un coin entre 2 murs ou pas
      ` sans cette condition le personnage se coincerait facilement aux extrémités des murs
      if testA<>0 && testB<>0 && ((testA>0 && testB>0) || (testA<0 && testB<0))
         if abs(testB)<taille
            x=oldx     
            y=oldy         
         endif
      endif


Enfaite cette partie vérifie et corrige s'il y a un mur qui va venir en travers de la route de notre glissade.
En 3D je fait 5 voir 6 tests selon la map. Ici j'ai bien 2 test de collision.

Je vais prendre du temps, pour corriger le problème.

Syltech

Edit: J'ai réussi a bien me replonger de dedans et j'ai trouvé le problème :)
Enfaite cette condition,

Code :
if testA<>0 && testB<>0 && ((testA>0 && testB>0) || (testA<0 && testB<0))

corrige un cas particulier dans les angles, c'est le système le plus important sans lequel on se coincerait un peu partout aux extrémités de mur.
Il ne me reste plus qu'a l'améliorer enfaite :smile:
Dernière édition le 14 Déc 2008 à 14:01
Image
Syltech Message lu Posté le 14 Déc 2008 à 17:30 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Voila c'est corrigé!

L'erreur était exactement ou je pensais, il fallait juste identifié ce nouveau cas particulier est le corriger.

Code :
if testA<>0 && testB<>0 && ((testA>0 && testB>0) || (testA<0 && testB<0)) 
or (((wallmap(nWall_A).ox<>wallmap(nWall_B).dx && wallmap(nWall_A).oy<>wallmap(nWall_B).dx)) 
&& (testA<0 && testB>0) || (testA>0 && testB<0))

Vous avez juste à remplacer par cette ligne.
Par contre il y a pas tout sur la même ligne de façon a pas déformé le forum ^^ à vous de corrigé :)

Syltech
Dernière édition le 14 Déc 2008 à 17:33
Image
Darktib Message lu Posté le 14 Déc 2008 à 20:22 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Ca marche nickel maintenant.

Reste plus que les optimisations^^
Syltech Message lu Posté le 14 Déc 2008 à 20:39 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Ouaip, je vais voir ce que je peux faire :smile:
J'ai pas mal de projet en cour la, j'avance mon tutoriel sur les collision, j'ai 1 projet de jeu en 3D avec une équipe, et j'ai d'autres petit projets que j'aimerais bien finir.

En même temps, j'avance bien en programmation depuis quelque temps, donc je doit pouvoir trouver quelques heures pour travailler dessus :smile:

Syltech
Image
Répondre
GameCorp - Site d'apprentissage et d'entraide à la création de jeux vidéo.
XHTML Valid 1.1 - Page générée en 0.0835 secondes