2D Spiel (Platformer) - Kollisionserkennung per Rectangles

Jack159

Lieutenant
Registriert
Dez. 2011
Beiträge
766
Hallo,

ich arbeite gerade an einem 2D Spiel (Platformer) und habe ein kleines Problem bei der Kollisionerkennung.
Hier zunächst ein Bild von der derzeitigen Situation:

collision.JPG

Die Blaue Figur ist die Spielfigur und die weißen Blöcke die Spielumgebung, welche der Spieler eben nicht durchlaufen können soll.
Der Spieler besitzt für die Kollsionserkennung 4 Rechtecke/Rectangles (rot eingezeichnet).
Die weißen Blöcke besitzen ihren gesamten Block als sich als Rectangle für die Kollisionserkennung.

Die Kollisionserkennung funktioniert bisher einwandfrei bis auf 1 kleinen Bug:
Wenn ich mit der Spielfigur, so wie sie genau auf dem Screenshot knapp unter dem Block steht, springe, dann kollidiert der Spieler zwar mit dem Block, aber das obere Rectangle der Spielfigur streift am Block vorbei. Wirklich kollidieren tuen nur das rechte Rectangle der Spielfigur mit dem Block, woraufhin entsprechend falsch gehandelt wird (Spielfigur "rutscht" links seitlich in dem Fall am Block vorbei).
Wenn ich allerdings das obere und untere Rectangle der Spielfigur auf z.b. 1 Pixel Abstand bis zum Rand jeweils vergrößere, dann habe ich das Problem, dass wenn ich meine Spielfigur nach z.B. rechts gegen einen Block bewege, dann fälschlicherweise eine Kollision am oberen Rectangle des Spielers erkannt wird, da dieser eben bis zum rechten Rand reicht und ich meine Spielfigur mit 5 Pixel pro Tick bewege. Der obere und untere Rectangle müssen also mind. 6 Pixel seitlich Patz haben, damit dies nicht passiert....

Weiß jemand vielleicht eine Lösung für mein Problem?
 
Spielfigur "rutscht" links seitlich in dem Fall am Block vorbei
An der Stelle habe ich Verständnisprobleme. Sie rutscht links am Block vorbei? Kannst das grob einzeichnen oder, noch besser, das ganze aufnehmen?
 
Sweepi schrieb:
An der Stelle habe ich Verständnisprobleme. Sie rutscht links am Block vorbei? Kannst das grob einzeichnen oder, noch besser, das ganze aufnehmen?

Du kannst mir aber soweit folgen, dass in dem Falle (so wie auf dem Screenshot zu sehen, dass ich dort direkt springe) das obere rote Rechteck der Spielfigur nicht mit dem weißen Block kollidiert (und demzufolge keine Kollision von der Oberseite des Spielers registriert wird), sondern das rechte rote Rechteck der Spielfigur mit dem weißen Block kollidiert (und demzufolge eine Kollision von der rechten Seite des Spielers registriert wird)?

Falls ja, dann poste ich hier den entsprechenden Codeausschnitt (Falls nein, dann sag bescheid, dann versuche ich es noch genauer zu erklären):
Dieser Codeausschnitt enthält die Prüfung und Behandlung einer Kollision mit der Spielfigur an der rechten Seite und einem Block.

Code:
/*
   getBoundsRight() liefert das rechte rote Rechteck der Spielfigur.

   tempObject.getBounds()) liefert das Rechteck eines Blocks (das ganze steckt in einer Schleife, an der Stelle sei die Rede von dem Block, unter dem der Spieler auf dem Screenshot steht).

   Die if-Abfrage prüft eben, ob die beiden genannten Rectangles miteinander kollidieren bzw. sich überschneiden.

   Wenn sich die Spielfigur bewegt (z.B. springt), dann werden velX bzw. velY der Spielfigur verändert. velX bzw. velY   
   werden permament in der Spielschleife zu x bzw y der Spielfigur addiert. "velX = 0;" bedeutet also, dass sich die  
   Spielfigur nicht mehr nach rechts oder links bewegen soll bzw. stehen bleiben soll.

   x = tempObject.getX() - width;  bedeutet, dass die Spielfigur direkt links neben dem Object/Block gesetzt wird, damit 
   eine "perfekte Kollision" ermöglicht wird.
*/
				if(getBoundsRight().intersects(tempObject.getBounds())) {
					velX = 0;
					x = tempObject.getX() - width;
				}


Jetzt müsste es (hoffentlich^^) verständlicher sein, was ich mit "vorbeirutschen" meine.
 
Jack159 schrieb:
und ich meine Spielfigur mit 5 Pixel pro Tick bewege. Der obere und untere Rectangle müssen also mind. 6 Pixel seitlich Patz haben, damit dies nicht passiert...
Also dein eigentliches Problem kann ich anhand der Beschreibung nicht nachvollziehen und ich verstehe auch nicht, warum deine Spielfigur 4 Boxen braucht, aber dieses Symptom was dich stört, bedeutet erst einmal, dass du beim Bewegen der Figur keinen Check drin hast, ob diese Bewegung überhaupt erlaubt ist.
Du musst quasi simulieren, ob mit der Bewegung eine Kollision verursacht werden würde (aktuellere Position der Spielfigur + Bewegungsvektor ergibt neue Position, die dann mit potentiellen Kollisionskandidaten verglichen wird) und dann diese Bewegung verhindern. Das kann man später dann noch optimieren, damit du nicht ständig mit den Positionswerten aller Objekte der Welt vergleichen musst (quadtree).
 
Wenn du das obere und untere Rectangle auf die Breite deiner Spielfigur vergrösserst, dann erhälst du natürlich bei normalem Abgleich Kollisionen, wenn du z.b. nach rechts läufst und gegen einen Stein läufst.
Berücksichtigst du allerdings den Bewegungsvektor bei der Kollisionsabfrage, sollte das doch leicht zu korrigieren sein.

(Horizontale Bewegung: nur Kollision rechts links möglich, also oben und unten garnicht erst abfragen).
 
Tumbleweed schrieb:
Also dein eigentliches Problem kann ich anhand der Beschreibung nicht nachvollziehen und ich verstehe auch nicht, warum deine Spielfigur 4 Boxen braucht

Wieviel Boxen würdest du denn bei der Spielfigur verwenden? Nur eine? Wie willst du denn da prüfen, ob der Spieler jetzt rechts oder links gegen eine Wand läuft, mit dem Kopf gegen eine Wand springt oder auf einen Boden aufkommt?
Jeder dieser Fälle erfordert ja unterschiedliche Behandlungen.

inter2k3 schrieb:
Wenn du das obere und untere Rectangle auf die Breite deiner Spielfigur vergrösserst, dann erhälst du natürlich bei normalem Abgleich Kollisionen, wenn du z.b. nach rechts läufst und gegen einen Stein läufst.
Berücksichtigst du allerdings den Bewegungsvektor bei der Kollisionsabfrage, sollte das doch leicht zu korrigieren sein.

Der Bewegungsvektor (oder ähnliches) hörte sich erst nach einer Lösung an, aber was ist, wenn ich die Spielfigur nicht in exakt genau 1 Richtung bewege sondern in 2 Richtungen, also schräg (z.B. nach rechts-oben) und dann gegen einen Block mit der rechten Seite stoße? Oder gar genau in eine Ecke von Blöcken fliege, sodass gleichzeitig eine Kollision rechts und oben bei der SPielfigur stattfindet?

inter2k3 schrieb:
(Horizontale Bewegung: nur Kollision rechts links möglich, also oben und unten garnicht erst abfragen).

Muss unten nicht permament abgefragt werden? Weil wenn ich aufhöre nach unten abzufragen und gerade auf einen Block stehe, dann fällt meine Spielfigur ja durch den Block, weil ja nicht mehr nach einer Kollision nach unten abgefragt wird, oder?

Korrigiert mich wenn ich falsch liege :D
 
Zuletzt bearbeitet:
Okay, hätte ich drauf kommen können, dass du es dafür brauchst. :)

Ich habe das anders gelöst, als ich das letzte mal Kollision für ein Spiel gebastelt habe. Ich hatte bei jeder Kollision eine "onCollision"-Methode auf den Betroffenen Spielobjekten aufgerufen und als Parameter eine Referenz auf den Kollisionspartner reingegeben. Dadurch kannst du feiner kontrollieren was wie mit wem kollidiert. Wenn z.B. deine Figur mit dem Kopf von unten gegen einen Klotz springt wie in Super Mario, dann kannst du im Fall einer Kollision sowas machen wie
Code:
if (collisionPartner instanceof CoinDropping && (collisionPartner.y + collisionPartner.height) > this.y) {
    ((CoinDropping) collisionPartner).dropCoin()
}
Ist jetzt nur aus der Hüfte und hängt natürlich von der Richtung deiner Achsen ab, aber… you get the idea. Dadurch reicht dir jedenfalls eine einzelne Box.
 
Zuletzt bearbeitet:
Tumbleweed schrieb:
Okay, hätte ich drauf kommen können, dass du es dafür brauchst. :)

Ich habe das anders gelöst, als ich das letzte mal Kollision für ein Spiel gebastelt habe. Ich hatte bei jeder Kollision eine "onCollision"-Methode auf den Betroffenen Spielobjekten aufgerufen und als Parameter eine Referenz auf den Kollisionspartner reingegeben. Dadurch kannst du feiner kontrollieren was wie mit wem kollidiert. Wenn z.B. deine Figur mit dem Kopf von unten gegen einen Klotz springt wie in Super Mario, dann kannst du im Fall einer Kollision sowas machen wie
Code:
if (collisionPartner instanceof CoinDropping && (collisionPartner.y + collisionPartner.height) > this.y) {
    ((CoinDropping) collisionPartner).dropCoin()
}
Ist jetzt nur aus der Hüfte und hängt natürlich von der Richtung deiner Achsen ab, aber… you get the idea. Dadurch reicht dir jedenfalls eine einzelne Box.

Ich glaube dein Beispiel ist etwas anders bzw. einfacher, da es sich bei deinem Beispiel (anscheinend) um die Kollisionsprüfung von Spielfigur und einer Münze handelt. Hier reicht natürlich jeweils 1 Rectangle für die Spielfigur und die Münze aus um eine Kollision zu prüfen und dann ggf. die Münze zu entfernen. Der Spieler bewegt sich ja durch die verschwindene Münze hindurch. Daher muss nicht geprüft werden von welcher Seite der Spieler die Münze berührt.

Aber ich glaube die Lösung gefunden zu haben:
Ich habe die oberen und unteren roten Rechtecke der Spielfigur breiter gemacht, sodass diese bis zum Rand der Spielfigur gehen. Bei der Prüfung auf Kollisionen habe ich aber nun die Reihenfolge verändert.
Vorher sah die Reihenfolge so aus:
- Prüfung auf Kollision an der oberen Seite der Spielfigur
- Prüfung auf Kollision an der unterenSeite der Spielfigur
- Prüfung auf Kollision an der linken Seite der Spielfigur
- Prüfung auf Kollision an der rechten Seite der Spielfigur

Dabei trat der Fehler aus dem Startpost auf. Jetzt sieht die Reihenfolge so aus:
- Prüfung auf Kollision an der linken Seite der Spielfigur
- Prüfung auf Kollision an der rechten Seite der Spielfigur
- Prüfung auf Kollision an der oberen Seite der Spielfigur
- Prüfung auf Kollision an der unterenSeite der Spielfigur

Ich habe versucht von allen möglichen Richtungen mit der Spielfigur gegen einen Block zu laufen und bisher habe ich nichts ungewöhnliches entdeckt :D
 
Zurück
Oben