Code : Tout sélectionner
;Comtois 02/12/04
;Mise à jour pour PB4.10 le 30/06/07
;Tut sur les Collisions Sphériques
;l'exemple est en 2D , mais le principe est le même pour la 3D.
;la différence réside dans le calcul de la distance
;en 2D on a Distance=Sqr((x1-x2)²+(y1-y2)²)
;en 3D on a Distance=Sqr((x1-x2)²+(y1-y2)²+(z1-z2)²)
;Avec x1,y1,z1 les coordonnées de la sphere 1
;et x2,y2,z2 les coordonnées de la sphere 2
;Pour détecter une collision entre deux entitys 3D , il suffit de définir une sphère qui enveloppe chacune des entitys
;et de tester la distance entre les entitys 3D. Bien sûr cette méthode a ses limites .
;Il est très rare d'avoir des entitys de forme sphérique :)
;l'avantage c'est que cette méthode est simple à mettre en oeuvre et elle est rapide (elle nécessite peu de calculs).
;Pour obtenir plus de précision Pour tester des collisions entre entitys ,
;il est possible de définir plusieurs petites sphères qui envelopperont au mieux le volume de chaque entity .
; Par exemple une sphere pour la tête d'un personnage,
; une autre sphere pour le tronc du personnage ,
;une troisième pour les jambes , etc
;en décomposant avec 3 ou 4 spheres il devient possible de détecter quelle partie du corps est touchée .
;-Declare
Declare Erreur(Message$)
;-Initialisation
#ScreenWidth = 800 : #ScreenHeight = 600 : #ScreenDepth = 32
If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse()=0
Erreur("Impossible d'initialiser DirectX 7 Ou plus")
ElseIf OpenScreen( #ScreenWidth , #ScreenHeight , #ScreenDepth , "" ) = 0
Erreur("Impossible d'ouvrir l'écran ")
EndIf
Structure Sphere
x.l
y.l
rayon.l
EndStructure
Global Sprite1.Sphere
Global Sprite2.Sphere
;/Sprite 1
Sprite1\x=400
Sprite1\y=300
Sprite1\rayon=60
CreateSprite(1,128,128)
If StartDrawing(SpriteOutput(1))
Circle(SpriteWidth(1)/2,SpriteHeight(1)/2,Sprite1\rayon,RGB(185,155,255))
StopDrawing()
EndIf
;/Sprite 2
Sprite2\x=0 ; utilise les coordonnées de la souris
Sprite2\y=0 ; utilise les coordonnées de la souris
Sprite2\rayon=40
CreateSprite(2,82,82)
If StartDrawing(SpriteOutput(2))
Circle(SpriteWidth(2)/2,SpriteHeight(2)/2,Sprite2\rayon,RGB(55,55,255))
StopDrawing()
EndIf
;-Procedures
Procedure Erreur(Message$)
MessageRequester( "Erreur" , Message$ , 0 )
End
EndProcedure
Procedure.f CalculDistance(x1,y1,x2,y2)
;en 2D Distance=Sqr((x1-x2)²+(y1-y2)²)
;en 3D Distance=Sqr((x1-x2)²+(y1-y2)²+(z1-z2)²)
Distance.f=Sqr((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
ProcedureReturn Distance
EndProcedure
Procedure AfficheDistance(x1,y1,x2,y2)
If StartDrawing(ScreenOutput())
;Affiche la distance entre la sphère 1 et la sphère 2
R1=Sprite1\rayon
R2=Sprite2\rayon
LineXY(x1,y1,x2,y2,RGB(255,0,0))
x=(x1+x2)/2
y=(y1+y2)/2
FrontColor(RGB(0,155,0))
BackColor(RGB(255,255,0))
Distance.f=CalculDistance(x1,y1,x2,y2)
DrawText(x,y,"d="+StrF(Distance,1))
;/Affiche le rayon 1
DrawText(x1,y1,"R1="+Str(R1))
;/Affiche le rayon 2
DrawText(x2,y2,"R2="+Str(R2))
;/Commentaire et collision
FrontColor(#White)
BackColor(#Black)
DrawText(0,0,"Soit 'R1' le rayon de la sphère 1 ,'R2' le rayon de la sphère 2 et 'd' la distance entre la sphère 1 et 2")
DrawText(0,20,"Il y a collision entre les deux sphères si la Distance 'd' est inférieure à la somme des deux rayons > 'd'<'R1+R2'")
If Distance<R1+R2
t$=" , Il y a collision"
Else
t$=" , il n'y a pas de collision"
EndIf
DrawText(0,40,"R1 + R2 = "+Str(R1)+" + "+Str(R2)+" = "+Str(R1+R2)+ " ..... et d = "+StrF(Distance,1))
;/Collision?
If Distance<R1+R2
FrontColor(#Yellow)
BackColor(#Red)
t$="Il y a collision !"
Else
FrontColor(#Yellow)
BackColor(#Blue)
t$="Il n'y a pas de collision"
EndIf
DrawText(400-TextWidth(t$)/2,580,t$)
StopDrawing()
EndIf
EndProcedure
;- Boucle principale
Repeat
ClearScreen(0)
ExamineKeyboard()
ExamineMouse()
;/Affiche le sprite 1
CentreX1=Sprite1\x+SpriteWidth(1)/2
Centrey1=Sprite1\y+SpriteHeight(1)/2
DisplaySprite(1,Sprite1\x,Sprite1\y)
;/Affiche le sprite 2 à la position de la souris
Sprite2\x=MouseX()
Sprite2\y=MouseY()
CentreX2=Sprite2\x+SpriteWidth(2)/2
Centrey2=Sprite2\y+SpriteHeight(2)/2
DisplayTransparentSprite(2,Sprite2\x,Sprite2\y)
;/
;Il y a collision si la distance entre la sphere de rayon R1 et la sphere de rayon R2 est < R1+R2
AfficheDistance(CentreX1,Centrey1,CentreX2,Centrey2)
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)