[DarkBasic] Moteur de collision 2D

Darktib Message lu Posté le 08 Jan 2009 à 20:43 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
dx,dy : t>1 je suppose (au lieu de t>0) ?

En gros, maintenant les variables cx,cy sont inutiles ?

En tout cas c'est une bonne optimisation, en ce moment je commence a programmer la librairie utilisant ce mode de collisions^^

edit : juste une question: si tu devais renommer les fonctions calcul_vectoriel et distance_vectoriel pour avoir des noms plus explicites, quels noms mettrait tu ?
Dernière édition le 08 Jan 2009 à 20:59
Syltech Message lu Posté le 08 Jan 2009 à 21:25 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266

Citation :

dx,dy : t>1 je suppose (au lieu de t>0) ?


Erf, oui c'est t>1^^


Citation :

En gros, maintenant les variables cx,cy sont inutiles ?


Elles sont bien inutiles ^^

Code :
Pour avoir des noms plus explicites, quels noms mettrait tu ?

Pour des noms plus explicites, c'est pas évident... Je dirais "Position_et_Distance_de_Projection" pour "calcul_vectoriel" et "Distance_de_Projection" pour "distance_vectoriel".

D'ailleurs tu m'a fait remarqué que j'ai pas modifier la fonction "distance_vectoriel" avec la nouvelle méthode...
Techniquement c'est a peu prêt les mêmes fonctions, à part que la fonction "distance_vectoriel" ne renvoie que la distance voici la nouvelle fonction:
Code :
function distance_vectoriel(x as float, y as float, Wall as v2d)
   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^2 + Wall.ly^2)
   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


Voilou! :wink:

Syltech

Edit: erf je viens de voir qu'il faut que je modifie aussi la fonction "isUnder"... je m'y colle ^^
Et donc la fonction "limite" ne servira plus à rien.

Voici la nouvelle fonction "isUnder":
Code :
function isUnder(x as float, y as float, Wall as v2d)
   coef as float : t as float : vdist as float
   coef = (x-Wall.ox)*Wall.lx + (y-Wall.oy)*Wall.ly
   t = coef/(Wall.lx^2 + Wall.ly^2)
   if t>=0 && t<=1
      vDist = ((x-Wall.ox)*Wall.ly - (y-Wall.oy)*Wall.lx) / wall.l
   endif
endfunction vDist
Dernière édition le 08 Jan 2009 à 21:47
Image
Darktib Message lu Posté le 08 Jan 2009 à 22:12 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
OK

Pour l'instant j'ai quasiment fini les structures (joueur, mur, etc...) et je fais des tests de compilation en me battant avec ces foutues références^^
Syltech Message lu Posté le 09 Jan 2009 à 00:26 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Ok bon courage ^^, sinon je pense qu'il va falloir que je prenne du temps pour réfléchir sur les ellipse, car mon petit doigt me dit que j'ai pas bien cherché la dernière fois :)

Syltech
Image
Darktib Message lu Posté le 09 Jan 2009 à 15:06 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Probleme reglé^^

Pour ce qui est de l'architecture, celle que je code est différente : il y a une classe qui contient les murs, et une classe qui définit les entités (joueurs); les collisions sont gérées par les entités, c'est globalement assez simple.
Syltech Message lu Posté le 09 Jan 2009 à 15:34 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Oui, j'imagine en gros comment ça marche. Rha je suis vraiment dégouté de pas pouvoir me plonger a fond dedans... vivement la fin d'étude :tongue: , mais bon des que j'ai du temps je continue à travailler dessus! Et puis ce post est plutôt actif, je voudrais que ça continue comme ça! :grin:

Syltech
Image
Darktib Message lu Posté le 09 Jan 2009 à 16:25 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Ca avance encore, j'ai par contre une question niveau logique : pour les collisions tu utilise les deux murs les plus proches si j'ai bien compris (nwall_a et nwall_b)?
Syltech Message lu Posté le 09 Jan 2009 à 16:45 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Oui, c'est exactement ça!

Je récupère les numéro des 2 murs les plus proches, si le joueur est en collision avec le mur_a, on renvoi au joueur la normal du mur_a.
Puis on test si le mur_b est en collision(seulement si le joueur est en cour de collision avec le mur_a), si c'est le cas, on renvoi au joueur les anciennes positions, ainsi que la normal du mur_b.

C'est principalement ce qui permet au joueur de ne pas trembler dans un coin, sinon dans un coin il testerait un mur puis l'autre, et ça en boucle tant qu'on avance dans un coin.

Syltech
Dernière édition le 09 Jan 2009 à 16:47
Image
bebou007 Message lu Posté le 09 Jan 2009 à 17:54 Bulle
Avatar de bebou007
Explorateur

Messages : 238
GCPoints : 43228
salut se systeme de collision a l'ai pas mal par contre le joueur doit etre un cercle.

j'ai cherche des tutorial sur les collision par polygone par contre je capte rien et j'ai trouver aucun tutorial bien expliquer
Darktib Message lu Posté le 09 Jan 2009 à 20:25 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Le probleme c'est que gérer en cercle et gérer en polygone c'est completement différent : en cercle il suffit d'avoir un centre et son rayon, alors qu'avec les polygones il faut la liste des points du polygone...

Sinon pour l'instant, sans joueur no gestion de collision j'en suis a 3000 fps sur un Pentium D 830, Geforce 6800 LE(256Mo DDR3), 3 Go DDR2, WinXP (et avec DirectX)

edit : encore avancé, j'ai maintenant codé toutes les fonctions qui vont me servir, il ne me reste plus qu'a faires les collisions en tant que tel (Et le fps est descendu a 1600, mais pour l'instant je ne cherche pas a optimiser).

edit2 : optimisations mathématiques :
testA > 0 && testB > 0 est équivalent a testA*testB >0, et ainsi de suite pour les autres tests.
Dernière édition le 09 Jan 2009 à 23:17
bebou007 Message lu Posté le 09 Jan 2009 à 23:53 Bulle
Avatar de bebou007
Explorateur

Messages : 238
GCPoints : 43228
resalut a tous voila j'ai trouver que pour faire des teste sur les collision il manquer un éditeur c'est pour quoi j'ai ajouter un éditeur de mur

voici le code
Code :
set display mode 1024,768,32,1
sync on


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
cx1 as float
cy1 as float
cx2 as float
cy2 as float
EndType

Global nWall_nombre as integer : nWall_nombre=0
Global nWall_max as integer : nWall_max=50
Dim wallmap(nWall_max) as v2d



Global wallx as float
Global wally as float
Global Dist as float

Global nx as float
Global ny as float

Global nWall_A as integer
Global nWall_B as integer

testA as integer
testB as integer

Global taille as integer : taille=30
vitesse as integer : vitesse=8

oldx as float : Joueur_x as float : Joueur_x=125
oldy as float : Joueur_y as float : Joueur_y=0

Wall as v2d

rem pour stocke depart click souris
departx as integer : departx=0
departy as integer : departy=0
finx as integer : finx=0
finy as integer : finy=0








do

   cls

   Gosub Deplacements

   if keystate(18)=1
    if stop=0
     if edit=0
     edit=1
     stop=1
     else
     edit=0
     stop=1
     endif
    endif
   endif


   if keystate(18)=0
   stop=0
   endif



   if edit=1




   if mouseclick()=1
   if stop1=0
   if departx=0
   departx=mousex()
   departy=mousey()
   stop1=1
   endif
   endif
   endif


 if mouseclick()=1
   if stop1=0
   if departx<>0
   finx=mousex()
   finy=mousey()
   stop1=1
   endif
   endif
   endif


   if departx<>0
   line departx,departy,mousex(),mousey()
   endif

   if mouseclick()=0
   if stop1=1
   stop1=0
   endif
   endif


   if mouseclick()=0
   if departx<>0
   if finx<>0
    add_mur(departx,departy,finx,finy)
    departx=0
    departy=0
    finx=0
    finy=0
   endif
   endif
   endif






   endif



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

   calcul_vectoriel(Joueur_x,Joueur_y,wall)
   CoeficientDirecteurInv(Joueur_x,Joueur_y,wallx,wally)

   if abs(dist)<=taille
      hit=1
      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
            calcul_vectoriel(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

   Gosub Affichage

   sync

loop


Deplacements:
   if edit=0
   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
   endif

Return

Affichage:


   if edit=0
   circle Joueur_x,Joueur_y,taille
   line Joueur_x,Joueur_y,Joueur_x+cos(a)*taille,Joueur_y-sin(a)*taille
   endif

   text 0,0,"FPS : "+str$(screen fps())
   text 0,14,"Hit : "+str$(hit)
   text 0,28, str$(edit)

Return








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.cx1 && wally=>Wall.cy1 && wallx<=Wall.cx2 && wally<=Wall.cy2)
         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
   wx = Wall.ox + Wall.lx*coef
   wy = Wall.oy + Wall.ly*coef
   if (wx=>Wall.cx1 && wy=>Wall.cy1 && wx<=Wall.cx2 && wy<=Wall.cy2)
         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)
Distance as float : wall as v2d
rayon_A as float : rayon_B as float
rayon_A=9999 : rayon_B=9999
for i=0 to nWall_nombre-1 : wall=wallmap(i)
   Distance=abs(distance_vectoriel(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)^2+(y2-y1)^2)
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^2+Normaley^2)
   nx=Normalex * MagnitudeInv: ny=Normaley * MagnitudeInv
endfunction

function isUnder(x as float, y as float, Wall as v2d)
   coef as float : wx as float : wy as float : vDist as integer
   coef = ((x-Wall.ox)*Wall.lx + (y-Wall.oy)*Wall.ly) / Wall.l2
   wx = Wall.ox + Wall.lx*coef
   wy = Wall.oy + Wall.ly*coef
   if (wx=>Wall.cx1 && wy=>Wall.cy1 && wx<=Wall.cx2 && wy<=Wall.cy2)
      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

function limite(nWall)
if wallmap(nWall).ox<wallmap(nWall).dx
wallmap(nWall).cx1=wallmap(nWall).ox
wallmap(nWall).cx2=wallmap(nWall).dx
else
wallmap(nWall).cx1=wallmap(nWall).dx
wallmap(nWall).cx2=wallmap(nWall).ox
endif
if wallmap(nWall).oy<wallmap(nWall).dy
wallmap(nWall).cy1=wallmap(nWall).oy
wallmap(nWall).cy2=wallmap(nWall).dy
else
wallmap(nWall).cy1=wallmap(nWall).dy
wallmap(nWall).cy2=wallmap(nWall).oy
endif
endfunction

function add_mur(posx1,posy1,posx2,posy2)

for x=0 to nWall_max-1

if wallmap(x).l=0
exit
endif
next x

wallmap(x).ox=posx1
wallmap(x).oy=posy1
wallmap(x).dx=posx2
wallmap(x).dy=posy2
wallmap(x).lx=wallmap(x).dx-wallmap(x).ox
wallmap(x).ly=wallmap(x).dy-wallmap(x).oy
wallmap(x).l2=wallmap(x).lx^2+wallmap(x).ly^2
wallmap(x).l=sqrt(wallmap(x).l2)
limite(x)

nWall_nombre=nWall_nombre+1

if nWall_nombre>nWall_max
nWall_nombre=nWall_max
endif

endfunction x


appuyer sur "e" pour entre dans l'éditeur un premier clic pour le premier point et encore un clic pour le deuxième point puis "e" pour sortir dans le code nWall_max pour le nombre max que l'on peut faire de mur

j'ai aussi remarquer que une vitesse de 50 le joueur passe a travers le mur


Dernière édition le 10 Jan 2009 à 00:03
Darktib Message lu Posté le 10 Jan 2009 à 00:17 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Sympa l'éditeur, vraiment tres pratique! Par contre j'ai remarqué qu'on ne peut pas avancer quand ils n'y a pas de murs...

Sinon pour l'instant le code C++ est 100% fonctionnel, j'ai juste viré une grosse partie des tests de collisions (testA et testB, ce qui fait qu'il oscille maintenant, mais je pense que ca sera bientot reglé. J'avais des problemes au début, mais qui étaient dus au fait que je n'utilise que des distances au carré.
bebou007 Message lu Posté le 10 Jan 2009 à 00:46 Bulle
Avatar de bebou007
Explorateur

Messages : 238
GCPoints : 43228
oui on peut pas avancer sans mur je sais pas de ou sa vient a parament comme il y a pas de mur le plus proche renvoyer et sa doit planter de la car il y a hit sur 1

serait il possible d'avoir le code c++ ou une lib pour tester en c++

Dernière édition le 10 Jan 2009 à 00:48
Darktib Message lu Posté le 10 Jan 2009 à 11:55 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
No prob'

Par contre je le posterai dans la section C++
bebou007 Message lu Posté le 10 Jan 2009 à 12:43 Bulle
Avatar de bebou007
Explorateur

Messages : 238
GCPoints : 43228
ok merci par contre j'ai rencontre certain bug sur les collision (tremblement,ne glisse pas a certain endroits) par example


Image
imagik.fr

ici je bloque


Image
imagik.fr


et ici je tremble
Darktib Message lu Posté le 10 Jan 2009 à 12:49 Bulle
Avatar de Darktib
Membre Ultime

Messages : 4017
GCPoints : 347288
Pour les tremblements, c'est du au fait qu'on ne vérifie qu'un mur. C'est bizarre, vu qu'en dbp ce code vérifie deux murs...

Pour l'autre, que veut dire le 'il bloque' : il s'arrete la, ou il se bloque indéfiniment a cet endroit (impossible de le faire bouger ailleurs)?
bebou007 Message lu Posté le 10 Jan 2009 à 13:00 Bulle
Avatar de bebou007
Explorateur

Messages : 238
GCPoints : 43228
ben le tremblement non il vérifie bien les 2 mur pour le bloquage en fait on peut sortir mais il glisse pas contre le petit mur qui dépasse

Syltech Message lu Posté le 11 Jan 2009 à 21:23 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Hello! Sympa de voir que ça a avancé! :)
Deja, Bravo Darktib pour l'optimisation testA*testB>0 et sympa ce petit éditeur Bebou007!

Pour la vitesse à 50 qui fait traversé les murs, c'est normal, c'est que si la vitesse est plus grande que la taille du joueur ça traverse et c'est tout à fait logique, imagine le cercle avancer de 50 alors que ça taille n'est que de 30, le test de collision ce fait de l'autre coté du mur.
Il y a des façons pour remédié à ce problème, Graphiboc en a parlé d'ailleurs, de faire plusieurs test de collision entre une position initial et la prochaine position du joueur, évidement ça demande plus de calculs...

Pour le tremblement que tu as découvert Bebou007, Bravo c'est un nouveau bug! Ça me fait donc un cas particulier supplémentaire à corriger! :tongue:

Le truc dans ce cas particulier, c'est que si le morceau de mur qui dépasse est inférieur au rayon du cercle, alors il y a tremblement. Je vais m'amuser à corrigé celui la je pense lol, m'enfin quand y faut y faut ^^

Syltech :smile:
Image
Syltech Message lu Posté le 11 Fév 2009 à 20:08 Bulle
Avatar de Syltech
Membre Confirmé

Messages : 282
GCPoints : 71266
Comme je l'ai expliqué dans mon sujet sur la collision cercle contre cercle :


Citation :

Hum, je viens de remarqué que les formules du genre "(x2-x1)^2+(y2-y1)^2+(z2-z1)^2" était très gourmande niveau Fps à cause du "^2".
J'ai remarqué ça après avoir fait quelques optimisations sur mon moteur de collision 3D.
Avec les "^2" de mes fonctions de calculs de distance, j'étais à 200 Fps, et après avoir changer mes formules par "(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1)", je me suis retrouvé à... 400 Fps !



Je vous conseille de modifier les fonctions qui utilisent le symbole "^" pour la puissance.
Voici les fonctions corrigées :

Code :
function calcul_vectoriel(x as float, y as float, Wall as v2d)
   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


Code :
function distance_vectoriel(x as float, y as float, Wall as v2d)
   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


Code :
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


Code :
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


Code :
function isUnder(x as float, y as float, Wall as v2d)
   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


Voila ! Je pense avoir fait le tour !

Syltech

Edit : J'ai mis mon tout premier message à jour pour les personnes qui découvriraient mon code, c'est propre, c'est clair et mon code est à jour !
Dernière édition le 12 Fév 2009 à 10:41
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.0529 secondes