Ich versuche, ein 2D-Plattformspiel (Mario-Typ) zu erstellen, und ich habe einige Probleme mit dem richtigen Umgang mit Kollisionen. Ich schreibe dieses Spiel in C ++ und verwende SDL für die Eingabe, das Laden von Bildern, das Laden von Schriftarten usw. Ich verwende OpenGL auch über die FreeGLUT-Bibliothek in Verbindung mit SDL, um Grafiken anzuzeigen.
Meine Methode zur Kollisionserkennung ist AABB (Axis-Aligned Bounding Box), was wirklich alles ist, mit dem ich beginnen muss. Was ich brauche, ist eine einfache Möglichkeit, sowohl zu erkennen, auf welcher Seite die Kollision aufgetreten ist, als auch die Kollisionen richtig zu behandeln. Wenn der Spieler mit der Oberseite der Plattform kollidiert, positionieren Sie ihn im Grunde genommen nach oben. Wenn die Seiten kollidieren, positionieren Sie den Spieler wieder auf der Seite des Objekts. Wenn es zu einer Kollision mit dem Boden kommt, positionieren Sie den Spieler unter der Plattform neu.
Ich habe viele verschiedene Methoden ausprobiert , z. B. den Versuch, die Eindringtiefe zu ermitteln und den Player anhand der Eindringtiefe rückwärts zu positionieren. Leider scheint nichts, was ich versucht habe, richtig zu funktionieren. Die Bewegung des Spielers ist sehr unangenehm und positioniert den Spieler neu, wenn ich das nicht möchte. Ein Grund dafür ist wahrscheinlich, dass ich das Gefühl habe, dass dies etwas so Einfaches ist, aber ich überlege es mir.
Wenn jemand glaubt, helfen zu können, schauen Sie sich bitte den folgenden Code an und helfen Sie mir, dies zu verbessern, wenn Sie können. Ich würde gerne darauf verzichten, eine Bibliothek zu verwenden, um damit umzugehen (wie ich selbst lernen möchte) oder so etwas wie das SAT (Separating Axis Theorem), wenn dies überhaupt möglich ist. Vielen Dank im Voraus für Ihre Hilfe!
void world1Level1CollisionDetection()
{
for(int i; i < blocks; i++)
{
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==true)
{
de2dObj ballPrev;
ballPrev.coords[0] = ball.coords[0];
ballPrev.coords[1] = ball.coords[1];
ballPrev.coords[2] = ball.coords[2];
ballPrev.coords[3] = ball.coords[3];
ballPrev.coords[0] -= ball.xspeed;
ballPrev.coords[1] -= ball.yspeed;
ballPrev.coords[2] -= ball.xspeed;
ballPrev.coords[3] -= ball.yspeed;
int up = 0;
int left = 0;
int right = 0;
int down = 0;
if (ballPrev.coords[0] < block[i].coords[0] && ballPrev.coords[2] < block[i].coords[0] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1])) || ((ball.coords[1] < block[i].coords[3]) || ball.coords[3] < block[i].coords[3])))
{
left = 1;
}
if (ballPrev.coords[0] > block[i].coords[2] && ballPrev.coords[2] > block[i].coords[2] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1])) || ((ball.coords[1] < block[i].coords[3]) || (ball.coords[3] < block[i].coords[3]))))
{
right = 1;
}
if(ballPrev.coords[1] < block[i].coords[1] && block[i].coords[1] < ballPrev.coords[3] && ballPrev.coords[3] < block[i].coords[3])
{
up = 1;
}
if(block[i].coords[1] < ballPrev.coords[1] && ball
{
down = 1;
}
cout << left << ", " << right << ", " << up << ", " << down << ", " << endl;
if (left == 1)
{
ball.coords[0] = block[i].coords[0] - 18.0f;
ball.coords[2] = block[i].coords[0] - 2.0f;
}
else if (right == 1)
{
ball.coords[0] = block[i].coords[2] + 2.0f;
ball.coords[2] = block[i].coords[2] + 18.0f;
}
else if (down == 1)
{
ball.coords[1] = block[i].coords[3] + 4.0f;
ball.coords[3] = block[i].coords[3] + 20.0f;
}
else if (up == 1)
{
ball.yspeed = 0.0f;
ball.gravity = 0.0f;
ball.coords[1] = block[i].coords[1] - 17.0f;
ball.coords[3] = block[i].coords[1] - 1.0f;
}
}
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==false)
{
ball.gravity = -0.5f;
}
}
}
Um zu erklären, was ein Teil dieses Codes bedeutet:
Die Blockvariable ist im Grunde eine Ganzzahl, die die Anzahl der Blöcke oder Plattformen speichert. Ich überprüfe alle Blöcke mit einer for-Schleife, und die Nummer, auf der sich die Schleife gerade befindet, wird durch die Ganzzahl i dargestellt. Das Koordinatensystem mag etwas seltsam erscheinen, daher lohnt es sich, dies zu erklären. Koordinaten [0] repräsentieren die x-Position (links) des Objekts (wo es auf der x-Achse beginnt). Koordinaten [1] repräsentieren die y-Position (oben) des Objekts (wo es auf der y-Achse beginnt). Koordinaten [2] repräsentiert die Breite des Objekts plus Koordinaten [0] (rechts). Koordinaten [3] repräsentiert die Höhe des Objekts plus Koordinaten [1] (unten). de2dCheckCollision führt eine AABB-Kollisionserkennung durch. Hoch ist negativ y und runter ist positiv y, wie es in den meisten Spielen der Fall ist.
Hoffentlich habe ich genug Informationen bereitgestellt, damit mir jemand erfolgreich helfen kann. Wenn ich etwas ausgelassen habe, das von entscheidender Bedeutung sein könnte, lassen Sie es mich wissen und ich werde die erforderlichen Informationen bereitstellen. Für jeden, der helfen kann, wäre die Bereitstellung von Code sehr hilfreich und wird sehr geschätzt.
Nochmals vielen Dank für Ihre Hilfe!
Bearbeiten : Ich habe meinen Code mit einem neuen Algorithmus aktualisiert, der überprüft, wo sich der Ball vor der Kollision befand. Eckkästen funktionieren jetzt korrekt auf dieser einzelnen Plattform, aber wenn ich eine Wand aus Objekten habe, kann ich wirklich dagegen gleiten, aber wenn ich mich beim Gleiten zur Wand bewege, gehe ich durch sie hindurch und stehe im Wesentlichen jetzt auf einer Block innerhalb der Wand. Es gibt auch einen Jitter-Effekt, der auftritt, wenn ich am Boden bin und der Ball ständig auf und ab geht.
TheirPos-ourSize +- 1
die 1 zu entfernen, wenn Sie dies tun. Wenn Sie sich nicht sicher sind, wie Sie diesen Algorithmus herausfinden können, wäre ich mehr als bereit zu helfen. Mein Algorithmus ist im Moment perfekt =] (auch in welcher Reihenfolge checken Sie die Objekte ein?)Antworten:
Wenn ich Ihren Code richtig verstehe, kompensieren Sie die Kollision, indem Sie den Ball um einen festen Betrag versetzen, ohne seine Geschwindigkeit zu beeinflussen. Der Grund, warum Ihr Ball nervös wirkt, ist, dass seine Position zwar aufgrund der Kollision korrigiert wird, seine Geschwindigkeit jedoch immer noch auf das kollidierende Objekt gerichtet ist. Aufgrund dieser Geschwindigkeit bewegt sich der Ball immer noch in Richtung des kollidierenden Blocks und kollidiert nach einigen Frames, die ihn wieder versetzen.
Die vielleicht einfachste Lösung besteht darin, sicherzustellen, dass die Geschwindigkeiten bei einer Kollision zurückgesetzt werden, und sicherzustellen, dass sich der Ball nach dem Versetzen nicht in Richtung des Blocks bewegt.
quelle
Sie zeigen keinen Code an, der die Bewegung / Geschwindigkeit des Balls handhabt. Wenn Sie den Ball nicht stoppen / abprallen lassen, bewegt sich Ihr Ball im nächsten Frame zurück in den Block und wird "zurückbewegt", sodass er wahrscheinlich an der Seite des Blocks "stecken bleibt".
Wenn dies nicht der Fall ist, wenn Sie die Probleme genauer beschreiben und / oder mehr Code veröffentlichen können, kann möglicherweise jemand besser helfen :-)
quelle
Nun, Sie können immer das tun, was ich getan habe, auch wenn es von meiner Seite schlecht implementiert wurde. Ich habe eine einfache Methode in meiner "Being" -Klasse namens update_prev_pos (), die genau das tut. Sie speichert Ihre aktuelle Position in einer Struktur, die Sie sich ansehen möchten später. In meiner Kollisionsauflösungsfunktion betrachte ich die Position der betreffenden Seite. Wenn sich die Seite zuvor außerhalb des Objekts befand, muss diese Seite korrigiert werden.
Ich verwende eine Zwei-Pass-Methode, um Kollisionen zu überprüfen und aufzulösen. Ich würde empfehlen, alle Kollisionen der x-Achse und dann alle Kollisionen der y-Achse zu überprüfen. Auf diese Weise bleiben Sie nicht an Objekten hängen, die Sie nicht sollten. glücklich kollidieren =)
quelle
Vielen Dank für all die Hilfe, Leute, und entschuldigen Sie die späte Antwort.
Ich habe all diese Ideen berücksichtigt und sie helfen mir, das Problem zu beheben. Wenn jemand neugierig ist, wie ich das ursprüngliche und vollständige Problem gelöst habe, finden Sie hier auf Stapelüberlauf die vollständige Antwort (einschließlich Erläuterungen zum besseren Umgang mit Kollisionen). Die Person, die meine Frage beantwortete, war sehr großzügig und lieferte ein Diagramm, das denjenigen helfen sollte, die auch dieses Problem haben.
Vielen Dank an die folgenden Personen, die mir bei diesem Problem geholfen haben:
Ich schätze es sehr!
quelle