Habe ich es doch gewusst... Die Kollisionsabfrage scheitert bei dir

Springe ich seitlich gegen eine Wand (z.B. die über dem Rohr), dann werde ich an die Decke positioniert, weil anscheinend nur "MoveY" bei der Abfrage unter Betracht genommen wird.
Nach ein wenig Denkarbeit habe ich einen Kollisionsalgorithmus zusammengebastelt, der mir bisher noch nie gemeckert hat:
Code: Alles auswählen
Enumeration 1 ;-> Danke für den Hinweis kswb73
#Collision_Top ;Auf den Boden geklatscht
#Collision_Bottom ;An die Decke gesprungen
#Collision_Left ;Gegen die linke Wand gedonnert
#Collision_Right ;Gegen die rechte Wand gedonnert
EndEnumeration
Procedure.i Collision(AX.f, AY.f, AWidth.f, AHeight.f, ADX.f, ADY.f, BX.f, BY.f, BWidth.f, BHeight.f)
;By Josef Sniatecki
Protected M.f, Y.f
If AX < BX + BWidth And AX + AWidth > BX And AY < BY + BHeight And AY + AHeight > BY
If ADX > 0
If ADY > 0
M = ADY/ADX
Y = AY - ((AX + AWidth) - BX)*M
If Y + AHeight > BY
ProcedureReturn #Collision_Left
Else
ProcedureReturn #Collision_Top
EndIf
ElseIf ADY < 0
M = ADY/ADX
Y = AY - ((AX + AWidth) - BX)*M
If Y < BY + BHeight
ProcedureReturn #Collision_Left
Else
ProcedureReturn #Collision_Bottom
EndIf
Else
ProcedureReturn #Collision_Left
EndIf
ElseIf ADX < 0
If ADY < 0
M = ADY/ADX
Y = AY + ((BX + BWidth) - AX)*M
If Y > BY + BHeight - 1
ProcedureReturn #Collision_Bottom
Else
ProcedureReturn #Collision_Right
EndIf
ElseIf ADY > 0
M = ADY/ADX
Y = AY + ((BX + BWidth) - AX)*M
If Y + AHeight - 1 < BY
ProcedureReturn #Collision_Top
Else
ProcedureReturn #Collision_Right
EndIf
Else
ProcedureReturn #Collision_Right
EndIf
ElseIf ADY > 0
ProcedureReturn #Collision_Top
ElseIf ADY < 0
ProcedureReturn #Collision_Bottom
EndIf
EndIf
ProcedureReturn #False
EndProcedure
AX, AY, AWidth und AHeight sind die Position und Größe deines Spielers/Ghosts. ADX und ADY ist der Bewegungsvektor deines Spielers (in deinem Fall "MoveX" und "MoveY"). Logischerweise ist BX, BY, BWidth und BHeight die Position und Größe des Gegenstandes, mit dem du eine Kollisionsabfrage durchführen möchtest (also z.B. eine Wand). Falls sich dieser Gegenstand auch bewegt, musst du diesen Bewegungsvektor vom Bewegungsvektor des Spielers abziehen (also ADX - BDX und ADY - BDY (das ergibt sich, wenn man als Bezungssystem den Gegenstand wählt)).
Zum Algorithmus: Hier werden die Vorzeichen des Vektors (ADX,ADY) in betracht genommen. Je nach Kombination der Vorzeichen des X und Y Parameters werden zwei in Frage kommende Seiten genauer geprüft. Nun leite ich aus diesem Vektor eine lineare Funktion ab, indem ich die Steigung (M = ADY/ADX) berechne. Dadurch kann ich nun den Spieler in den Moment versetzen, an dem er nur den Gegenstand BERÜHRT hat, also quasi nicht mit diesem überlappt. Nun kann ich also genau prüfen, mit welcher Seite der Spieler gegen den Gegenstand kollidierte.
Das Ergebnis ist demnach eines der vier Konstanten aus dem "Enumeration"-Block.
Also kannst du folgendermaßen schnell und leicht eine genaue Kollision zwischen zwei Rechtecken (nicht unterschiedlich rotiert) berechnen:
Code: Alles auswählen
Select Collision(PlayerX, PlayerY, PlayerWidth, PlayerHeight, PlayerMoveX, PlayerMoveY, WallX, WallY, WallWidth, WallHeight)
Case #Collision_Top
PlayerY = WallY - PlayerHeight
PlayerMoveY = 0
Case #Collision_Bottom
PlayerY = WallY + WallHeight
PlayerMoveY = 0
Case #Collision_Left
PlayerX = WallX - PlayerWidth
PlayerMoveX = 0
Case #Collision_Right
PlayerX = WallX + WallWidth
PlayerMoveX = 0
EndSelect
Viel Spaß beim Einbauen
Gruß Josef
EDIT: Sehe gerade, dass die Kollision im obersten Download einwandfrei funktioniert. Wie ich sehe, hast du dass mit dem zweidiemnsionalen Tile-Array gelöst. Nur komisch das beim neuen Download immer so ein zurückzucken an dem Rohr entsteht.
EDIT2: Setzt man in Version 1.3 das Feld (3, 8 ) = 1, dann bemerkt man schnell, dass bei einer seitlichen Kollision etwas nicht stimmt.