7 days of WordPress themes, graphics & videos - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Game Development
  2. Platformer

Grundlegende 2D-Platformer-Physik, Teil 4

Read Time: 14 mins
This post is part of a series called Basic 2D Platformer Physics .
Basic 2D Platformer Physics, Part 3
Basic 2D Platformer Physics, Part 5: Object vs. Object Collision Detection

German (Deutsch) translation by Federicco Ancie (you can also view the original English article)

Ledge Grabbing

Jetzt, da wir springen, von Einwegplattformen herunterfallen und herumlaufen können, können wir auch Ledge-Grabbing Funktion implementieren. Ledge-Grabbing-Mechaniken sind definitiv kein Muss in jedem Spiel, aber es ist eine sehr beliebte Methode, um den möglichen Bewegungsbereich eines Spielers zu erweitern, ohne etwas Extremes wie einen Doppelsprung zu machen.

Wir feststellen, ob ein Felsvorsprung ergriffen werden kann. Um Sie sicher sind, ob der Charakter einen Vorsprung greifen kann, überprüfen wir ständig die Seite, auf die sich der Charakter bewegt. Wenn wir oben auf dem AABB ein leeres Plättchen und darunter ein festes Plättchen finden, ist das obere Ende dieses festen Plättchens den Felsvorsprung, auf die unser Charakter greifen kann.

Variablen einrichten

Gehen wir zu unserer Character -Klasse, wo wir das Ledge-Grabbing implementieren. In der MovingObject-Klasse macht dies keinen Sinn, da die meisten Objekte keine Option zum Ergreifen eines Felsvorsprungs haben. Daher wäre es eine Verschwendung, dort eine Verarbeitung in diese Richtung durchzuführen.

Zuerst müssen wir ein paar Konstanten hinzufügen. Beginnen wir mit der Erstellung der Sensor-Offset-Konstanten.

cGrabLedgeStartY und cGrabLedgeEndY sind Offsets vom oberen Rand des AABB. Der erste ist der erste Sensorpunkt und der zweite ist der Endsensorpunkt. Wie Sie sehen können, muss der Charakter innerhalb von 2 Pixeln einen Felsvorsprung finden.

Wir brauchen auch eine zusätzliche Konstante, um den Charakter an der Kachel auszurichten, die er gerade ergriffen hat. Für unseren Charakter wird dies auf -4 gesetzt.

Wie möchten uns an die Koordinaten der Kachel erinnern, die wir gepackt haben. Speichern wir diese als Mitgliedsvariable eines Charakters.

Implementierung

Wir müssen sehen, ob wir den Felsvorsprungaus dem Sprungzustand herausholen können, also lasst uns dorthin gehen. Nachdem wir überprüft haben, ob der Charakter auf dem Boden gelandet ist, wollen wir sehen, ob die Bedingungen für das Ergreifen eines Felsvorsprungs erfüllt sind. Die Hauptbedingungen sind wie folgt:

  • Die vertikale Geschwindigkeit ist kleiner oder gleich Null (das Zeichen fällt).
  • Der Charakter ist nicht an der Decke - es nützt nichts, sich einen Felsvorsprung zu schnappen, wenn man nicht davon springen kann.
  • Der Charakter kollidiert mit der Wand und bewegt sich darauf zu.

Wenn diese drei Bedingungen erfüllt sind, dann müssen wir für die Leiste zu greifen suchen. Beginnen wir mit den Top-Position des Sensors berechnen, die sein wird, entweder die obere linke oder rechte obere Ecke des AABB.

Wie Sie sich vielleicht vorstellen können, stoßen wir hier auf ein ähnliches Problem wie bei der Implementierung der Kollisionsprüfungen. Wenn der Charakter sehr schnell fällt, ist es sehr wahrscheinlich, dass er den Hotspot übersieht, an dem er den Felsvorsprung greifen kann . Deshalb müssen wir nach der Kachel suchen, die wir greifen müssen, und zwar nicht ausgehend von der Ecke des aktuellen Rahmens, sondern von der vorherigen - wie hier dargestellt:


Das oberste Bild eines Zeichens ist seine Position im vorherigen Frame. In dieser Situation müssen wir nach Möglichkeiten suchen, um einen Vorsprung aus der oberen rechten Ecke des AABB des vorherigen Frames zu ergreifen und an der Position des aktuellen Frames anzuhalten.

Lassen Sie uns die Koordinaten der Kacheln ermitteln, die wir überprüfen müssen, indem wir zunächst die Variablen deklarieren. Wir werden Kacheln in einer einzelnen Spalte überprüfen. Alles, was wir brauchen, ist die X-Koordinate der Spalte sowie ihre oberen und unteren Y-Koordinaten.

Lassen Sie uns die X-Koordinate der AABB-Ecke ermitteln.

Wir möchten nur dann nach einem Felsvorsprung von der Position des vorherigen Frames suchen, wenn wir uns in dieser Zeit bereits in Richtung der geschobenen Wand bewegt haben - also hat sich die X-Position unseres Charakters nicht geändert.

Wie Sie sehen können, berechnen wir in diesem Fall das topY anhand der Position des vorherigen Frames und das unterste anhand der Position des aktuellen Frames. Wenn wir nicht neben einer Wand waren, werden wir einfach sehen, ob wir einen Felsvorsprung greifen können, indem wir nur die Position des Objekts im aktuellen Rahmen verwenden.

Okay, jetzt, da wir wissen, welche Kacheln überprüft werden müssen, können wir sie durchlaufen. Wir werden von oben nach unten gehen, da diese Reihenfolge am sinnvollsten ist, da wir Ledge-Grabbing nur dann zulassen, wenn der Charakter fällt.

Lassen Sie uns nun überprüfen, ob die Kachel, die wir iterieren, die Bedingungen erfüllt, unter denen der Charakter einen Felsvorsprung greifen kann. Die Bedingungen sind, wie zuvor erläutert, wie folgt:

  • Die Kachel ist leer.
  • Die Kachel darunter ist eine feste Kachel (dies ist die Kachel, die wir greifen möchten).

Der nächste Schritt besteht darin, die Position der Ecke der Kachel zu berechnen, die wir greifen möchten. Dies ist ziemlich einfach - wir müssen nur die Position der Kachel ermitteln und sie dann um die Größe der Kachel versetzen.

Nachdem wir dies wissen, sollten wir prüfen, ob sich die Ecke zwischen unseren Sensorpunkten befindet. Natürlich wollen wir das nur tun, wenn wir die Kachel in Bezug auf die Position des aktuellen Rahmens überprüfen, dh die Kachel mit der Y-Koordinate gleich dem unteren Y. Wenn dies nicht der Fall ist, können wir davon ausgehen, dass wir den Felsvorsprung zwischen dem vorherigen und dem aktuellen Frame passiert haben - also möchten wir denFelsvorsprung trotzdem greifen.

Jetzt sind wir zu Hause und haben den Vorsprung gefunden, den wir ergreifen wollen. Speichern wir zunächst die Kachelposition des ergriffenen Felsvorsprungs.

Wir müssen auch den Charakter an dem Felsvorsprung ausrichten. Wir möchten die Oberseite des Leistensensors des Charakters an der Oberseite der Kachel ausrichten und diese Position dann um cGrabLedgeTileOffsetY versetzen.

Abgesehen davon müssen wir beispielsweise die Geschwindigkeit auf Null setzen und den Status in CharacterState.GrabLedge ändern. Danach können wir aus der Schleife ausbrechen, da es keinen Sinn macht, den Rest der Kacheln zu durchlaufen.

Das wird es sein! Die Leisten können jetzt erkannt und erfasst werden. Jetzt müssen wir nur noch den GrabLedge-Status implementieren, den wir zuvor übersprungen haben.

Ledge Grab Controls

Sobald der Charakter einen Felsvorsprung greift, hat der Spieler zwei Möglichkeiten: Er kann entweder nach oben oder nach unten springen. Das Springen funktioniert wie gewohnt. Der Spieler drückt die Sprungtaste und die Kraft des Sprunges ist identisch mit der Kraft, die beim Springen vom Boden ausgeübt wird. Das Herunterfallen erfolgt durch Drücken der Abwärtstaste oder der Richtungstaste, die von dem Felsvorsprung weg zeigt.

Steuert die Implementierung

Das erste, was Sie hier tun müssen, ist festzustellen, ob sich den Felsvorsprung links oder rechts vom Charakter befindet. Wir können dies tun, weil wir die Koordinaten des Felsvorsprungs gespeichert haben, die der Charakter erfasst.

Wir können diese Informationen verwenden, um zu bestimmen, ob der Charakter von dem Felsvorsprung fallen soll. Um herunterzufallen, muss der Spieler entweder:

  • Drücken Sie die Abwärts-Taste
  • Drücken Sie die linke Taste, wenn wir einen Felsvorsprung rechts greifen, oder
  • Drücken Sie die rechte Taste, wenn wir links einen Felsvorsprunggreifen

Hier gibt es eine kleine Einschränkung. Stellen Sie sich eine Situation vor, in der wir die Abwärtstaste und die rechte Taste gedrückt halten, während sich der Charakter an einem Felsvorsprung rechts festhält. Dies führt zu folgender Situation:

Das Problem hierbei ist, dass der Charakter den Felsvorsprung sofort greift, nachdem er sie losgelassen hat.

Eine einfache Lösung besteht darin, die Bewegung in Richtung von dem Felsvorsprung für ein paar Frames zu sperren, nachdem wir von dem Felsvorsprung gefallen sind. Dazu müssen wir zwei neue Variablen hinzufügen; Nennen wir sie mCannotGoLeftFrames und mCannotGoRightFrames.

Wenn der Charakter von dem Felsvorsprung fällt, müssen wir diese Variablen setzen und den Status ändern, um zu springen.

Kehren wir nun ein wenig zum Jump zustand zurück und stellen wir sicher, dass unser Verbot, sich nach dem Ablegen von dem Felsvorsprung nach links oder rechts zu bewegen, eingehalten wird. Lassen Sie uns die Eingaben zurücksetzen, bevor wir prüfen, ob wir nach einem Vorsprung suchen sollten.

Wie Sie sehen können, erfüllen wir auf diese Weise nicht die Bedingungen, die zum Ergreifen eines Felsvorsprungs erforderlich sind, solange die blockierte Richtung mit der Richtung des Felsvorsprungs übereinstimmt, die der Charakter möglicherweise zu ergreifen versucht. Jedes Mal, wenn wir eine bestimmte Eingabe ablehnen, dekrementieren wir die verbleibenden blockierenden Frames, sodass wir uns schließlich wieder bewegen können - in unserem Fall nach 3 Frames.

Lassen Sie uns nun weiter am GrabLedge-Status arbeiten. Da wir es geschafft haben, von dem Felsvorsprung zu fallen, müssen wir es jetzt ermöglichen, aus der Greifposition zu springen.

Wenn der Charakter nicht von dem Felsvorsprung gefallen ist, müssen wir überprüfen, ob die Sprungtaste gedrückt wurde. In diesem Fall müssen wir die vertikale Geschwindigkeit des Sprungs einstellen und den Status ändern:

Das wars so ziemlich! Jetzt sollte Ledge Grabbing in allen möglichen Situationen ordnungsgemäß funktionieren.

Lassen Sie den Charakter kurz nach dem Verlassen einer Plattform springen

Um das Springen in Plattformspielen zu erleichtern, darf der Charakter oft springen, wenn er gerade vom Rand einer Plattform getreten ist und nicht mehr auf dem Boden liegt. Dies ist eine beliebte Methode, um die Illusion zu mildern, dass der Spieler die Sprungtaste gedrückt hat, der Charakter jedoch nicht gesprungen ist, was möglicherweise auf eine Eingangsverzögerung oder das Drücken der Sprungtaste unmittelbar nach dem Verlassen der Plattform durch den Spieler zurückzuführen ist.

Lassen Sie uns jetzt einen solchen Mechaniker implementieren. Zunächst müssen wir eine Konstante hinzufügen, wie viele Frames der Charakter, nachdem er die Plattform verlassen hat, noch einen Sprung ausführen kann.

Wir benötigen auch einen Frame-Zähler in der Character-Klasse, damit wir wissen, wie viele Frames der Charakter bereits in der Luft ist.

Setzen wir nun den mFramesFromJumpStart jedes Mal auf 0, wenn wir gerade den Boden verlassen haben. Machen wir das gleich, nachdem wir UpdatePhysics aufgerufen haben.

Und erhöhen wir es in jedem Frame, in dem wir uns im Sprungzustand befinden.

Wenn wir uns im Sprungzustand befinden, können wir keinen In-Air-Sprung zulassen, wenn wir uns entweder an der Decke befinden oder eine positive vertikale Geschwindigkeit haben. Positive vertikale Geschwindigkeit würde bedeuten, dass der Charakter keinen Sprung verpasst hat.

Wenn dies nicht der Fall ist und die Sprungtaste gedrückt wird, müssen wir nur die vertikale Geschwindigkeit auf den Sprungwert einstellen, als ob wir normal gesprungen wären, obwohl sich das Zeichen bereits im Sprungzustand befindet.

Und das ist es! Wir können den cJumpFramesThreshold auf einen großen Wert wie 10 Frames setzen, um sicherzustellen, dass er funktioniert.

Der Effekt hier ist ziemlich übertrieben. Es ist nicht sehr auffällig, wenn wir dem Charakter erlauben, nur 1-4 Frames zu springen, nachdem er tatsächlich nicht mehr auf dem Boden liegt, aber insgesamt können wir so ändern, wie nachsichtig unsere Sprünge sein sollen.

Skalieren der Objekte

Machen wir es möglich, die Objekte zu skalieren. Wir haben die mScale bereits in der MovingObject-Klasse. Alles, was wir tatsächlich tun müssen, ist sicherzustellen, dass sie den AABB- und den AABB-Offset ordnungsgemäß beeinflusst.

Lassen Sie uns zunächst unsere AABB-Klasse so bearbeiten, dass sie eine Skalierungskomponente enthält.

Bearbeiten wir nun die halfSize, sodass wir beim Zugriff tatsächlich eine skalierte Größe anstelle der nicht skalierten erhalten.

Wir möchten auch in der Lage sein, nur einen X- oder Y-Wert der halben Größe zu erhalten oder einzustellen, daher müssen wir auch für diese getrennte Getter und Setter erstellen.

Neben der Skalierung des AABB selbst müssen wir auch das mAABBOffset skalieren, damit das Sprite nach dem Skalieren des Objekts immer noch mit dem AABB übereinstimmt, wie es es getan hat, als das Objekt nicht skaliert wurde. Kehren wir zur MovingObject-Klasse zurück, um sie zu bearbeiten.

Wie zuvor möchten wir auch separat auf X- und Y-Komponenten zugreifen können.

Schließlich müssen wir auch sicherstellen, dass die Skalierung im MovingObject auch im AABB geändert wird. Die Skalierung des Objekts kann negativ sein, aber der AABB selbst sollte keine negative Skalierung haben, da wir uns darauf verlassen, dass die halbe Größe immer positiv ist. Deshalb übergeben wir nicht einfach die Skala an die AABB, sondern eine Skala, bei der alle Komponenten positiv sind.

Jetzt müssen wir nur noch sicherstellen, dass wir die Variablen, wo immer wir sie direkt verwendet haben, jetzt über die Getter und Setter verwenden. Überall dort, wo wir halfSize.x verwendet haben, möchten wir HalfSizeX verwenden, wo immer wir halfSize.y verwendet haben, möchten wir HalfSizeY verwenden und so weiter. Einige Verwendungen einer Such- und Ersetzungsfunktion sollten sich gut damit befassen.

Überprüfen Sie die Ergebnisse

Die Skalierung sollte jetzt gut funktionieren, und aufgrund der Art und Weise, wie wir unsere Kollisionserkennungsfunktionen aufgebaut haben, spielt es keine Rolle, ob der Charakter riesig oder winzig ist - er sollte gut mit der Karte interagieren.

Zusammenfassung

Dieser Teil schließt unsere Arbeit mit der Tilemap ab. In den nächsten Abschnitten werden wir Dinge einrichten, um Kollisionen zwischen Objekten zu erkennen.

Es hat einige Zeit und Mühe gekostet, aber das System sollte im Allgemeinen sehr robust sein. Eine Sache, die momentan möglicherweise fehlt, ist die Unterstützung für Pisten. Viele Spiele verlassen sich nicht auf sie, aber viele von ihnen. Das ist das größte Verbesserungsziel für dieses System. Vielen Dank fürs Lesen, bis zum nächsten Teil!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Game Development tutorials. Never miss out on learning about the next big thing.
Advertisement
Scroll to top
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.