GameCorp - Index des forumsGame MakingProgrammationDark Basic - DarkGDK[DarkBasic] Moteur de collision 2D
[DarkBasic] Moteur de collision 2D
| Syltech |
Posté le 12 Déc 2008 à 21:41
|
|
![]() 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
endfunctionJ’espère que vous comprendrez comment ça fonctionne ! Bon courage ! Syltech
Dernière édition le 12 Fév 2009 à 11:32
![]() |
|
| Darktib |
Posté le 12 Déc 2008 à 23:36
|
|
![]() 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 |
|
| Mod |
Posté le 13 Déc 2008 à 10:53
|
|
![]() Messages : 4954 GCPoints : 2100823 |
Excellent, ça marche parfaitement bien Merci pour ce code ;).
Dernière édition le 13 Déc 2008 à 10:54
|
|
| Syltech |
Posté le 13 Déc 2008 à 12:52
|
|
![]() 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 ![]() |
|
| Mod |
Posté le 13 Déc 2008 à 15:04
|
|
![]() 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 |
|
| Syltech |
Posté le 13 Déc 2008 à 18:05
|
|
![]() Messages : 282 GCPoints : 71266 |
Hum si je trouve le temps je ferais ça
Dernière édition le 13 Déc 2008 à 18:06
![]() |
|
| Syltech |
Posté le 14 Déc 2008 à 09:50
|
|
![]() 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 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
endifSinon 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
![]() |
|
| Darktib |
Posté le 14 Déc 2008 à 11:57
|
|
![]() 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 |
Posté le 14 Déc 2008 à 12:18
|
|
![]() 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 La formule ne sera jamais modifié dans mon tutoriel donc... Syltech ![]() |
|
| Darktib |
Posté le 14 Déc 2008 à 12:22
|
|
![]() 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 |
Posté le 14 Déc 2008 à 12:32
|
|
![]() 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 :
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? ![]() |
|
| Darktib |
Posté le 14 Déc 2008 à 12:48
|
|
![]() 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
endfunctionedit : désolé pour déformer le forum^^
Dernière édition le 14 Déc 2008 à 12:49
|
|
| Syltech |
Posté le 14 Déc 2008 à 12:57
|
|
![]() 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 ![]() |
|
| Darktib |
Posté le 14 Déc 2008 à 13:04
|
|
![]() Messages : 4017 GCPoints : 347288 |
En effet ca marche pour le mur 6 Sinon oui la cas particulier c'est bien ce que tu as dit, maintenat reste a le gérer^^ |
|
| Mod |
Posté le 14 Déc 2008 à 13:19
|
|
![]() 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 |
Posté le 14 Déc 2008 à 13:24
|
|
![]() 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 |
Posté le 14 Déc 2008 à 13:54
|
|
![]() Messages : 282 GCPoints : 71266 |
Citation :
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
endifEnfaite 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
Dernière édition le 14 Déc 2008 à 14:01
![]() |
|
| Syltech |
Posté le 14 Déc 2008 à 17:30
|
|
![]() 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
![]() |
|
| Darktib |
Posté le 14 Déc 2008 à 20:22
|
|
![]() Messages : 4017 GCPoints : 347288 |
Ca marche nickel maintenant. Reste plus que les optimisations^^ |
|
| Syltech |
Posté le 14 Déc 2008 à 20:39
|
|
![]() Messages : 282 GCPoints : 71266 |
Ouaip, je vais voir ce que je peux faire 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 Syltech ![]() |
|
GameCorp - Index des forumsGame MakingProgrammationDark Basic - DarkGDK[DarkBasic] Moteur de collision 2D
Répondre





