Grid-Steuerung in GMS2

Grid-Steuerung-in-GMS2

Die Steuerung innerhalb eines unsichtbaren Gitters ist in zahlreichen klassischen Spielen erforderlich. Das Tutorial zeigt nicht nur, wie man das Prinzip technisch umsetzt, sondern streift auch Themen wie Konstanten, Umgang mit globalen Variablen und eine flexiblere Art der Steuerung.

Was ist eine Grid-Steuerung?

In den meisten Spielen wird gewünscht, dass sich Spieler und Gegner pixelgenau bewegen. Bei einer Grid-Steuerung handelt es sich um ein Raster und die Spielfigur bewegt sich von Feld zu Feld. Etwa wie auf einem Schachbrett. Das Ziel dieses Tutorials sieht wie folgt aus:

Grid-Steuerung-in-GMS2

Der rote Kreis ist der Spieler, der mit den Pfeiltasten in alle vier Richtungen bewegt werden kann. Lässt man die Taste los, bleibt er mittig im Gitter stehen. Das Gitter selbst soll nur das Prinzip zeigen und muss im Spiel natürlich nicht gezeichnet werden.

Grafiken

Grafik des SpielersFür das Beispiel benötigen wir zwei Grafiken. Eine Wand und einen Spieler. Beide haben eine Auflösung von 32×32 Pixeln. Die Wand ist, wie im Beispiel zu sehen, Grau. Der Spieler ist Rot. Die Farben spielen natürlich keine Rolle. Wichtig ist, dass die Kollisionsmaske bei beiden gefüllt ist. Origin liegt bei 0,0.

Die ersten Skripte

Ich möchte nicht nur plump zeigen, wie man die Steuerung implementiert, sondern eine Version anbieten, mit der man auch bei größeren Projekten arbeiten kann. Deshalb leben wir zwei Skripte an, die wir bei einem simplen Beispiel nicht bräuchten.

scr_global_variables

Globale Variablen lege ich immer in einem extra Skript ab. Dieses Skript wird am Anfang des Spiels gestartet. In der Regel habe ich dafür sogar einen eigenen Raum, in dem am Anfang alles initialisiert wird, was man im Spiel braucht. Wir laden im Spiel das Script lediglich im Objekt obj_game_controller, das Prinzip sollte aber klar sein.

Außerdem legen wir gleich zwei Konstanten an.

Bei den Makros handelt es sich um Konstanten. Sie stehen, wie globale Variablen, immer zur Verfügung, können aber im Spiel nicht mehr geändert werden. Wichtig ist, dass vor macro das Rautezeichen (#) steht. Ein = entfällt ebenfalls und am Ende darf kein Semikolon (;) stehen.

Darunter definieren wir die globalen Variablen. Hierbei handelt es sich um die vier Pfeiltasten und Escape. Es ist sinnvoll, solche Tasten außerhalb der Objekte zu definieren. Globale Variablen verwenden wir, weil es in einem Spiel sein kann, dass die Werte durch ein Setup geändert und in einer INI gespeichert werden.

scr_checkInput

Wir definieren die fünf Tasten als Variablen. Das hat den Vorteil, dass wir nicht laufend die globalen Variablen eingeben müssen sondern lediglich mit kUp, kDown etc. arbeiten.

Die Objekte

Für das Beispiel brauchen wir vier Objekte.

obj_par_collision

Das Objekt ist komplett leer. Es dient lediglich zur Kollisionsabfrage. Dadurch werden die späteren Abfragen erleichtert, wenn man verschiedene Wände braucht.

obj_game_controller

Create-Event

Das war es schon. Wie gesagt, platziert man das am besten im ersten Raum. In einem größeren Spiel kommen hier noch weitere Abfragen und Definitionen hinzu. Anlegen und Auslesen der INI, der Auflösungen und vieles mehr.

obj_wall01

Wir laden die Grafik ein und definieren mit obj_par_collision den Parent. Mehr gibt es hier nicht zu tun.

obj_testplayer

Hier brauchen wir drei Events. Das Draw Event wäre nicht unbedingt nötig, aber da wir auch das Grid zeichnen möchten, gönnen wir uns den “Umstand”.

Create Event

Zunächst: Das image_speed wäre nicht nötig, wir haben ja keine Animation. Da manche aber für ein RPG eine Animation haben möchten, hab ich es mal platziert.

Die Variablen to_x und to_y werden im Step-Event benötigt. Beim Ausgangszustand definieren wir sie bei der Position, an der unser Spieler bei Spielbeginn steht. Die Variable moving brauchen wir um bei der Steuerung abzufragen, ob sich der Spieler aktuell bewegt.

Step Event

Hier beginnt der wichtigste Teil.

Gehen wir den Code Schritt für Schritt durch. Im ersten Block erfolgt die Bewegung. Weichen to_x und to_y von x und y ab, bewegt sich der Spieler im Schritt, den wir als move_step definiert haben. Das ist eine der Konstanten und beträgt im Beispiel 4 Pixel.

Anschließend wird geschaut, ob die Positionen identisch sind. Wenn to_x und to_y auf x und y stehen, wird die Bewegung wieder erlaubt.

Danach prüfen wir die Steuerung. Zunächst wird das Skript scr_checkInput ausgeführt. Danach haben wir für jede Richtung einen eigenen Block, der immer gleich funktioniert. Wir prüfen die Taste und ob man sich bewegen darf. Anschließend haben wir eine Variable, entweder xx oder yy, die prüft, ob man sich in diese Richtung bewegen darf. Das machen wir, indem wir x bzw. y mit grid_steps addieren. Daraufhin wird geschaut, ob der Platz bei der neuen Koordinate (xx oder yy) frei ist. Im Beispiel machen wir das mit place_meeting und beziehen uns auf obj_par_collision.

Wenn der Platz frei ist, geben wir bekannt, dass wir uns bewegen können. Den Variablen to_x und to_y wird der neue Wert gegeben. Beim nächsten Durchlauf des Step-Events wird oben die Bewegung durchgeführt.

Innerhalb der place_meeting – Abfrage könnten wir nun auch die entsprechenden Sprites für den Spieler definieren.

Im Prinzip war es das schon. Jetzt zeichnen wir noch das Gitter und deswegen müssen wir auch die Spielfigur zeichnen. Ohne Draw-Event würde es automatisch gehen.

Draw Event

Als erstes wird der Spieler gezeichnet. Danach definieren wir mit verticalLines und horicontalLines die Anzahl Linien, die wir brauchen. Wer etwas Geschwindigkeit sparen will, lässt das var weg und kopiert die zwei Zeilen in den Create-Event.

Nun definieren wir Transparenz und Farbe des Gitters und zeichnen die Linien mit Hilfe von zwei for-Schleifen. Die Linien gehen über die Wände hinweg, in diesem Beispiel soll uns das aber nicht stören.

Raum bauen

Nun kann ein Testraum wie oben gezeigt gebaut werden. Das Objekt obj_game_controller kann man außerhalb platzieren. Theoretisch können die Wände skaliert werden, ich hab es bei einzelnen Objekten belassen. Wer das Prinzip optimieren will, macht ein unsichtbares Wandobjekt für die Kollision und arbeitet bei den Wänden (und ggf. beim Boden) mit Tiles. Das wirkt sich auf die Geschwindigkeit sehr gut aus, da man die Anzahl Objekte, bei denen die Kollision geprüft werden muss, stark reduziert wird.

Variationen

Aufgrund der Konstanten und globalen Variablen lässt sich das Beispiel schnell an eigene Ansprüche anpassen. Geschwindigkeit, Gitternetz, Steuerung per Gamepad, alles kein Problem.

In manchen Spielen kann es erforderlich sein, statt einen Schritt so viele zu machen, bis die Spielfigur an einer Wand kollidiert. Ein Beispiel hierfür sind Denkspiele, wie etwa Atomix. Mit einer kleinen Modifikation des Step-Events können wir auch das erreichen. Da wir im Draw-Event bereits die Anzahl der Linien auslesen, müssen wir die beiden Zeilen noch in das Create-Event verschieben. Diese Info brauchen wir gleich.

Create Event

Wichtig: Für x brauchen wir verticalLines, für y horicontalLines.

Step Event

Das zentrale Element ist die Abfrage der Kollision mittels collision_line. In der for-Schleife gehen wir Schrittweise vor. Die Schritte, die wir benötigen, sagen uns die zwei Variablen aus dem Create Event. Bei jedem Schritt schauen wir, ob es zu einer Kollision kommt. Wenn es keine Kollision gibt, geht es in den nächsten Schritt. Haben wir eine Kollision, legen wir das neue Ziel fest. Etwa mit to_x -= i*grid_steps-grid_steps;. Das heißt: Wir nehmen die Koordinaten einen Schritt vorher, da wir ja nicht in der Wand stehen bleiben möchten. Fertig ist der Lack.

 

Hat Dir dieser Artikel gefallen? Dann würden wir uns sehr über Unterstützung freuen.

Hinterlasse einen Kommentar

avatar
1024
  Abonnieren  
Benachrichtige mich bei