Seitengenaue Kollisionsabfrage
Verfasst: 18.08.2009 12:25
Hi,
habe mal in den tiefen der Hyperlinks gestöbert und endlich eine
Lösung für Kollisionen zwischen zwei Rechtecken gefunden. Oft habe ich hier
schon mal ein Thread eröffnet, um zu erfahren wie man dieses Problem
löst. Doch leider konnten mir auch nicht einmal die guten Makros von
Kaeru weiter helfen.
Nun zum eigentlichen Code:
Diese Funktion prüft, ob es überhaupt zu einer Kollision zwischen zwei
Rechtecken gekommen ist. Danach wird überprüft, welche Seite des
zweiten Rechteckes getroffen wurde.
Als ich diese Funktion endlich gefunden habe, bin ich sofort an einen kleinen
Jump&Run-Prototyp ran gegangen:
Tata... Die Kollisionsabfrage funktioniert perfekt. Ich denke jeder würde
gerne ein richtiges BreakOut- oder Jump&Run-Game machen. Deswegen
habe ich dies hier gepostet.
Gruß Josef
habe mal in den tiefen der Hyperlinks gestöbert und endlich eine
Lösung für Kollisionen zwischen zwei Rechtecken gefunden. Oft habe ich hier
schon mal ein Thread eröffnet, um zu erfahren wie man dieses Problem
löst. Doch leider konnten mir auch nicht einmal die guten Makros von
Kaeru weiter helfen.

Nun zum eigentlichen Code:
Code: Alles auswählen
Enumeration 1
#Collision_Left
#Collision_Right
#Collision_Top
#Collision_Bottom
EndEnumeration
Procedure.i RectangleCollision(X1.f, Y1.f, Width1.f, Height1.f, X2.f, Y2.f, Width2.f, Height2.f)
Protected A.f, B.f
A = (X2 + Width2/2) - (X1 + Width1/2)
B = (Y2 + Height2/2) - (Y1 + Height1/2)
If Abs(A) - (Width1/2) - (Width2/2) <= 0 And Abs(B) - (Height1/2) - (Height2/2) <= 0
If A => 0
If B => 0
If Abs(A) - (Width1/2) - (Width2/2) > Abs(B) - (Height1/2) - (Height2/2)
ProcedureReturn #Collision_Left
Else
ProcedureReturn #Collision_Top
EndIf
Else
If Abs(A) - (Width1/2) - (Width2/2) > Abs(B) - (Height1/2) - (Height2/2)
ProcedureReturn #Collision_Left
Else
ProcedureReturn #Collision_Bottom
EndIf
EndIf
Else
If B => 0
If Abs(A) - (Width1/2) - (Width2/2) > Abs(B) - (Height1/2) - (Height2/2)
ProcedureReturn #Collision_Right
Else
ProcedureReturn #Collision_Top
EndIf
Else
If Abs(A) - (Width1/2) - (Width2/2) > Abs(B) - (Height1/2) - (Height2/2)
ProcedureReturn #Collision_Right
Else
ProcedureReturn #Collision_Bottom
EndIf
EndIf
EndIf
Else
ProcedureReturn #Null
EndIf
EndProcedure
Rechtecken gekommen ist. Danach wird überprüft, welche Seite des
zweiten Rechteckes getroffen wurde.
Als ich diese Funktion endlich gefunden habe, bin ich sofort an einen kleinen
Jump&Run-Prototyp ran gegangen:
Code: Alles auswählen
Enumeration 1
#Collision_Left
#Collision_Right
#Collision_Top
#Collision_Bottom
EndEnumeration
; Die göttliche Funktion:
Procedure.i RectangleCollision(X1.f, Y1.f, Width1.f, Height1.f, X2.f, Y2.f, Width2.f, Height2.f)
Protected A.f, B.f
A = (X2 + Width2/2) - (X1 + Width1/2)
B = (Y2 + Height2/2) - (Y1 + Height1/2)
If Abs(A) - (Width1/2) - (Width2/2) <= 0 And Abs(B) - (Height1/2) - (Height2/2) <= 0
If A => 0
If B => 0
If Abs(A) - (Width1/2) - (Width2/2) > Abs(B) - (Height1/2) - (Height2/2)
ProcedureReturn #Collision_Left
Else
ProcedureReturn #Collision_Top
EndIf
Else
If Abs(A) - (Width1/2) - (Width2/2) > Abs(B) - (Height1/2) - (Height2/2)
ProcedureReturn #Collision_Left
Else
ProcedureReturn #Collision_Bottom
EndIf
EndIf
Else
If B => 0
If Abs(A) - (Width1/2) - (Width2/2) > Abs(B) - (Height1/2) - (Height2/2)
ProcedureReturn #Collision_Right
Else
ProcedureReturn #Collision_Top
EndIf
Else
If Abs(A) - (Width1/2) - (Width2/2) > Abs(B) - (Height1/2) - (Height2/2)
ProcedureReturn #Collision_Right
Else
ProcedureReturn #Collision_Bottom
EndIf
EndIf
EndIf
Else
ProcedureReturn #Null
EndIf
EndProcedure
#ScreenWidth = 1024
#ScreenHeight = 768
#ScreenDepth = 32
Structure Player
X.f
Y.f
Size.i
MoveX.f
MoveY.f
EndStructure
Structure Wall
X.f
Y.f
Width.i
Height.i
EndStructure
Global Player.Player
Global NewList Wall.Wall()
Define Side.i
Procedure.i AddWall(X.i, Y.i, Width.i, Height.i)
AddElement(Wall())
Wall()\X = X
Wall()\Y = Y
Wall()\Width = Width
Wall()\Height = Height
ProcedureReturn @Wall()
EndProcedure
If Not (InitSprite() And InitKeyboard() And InitMouse())
MessageRequester("Error", "InitSprite(), InitKeyboard(), InitMouse()")
ElseIf Not OpenScreen(#ScreenWidth, #ScreenHeight, #ScreenDepth, "CollisionTest")
MessageRequester("Error", "OpenScreen()")
EndIf
Player\Size = 30
Player\X = #ScreenWidth/2 - Player\Size/2
Player\Y = #ScreenHeight/2 - Player\Size/2
; Ein paar Wände zum hüpfen:
AddWall(100, 600, 900, 10)
AddWall(200, 500, 80, 10)
AddWall(300, 400, 80, 10)
AddWall(400, 300, 80, 10)
AddWall(500, 200, 80, 10)
AddWall(350, 400, 300, 10)
AddWall(700, 200, 20, 300)
AddWall(800, 200, 20, 700)
AddWall(820, 400, 20, 10)
AddWall(820, 500, 40, 10)
AddWall(900, 300, 40, 10)
Repeat
ExamineKeyboard()
ExamineMouse()
ClearScreen(#Black)
StartDrawing(ScreenOutput())
; Draw Player:
Box(Player\X, Player\Y, Player\Size, Player\Size, #White)
; Draw all walls:
ForEach Wall()
Box(Wall()\X, Wall()\Y, Wall()\Width, Wall()\Height, #Red)
Next
StopDrawing()
FlipBuffers()
If KeyboardPushed(#PB_Key_Left)
Player\MoveX = -4
ElseIf KeyboardPushed(#PB_Key_Right)
Player\MoveX = 4
Else
Player\MoveX = 0
EndIf
If Jumpable And Player\MoveY = 0 And KeyboardPushed(#PB_Key_Up)
; Springen:
Player\MoveY = 15
Jumpable = #False
Else
; Die Gravitation zieht den Spieler hinunter:
Player\MoveY - 0.9
If Player\MoveY < -12
Player\MoveY = -12
EndIf
EndIf
Player\X + Player\MoveX
Player\Y - Player\MoveY
ForEach Wall()
Side = RectangleCollision(Player\X, Player\Y, Player\Size, Player\Size, Wall()\X, Wall()\Y, Wall()\Width, Wall()\Height)
;Kollision ist aufgetreten; Welche Seite der Wand ist betroffen?:
If Side
Select Side
Case #Collision_Left
Player\X = Wall()\X - Player\Size
Player\MoveX = 0
Case #Collision_Right
Player\X = Wall()\X + Wall()\Width
Player\MoveX = 0
Case #Collision_Top
; Der Spieler ist auf einen Boden gelandet:
Player\Y = Wall()\Y - Player\Size
Player\MoveY = 0
; Den Spieler wieder springfähig machen:
Jumpable = #True
Case #Collision_Bottom
Player\Y = Wall()\Y + Wall()\Height
Player\MoveY = 0
EndSelect
EndIf
Next
Delay(13) ;CPU ein bisschen schonen
Until KeyboardPushed(#PB_Key_Escape)
gerne ein richtiges BreakOut- oder Jump&Run-Game machen. Deswegen
habe ich dies hier gepostet.
Gruß Josef