Je pense avoir choisi la méthode la moins coûteuse. J'optimiserai peut-être encore un peu la chose.
Les arguments sont logiquement les coordonnées du centre du cercle et son rayon, ainsi que les coordonnées de la boite. Attention, ici la boite est définie en coordonnées des coins opposés, et non pas par les coordonnées d'un coin et la taille (contrairement à la commande Box())
Edité : je remets le code complet avec le prog principal de test, ce qui facilitera la compréhension des choses.
Code : Tout sélectionner
Procedure Triangle(tx1.f, ty1.f, tx2.f, ty2.f, tx3.f, ty3.f, Color.l, Mode.l) ; Dessin d'un triangle avec attribut de couleur et mode de tracé (4 = vide, 0 = plein)
LineXY(tx1, ty1, tx2, ty2, Color)
LineXY(tx2, ty2, tx3, ty3, Color)
LineXY(tx3, ty3, tx1, ty1, Color)
If Mode <> 4
FillArea((tx1 + tx2 + tx3) / 3, (ty1 + ty2 + ty3) / 3, Color, Color)
EndIf
EndProcedure
Procedure Box_And_Box_Collision(b1x1.f, b1y1.f, b1x2.f, b1y2.f, b2x1.f, b2y1.f, b2x2.f, b2y2.f)
If b1x1 > b1x2 ; on redresse les enveloppes
xz.f = b1x1
b1x1 = b1x2
b1x2 = xz
EndIf
If b2x1 > b2x2
xz.f = b2x1
b2x1 = b2x2
b2x2 = xz
EndIf
If b1y1 > b1y2
yz.f = b1y1
b1y1 = b1y2
b1y2 = yz
EndIf
If b2y1 > b2y2
yz.f = b2y1
b2y1 = b2y2
b2y2 = yz
EndIf
dx1.f = b1x2 - b1x1 ; on prend les dimensions de chaque boite
dy1.f = b1y2 - b1y1
dx2.f = b2x2 - b2x1
dy2.f = b2y2 - b2y1
bbx1.f = b1x1 ; on calcule l'enveloppe dans laquelle s'inscrivent les deux boites
If bbx1 > b2x1
bbx1 = b2x1
EndIf
bbx2.f = b1x2
If bbx2 < b2x2
bbx2 = b2x2
EndIf
bby1.f = b1y1
If bby1 > b2y1
bby1 = b2y1
EndIf
bby2.f = b1y2
If bby2 < b2y2
bby2 = b2y2
EndIf
dbx.f = bbx2 - bbx1 ; on prend les dimensions de l'enveloppe globale
dby.f = bby2 - bby1
If dbx <= dx1 + dx2 And dby <= dy1 + dy2 ; Si la boite globale est plus petite que la plus petite enveloppe des deux boites disjointes, c'est qu'elles sont en contact
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
Procedure Box_And_Triangle_Collision(bx1.f, by1.f, bx2.f, by2.f, tx1.f, ty1.f, tx2.f, ty2.f, tx3.f, ty3.f)
envx1.f = tx1 ; Pour l'instant je calcule le rectangle dans lequel le triangle est inscrit
If envx1 > tx2
envx1 = tx2
EndIf
If envx1 > tx3
envx1 = tx3
EndIf
envx2.f = tx1
If envx2 < tx2
envx2 = tx2
EndIf
If envx2 < tx3
envx2 = tx3
EndIf
envy1.f = ty1
If envy1 > ty2
envy1 = ty2
EndIf
If envy1 > ty3
envy1 = ty3
EndIf
envy2.f = ty1
If envy2 < ty2
envy2 = ty2
EndIf
If envy2 < ty3
envy2 = ty3
EndIf
Box(envx1, envy1, envx2 - envx1, envy2 - envy1, #Green) ; je le dessine pour info
ProcedureReturn Box_And_Box_Collision(bx1, by1, bx2, by2, envx1, envy1, envx2, envy2)
EndProcedure
Procedure Triangle_And_Triangle_Collision(t1x1.f, t1y1.f, t1x2.f, t1y2.f, t1x3.f, t1y3.f, t2x1.f, t2y1.f, t2x2.f, t2y2.f, t2x3.f, t2y3.f)
env1x1.f = t1x1 ; Pour l'instant je calcule le rectangle dans lequel le triangle est inscrit
If env1x1 > t1x2
env1x1 = t1x2
EndIf
If env1x1 > t1x3
env1x1 = t1x3
EndIf
env1x2.f = t1x1
If env1x2 < t1x2
env1x2 = t1x2
EndIf
If env1x2 < t1x3
env1x2 = t1x3
EndIf
env1y1.f = t1y1
If env1y1 > t1y2
env1y1 = t1y2
EndIf
If env1y1 > t1y3
env1y1 = t1y3
EndIf
env1y2.f = t1y1
If env1y2 < t1y2
env1y2 = t1y2
EndIf
If env1y2 < t1y3
env1y2 = t1y3
EndIf
env2x1.f = t2x1
If env2x1 > t2x2
env2x1 = t2x2
EndIf
If env2x1 > t2x3
env2x1 = t2x3
EndIf
env2x2.f = t2x1
If env2x2 < t2x2
env2x2 = t2x2
EndIf
If env2x2 < t2x3
env2x2 = t2x3
EndIf
env2y1.f = t2y1
If env2y1 > t2y2
env2y1 = t2y2
EndIf
If env2y1 > t2y3
env2y1 = t2y3
EndIf
env2y2.f = t2y1
If env2y2 < t2y2
env2y2 = t2y2
EndIf
If env2y2 < t2y3
env2y2 = t2y3
EndIf
Box(env1x1, env1y1, env1x2 - env1x1, env1y2 - env1y1, #Green) ; je le dessine pour info
Box(env2x1, env2y1, env2x2 - env2x1, env2y2 - env2y1, #Green)
ProcedureReturn Box_And_Box_Collision(env1x1, env1y1, env1x2, env1y2, env2x1, env2y1, env2x2, env2y2)
EndProcedure
Procedure Circle_And_Circle_Collision(cx1.f, cy1.f, radius1.f, cx2.f, cy2.f, radius2.f)
dx.f = cx2 - cx1 ; On calcule la distance entre le centre du cercle 1 et le centre du cercle 2
dy.f = cy2 - cy1
min_distance.f = radius1 + radius2
min_distance2.f = min_distance * min_distance
If dx * dx + dy * dy <= min_distance2 ; si cette distance est inférieure à la somme des rayons, il y a collision
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure Circle_And_Box_Collision(cx.f, cy.f, radius.f, x1.f, y1.f, x2.f, y2.f)
If x1 > x2 ; Redressement du rectangle de référence si nécessaire
xz.f = x1
x1 = x2
x2 = xz
EndIf
If y1 > y2
yz.f = y1
y1 = y2
y2 = yz
EndIf
If cx + radius => x1 And cy => y1 And cy <= y2 And cx + radius <= x2 ; Test pour savoir si le cercle touche le bord gauche de la boite
ProcedureReturn #True
EndIf
If cx - radius <= x2 And cy => y1 And cy <= y2 And cx - radius => x1 ; Test pour savoir si le cercle touche le bord droit de la boite
ProcedureReturn #True
EndIf
If cy + radius => y1 And cx => x1 And cx <= x2 And cy + radius <= y2 ; Test pour savoir si le cercle touche le bord bas de la boite
ProcedureReturn #True
EndIf
If cy - radius <= y2 And cx => x1 And cx <= x2 And cy - radius => y1 ; Test pour savoir si le cercle touche le bord haut de la boite
ProcedureReturn #True
EndIf
dx1.f = cx - x1 ; Si le cercle ne touche pas par un bord, on vérifie qu'il n'est pas en contact par un coin
dy1.f = cy - y1
dx2.f = cx - x2
dy2.f = cy - y2
radius2.f = radius * radius
If dx1 * dx1 + dy1 * dy1 <= radius2 ; Test pour le coin x1, y1
ProcedureReturn #True
EndIf
If dx1 * dx1 + dy2 * dy2 <= radius2 ; Test pour le coin x1, y2
ProcedureReturn #True
EndIf
If dx2 * dx2 + dy1 * dy1 <= radius2 ; Test pour le coin x2, y1
ProcedureReturn #True
EndIf
If dx2 * dx2 + dy2 * dy2 <= radius2 ; Test pour le coin x2, y2
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
Procedure Circle_And_Triangle_Collision(cx.f, cy.f, radius.f, tx1.f, ty1.f, tx2.f, ty2.f, tx3.f, ty3.f)
envx1.f = tx1 ; Pour l'instant je calcule le rectangle dans lequel le triangle est inscrit
If envx1 > tx2
envx1 = tx2
EndIf
If envx1 > tx3
envx1 = tx3
EndIf
envx2.f = tx1
If envx2 < tx2
envx2 = tx2
EndIf
If envx2 < tx3
envx2 = tx3
EndIf
envy1.f = ty1
If envy1 > ty2
envy1 = ty2
EndIf
If envy1 > ty3
envy1 = ty3
EndIf
envy2.f = ty1
If envy2 < ty2
envy2 = ty2
EndIf
If envy2 < ty3
envy2 = ty3
EndIf
Box(envx1, envy1, envx2 - envx1, envy2 - envy1, #Green) ; je le dessine pour info
ProcedureReturn Circle_And_Box_Collision(cx, cy, radius, envx1, envy1, envx2, envy2) ; et j'utilise le test cercle / boite. On verra plus tard pour faire mieux
EndProcedure
;
;
;
ScreenWidth = GetSystemMetrics_(#SM_CXSCREEN)
ScreenHeight = GetSystemMetrics_(#SM_CYSCREEN)
ScreenDepth = 32
cx1 = 3 * ScreenWidth / 4
cy1 = ScreenHeight / 2
radius1 = 150
radius2 = 100
bx1 = 200
by1 = 300
bx2 = 350
by2 = 400
tx1 = ScreenWidth / 4
ty1 = 3 * ScreenHeight / 4- 30
tx2 = ScreenWidth / 2
ty2 = 3 * ScreenHeight / 4
tx3 = 3 * ScreenWidth / 8
ty3 = ScreenHeight / 2
Statistics = #True
#Circle = 0
#Triangle = 1
#Box = 2
Mode = #Circle
If InitSprite() And InitMouse() And InitKeyboard()
If OpenScreen(ScreenWidth, ScreenHeight, ScreenDepth, "")
Quit = #False
Repeat
FlipBuffers(0)
ClearScreen(0, 0, 0)
ExamineKeyboard()
ExamineMouse()
If KeyboardPushed(#PB_Key_Escape) : Quit = #True : EndIf
If KeyboardPushed(#PB_Key_F1) : Repeat : ExamineKeyboard() : Until KeyboardReleased(#PB_Key_F1) : Statistics = 1 - Statistics : EndIf
If KeyboardPushed(#PB_Key_F2) : Repeat : ExamineKeyboard() : Until KeyboardReleased(#PB_Key_F2) : Detect_Collisions = 1 - Detect_Collisions : EndIf
If KeyboardPushed(#PB_Key_Left) : Repeat : ExamineKeyboard() : Until KeyboardReleased(#PB_Key_Left) : Mode - 1 : If Mode < #Circle : Mode = #Circle : EndIf : EndIf
If KeyboardPushed(#PB_Key_Right) : Repeat : ExamineKeyboard() : Until KeyboardReleased(#PB_Key_Right) : Mode + 1 : If Mode > #Box : Mode = #Box : EndIf : EndIf
StartDrawing(ScreenOutput())
DrawingMode(4)
Color = #White
Select Mode
Case #Circle
cx2 = MouseX()
cy2 = MouseY()
Circle(cx2, cy2, radius2, #White)
If Detect_Collisions
If Circle_And_Circle_Collision(cx2, cy2, radius2, cx1, cy1, radius1)
Circle(cx1, cy1, radius1, #Red)
Else
Circle(cx1, cy1, radius1, #White)
EndIf
If Circle_And_Box_Collision(cx2, cy2, radius2, bx1, by1, bx2, by2)
Box(bx1, by1, bx2 - bx1, by2 - by1, #Red)
Else
Box(bx1, by1, bx2 - bx1, by2 - by1, #White)
EndIf
If Circle_And_Triangle_Collision(cx2, cy2, radius2, tx1, ty1, tx2, ty2, tx3, ty3)
Triangle(tx1, ty1, tx2, ty2, tx3, ty3, #Red, 4)
Else
Triangle(tx1, ty1, tx2, ty2, tx3, ty3, #White, 4)
EndIf
Else
Circle(cx1, cy1, radius1, #White)
Box(bx1, by1, bx2 - bx1, by2 - by1, #White)
Triangle(tx1, ty1, tx2, ty2, tx3, ty3, #White, 4)
EndIf
Case #Triangle
t2x1 = MouseX()
t2y1 = MouseY()
t2x2 = t2x1 - 110
t2y2 = t2y1 + 70
t2x3 = t2x1 - 90
t2y3 = t2y1 - 80
Triangle(t2x1, t2y1, t2x2, t2y2, t2x3, t2y3, #White, 4)
If Detect_Collisions
If Triangle_And_Triangle_Collision(tx1, ty1, tx2, ty2, tx3, ty3, t2x1, t2y1, t2x2, t2y2, t2x3, t2y3)
Triangle(tx1, ty1, tx2, ty2, tx3, ty3, #Red, 4)
Else
Triangle(tx1, ty1, tx2, ty2, tx3, ty3, #White, 4)
EndIf
If Circle_And_Triangle_Collision(cx1, cy1, radius1, t2x1, t2y1, t2x2, t2y2, t2x3, t2y3)
Circle(cx1, cy1, radius1, #Red)
Else
Circle(cx1, cy1, radius1, #White)
EndIf
If Box_And_Triangle_Collision(bx1, by1, bx2, by2, t2x1, t2y1, t2x2, t2y2, t2x3, t2y3)
Box(bx1, by1, bx2 - bx1, by2 - by1, #Red)
Else
Box(bx1, by1, bx2 - bx1, by2 - by1, #White)
EndIf
Else
Circle(cx1, cy1, radius1, #White)
Box(bx1, by1, bx2 - bx1, by2 - by1, #White)
Triangle(tx1, ty1, tx2, ty2, tx3, ty3, #White, 4)
EndIf
Case #Box
b2x1 = MouseX()
b2y1 = MouseY()
b2x2 = b2x1 + 100
b2y2 = b2y1 + 150
Box(b2x1, b2y1, b2x2 - b2x1, b2y2 - b2y1, #White)
If Detect_Collisions
If Box_And_Box_Collision(bx1, by1, bx2, by2, b2x1, b2y1, b2x2, b2y2)
Box(bx1, by1, bx2 - bx1, by2 - by1, #Red)
Else
Box(bx1, by1, bx2 - bx1, by2 - by1, #White)
EndIf
If Circle_And_Box_Collision(cx1, cy1, radius1, b2x1, b2y1, b2x2, b2y2)
Circle(cx1, cy1, radius1, #Red)
Else
Circle(cx1, cy1, radius1, #White)
EndIf
If Box_And_Triangle_Collision(b2x1, b2y1, b2x2, b2y2, tx1, ty1, tx2, ty2, tx3, ty3)
Triangle(tx1, ty1, tx2, ty2, tx3, ty3, #Red, 4)
Else
Triangle(tx1, ty1, tx2, ty2, tx3, ty3, #White, 4)
EndIf
Else
Circle(cx1, cy1, radius1, #White)
Box(bx1, by1, bx2 - bx1, by2 - by1, #White)
Triangle(tx1, ty1, tx2, ty2, tx3, ty3, #White, 4)
EndIf
EndSelect
If Statistics
DrawingMode(1)
BackColor(0, 0, 0)
FrontColor(255, 255, 255)
Locate(10, 10)
DrawText("FPS : " + Str(FPS))
Locate(10, 30)
DrawText("Aide / Statistiques (F1)")
Locate(10, 50)
Select Detect_Collisions
Case #False
sDetect_Collisions.s = "False"
Case #True
sDetect_Collisions.s = "True"
EndSelect
DrawText("Detect collisions (F2) : " + sDetect_Collisions)
Locate(10, 70)
Select Mode
Case #Circle
sMode.s = "Circle"
Case #Triangle
sMode.s = "Triangle"
Case #Box
sMode.s = "Box"
EndSelect
DrawText("Mode (Left / Right) : " + sMode)
EndIf
NFrames + 1
If ElapsedMilliseconds() - tz => 1000
FPS = NFrames
NFrames = 0
tz = ElapsedMilliseconds()
EndIf
StopDrawing()
Until Quit
CloseScreen()
EndIf
EndIf
CallDebugger
End