2D Spiele

Top  Previous  Next

Diesen Monat werden wir die Workshop-Serie 2D-Games abschließen indem wir uns um Seiten-scrollende Games kümmern. Dabei handelt es sich um Spiele, in denen der Player riesige Welten erforschen kann. Der Engine wird dabei gesagt, dass sie neue Teile dieser Welten dann darstellen soll, wenn der Player einige Schwellenbereiche kreuzt, die sich normalerweise in der Nähe der Ecken des Bildschirms befinden.

 

Ich weiß, das mag ein bisschen konfus klingen, also öffnen wir gleich die Demo pagescrolling1.c und starten sie:

 

aum85_workshop1

 

Bewegen Sie den Player in Richtung linke Bildschirmseite. Sie werden merken, dass er nicht aus dem Bildschirm verschwinden kann - eine gute Sache, berücksichtigt man die Tatsache, dass dies der erste Raum unserer Welt ist. Gehen Sie jetzt auf die rechte Seite des Bildschirms und Sie werden sehen, dass der Player in einen anderen Raum teleportiert wird (in Wahrheit ein anderes Panel aber das ist eine Geschichte, die ich mir für später aufhebe).

 

aum85_workshop2

 

Gehen Sie weiter nach rechts und Sie werden im letzten Raum unseres Demos landen:

 

aum85_workshop3

 

Meine "riesige" Welt besteht nur aus 3 Räumen, aber Sie können selbstverständlich soviele hinzufügen wie Sie wollen. Zurück zur Seiten-scrolling-Debatte: wie Sie sehen, erlaubt es dieses Demo dem Player diverse Räume zu erforschen. Sobald er sich einer der Bildschirmgrenzen nähert wird ein neuer Raum dargestellt. Betrachten wir uns den Code, der all diese Dinge bewerkstelligt:

 

PANEL* player_pan;

 

PANEL* page1_pan =

{        

       pos_x = 0;

       pos_y = 0;

       bmap = "page1.pcx";

       flags = SHOW;

}

 

PANEL* page2_pan =

{        

       pos_x = 0;

       pos_y = 0;

       bmap = "page2.pcx";

}

 

PANEL* page3_pan =

{        

       pos_x = 0;

       pos_y = 0;

       bmap = "page3.pcx";

}

 

Wir definieren einen Panel-Pointer, der für den Player und 3 reguläre Panels - die werden unsere "Räume" darstellen - benutzt werden wird. Da die Räume für diese Art von Spielen verschieden sein sollen, können wir dafür fast jedes Bild verwenden.

 

function main()

{

       fps_max = 60;

       video_mode = 7;

       video_depth = 32;

       video_screen = 1;

}

 

function player_startup()

{

       VECTOR player_speed;

       var horizontal_speed = 0;

       player_pan = pan_create("bmap = player.png; NULL;", 150);

       player_pan.pos_x = 380;

       player_pan.pos_y = 510;

       player_pan.flags |= VISIBLE;

       player_pan.center_x = player_pan.size_x * 0.5;

       player_pan.center_y = player_pan.size_y;

       while (1)

       {

               vec_set(player_speed.x, accelerate (horizontal_speed, 3 * (key_cur - key_cul), 0.3));

               player_pan.pos_x += player_speed.x;

               if (key_cul + key_cur)

               {

                       player_pan.angle += 0.2 * sin(40 * total_ticks);

               }

               else

               {

                       player_pan.angle = 0;

               }

               wait (1);

       }

}

 

Die Funktion, die für den Player benutzt wurde ist der, die wir in einem vorangegangenen Workshop verwendet haben sehr ähnlich: sie erstellt ein Panel und weist es dem Pointer "player_pan" zu, platziert es bei x = 380 und y = 510 Pixeln und macht es sichtbar. Dann setzt sie den Drehpunkt für das Player-Panel ins Zentrum seiner Bitmap.

 

Die "while (1)"-Schleife bewegt den Player horizontal mit der von 3 gegebenen Geschwindigkeit und der von 0.3 gegebenen Reibung. Die sich ergebende, beschleunigte Geschwindigkeit wird auf den pos_x-Wert des Players addiert. Zusätzlich hierzu wird, um einen einfachen Animationseffekt zu erzielen, beim Drücken einer der beiden Rechts- / Links-Pfeiltasten der Winkel des Players verändert.

 

function pages_startup()

{

       while (1)

       {

               if ((player_pan.pos_x > 750) && (is(page1_pan, SHOW)))

               {

                       player_pan.pos_x = 0;

                       page1_pan.flags &= ~SHOW;

                       page2_pan.flags |= SHOW;

                       page3_pan.flags &= ~SHOW;

               }

               if ((player_pan.pos_x > 750) && (is(page2_pan, SHOW)))

               {

                       player_pan.pos_x = 5;

                       page1_pan.flags &= ~SHOW;

                       page2_pan.flags &= ~SHOW;

                       page3_pan.flags |= SHOW;

               }

               if ((player_pan.pos_x < 0) && (is(page2_pan, SHOW)))

               {

                       player_pan.pos_x = 750;

                       page1_pan.flags |= SHOW;

                       page2_pan.flags &= ~SHOW;

                       page3_pan.flags &= ~SHOW;

               }

               if ((player_pan.pos_x < 0) && (is(page3_pan, SHOW)))

               {

                       player_pan.pos_x = 750;

                       page1_pan.flags &= ~SHOW;

                       page2_pan.flags |= SHOW;

                       page3_pan.flags &= ~SHOW;

               }

               if ((player_pan.pos_x < 0) && (is(page1_pan, SHOW))) // trying to move outside the left level border?

               {

                       player_pan.pos_x = 0; // don't allow the player to do that!

               }

               if ((player_pan.pos_x > 750) && (is(page3_pan, SHOW))) // trying to move outside the right level border?

               {

                       player_pan.pos_x = 750; // don't allow the player to do that!

               }

               wait (1);

       }

}

 

Die obige Funktion kümmert sich um das Seiten-Scrolling indem sie den pos_x-Wert des Player-Panels überwacht. Wenn dieser Wert 750 Pixel überschreitet, was bedeutet, dass der Player dem rechten Rand des Raumes nahegekommen ist, bewegt sie den Player auf die rechte Seite des Bildschirms, versteckt das gegenwärtige Panel und macht ein neues Panel sichtbar. In ähnlicher Weise, nämlich wenn der Player versucht, über die linke Seite des Raumes zu entkommen (der pos_x-Wert des Players ist kleiner als Null), wird der Player auf die rechte Bildschirmseite bewegt und ein neues Panel wird dargestellt. Die letzten paar Zeilen verweigern es dem Player, am Anfang aus dem Bildschirm zu laufen (die linke Seite von room1) und ebenso am Ende des Levels (die rechte Seite von room3).

 

Das ist schon ein gutes Stück des Codes für Seiten-scrollende Welten wenn der Player verschiedene Räume erkunden soll. Aber wie erstellen wir eine sanft scrollende Seite ganz so wie in... sagen wir mal Mario-ähnlichen Games? Ich habe gewußt, dass Sie diese Frage stellen werden, also starten Sie pagescrolling2.c.

 

aum85_workshop4

 

Sieht aus wie das erste Demo. Aber wenn Sie den Player jetzt in Richtung rechte Bildschirmseite bewegen, werden Sie bemerken, dass, sowie er sich dem rechten Rand des Bildschirms nähert, der gesamte Hintergrund anfängt nach links zu scrollen.

 

aum85_workshop5

 

Gehen Sie weiter nach rechts und sie werden auch den dritten Raum sehen:

 

aum85_workshop6

 

Es ist klar, dass die Bitmaps, die für diese sanft, kontinuierlich scrollenden "Räume" benutzt werden, perfekt aneinander passen müssen. Andernfalls sehen Sie diese hässlichen Grenzen dort, wo die Panels aufeinander treffen. Bewegen Sie den Player in Richtung der linken Bildschirmseite - das Scrolling funktioniert auch in die entgegengesetzte Richtung. Werfen Sie einen Blick auf die in der oberen rechten Ecke angezeigte Zahl. Sie zeigt den Offset-Wert, der für all diese Scroll-Panels (Hintergründe) gilt.

 

Zeit, den Code für die Datei pagescrolling2.c zu untersuchen:

 

var offset_x = 0;

 

VECTOR player_speed;

 

PANEL* player_pan;

 

PANEL* page1_pan =

{        

       pos_x = 0;

       pos_y = 0;

       bmap = "page1.pcx";

       flags = SHOW;

}

 

PANEL* page2_pan =

{        

       pos_x = 0;

       pos_y = 0;

       bmap = "page2.pcx";

       flags = SHOW;

}

 

PANEL* page3_pan =

{        

       pos_x = 0;

       pos_y = 0;

       bmap = "page3.pcx";

       flags = SHOW;

}

 

Soweit nichts Neues. Wir definieren eine Variable, einen Vektor, einen Panel-Pointer und die Panels, die für unsere virtuellen, sanft scrollenden Räume gebraucht werden.

 

function main()

{

       fps_max = 60;

       video_mode = 7; // 800x600 pixels

       video_screen = 1; // start in full screen mode

}

 

function player_startup()

{

       var horizontal_speed = 0;

       player_pan = pan_create("bmap = player.png; NULL;", 150);

       player_pan.pos_x = 380;

       player_pan.pos_y = 510;

       player_pan.flags |= VISIBLE;

       player_pan.center_x = player_pan.size_x * 0.5;

       player_pan.center_y = player_pan.size_y;

       while (1)

       {

               vec_set(player_speed.x, accelerate (horizontal_speed, 6 * (key_cur - key_cul), 0.5));

               if ((player_pan.pos_x > 100) && (player_pan.pos_x < 650))

               {

                               player_pan.pos_x += player_speed.x;

                               player_pan.pos_x = clamp(player_pan.pos_x, 101, 649);

               }

               if ((player_pan.pos_x == 101) || (player_pan.pos_x == 649))

               {

                       if (key_cul + key_cur)

                       {

                               offset_x -= player_speed.x;

                       }

               }

               if (key_cul + key_cur)

               {

                       player_pan.angle += 0.2 * sin(40 * total_ticks);

               }

               else

               {

                       player_pan.angle = 0;

               }

               player_pan.pos_x = clamp(player_pan.pos_x, 0, 750); // don't allow the player to get out of the screen borders

               offset_x = clamp(offset_x, -1600, 0);

               wait (1);

       }

}

 

Die StartUp-Funktion des Players erstellt das Panel, das für den Player benutzt werden wird und setzt es wie im vorigen Demo ein. Die "while (1)"-Schleife funktioniert jedoch anders. Ist die pos_x des Players größer als 100 Pixel und kleiner als 650 Pixel (der Player ist von den Bildschirmgrenzen entfernt), kann er sich frei bewegen und sein pos_x-Wert wird auf das Intervall von 101...649 Pixel begrenzt. Ist pos_x gleich 101 (der Player ist der linken Bildschirmseite nahe gekommen) oder pos_x ist gleich 649 (der Player ist der rechten Bildschirmseite nahe gekommen) und einer der links- / rechts-Pfeiltasten ist gedrückt, wird sich der Player gar nicht mehr bewegen - stattdessen wird der Hintergrund durch Ändern seines offset_x-Wertes bewegt!

 

Das bedeutet, dass sich das Player-Panel, sobald es einer der Bildschirmgrenzen nahe kommt, aufhört sich zu bewegen. Da sich nun der Hintergrund in die Gegenrichtung bewegt, denkt der Player aber trotzdem, dass sich sein / ihr Charakter weiterbewegt. Die Animation läuft zu jeder Zeit vorausgesetzt, eine der beiden rechts- / links-Pfeiltasten bleibt gedrückt. Auf diese Weise kann der Player-Charakter sich frei bewegen solange er von den Bildschirmgrenzen entfernt ist und läßt den Hintergrund scrollen und neue Bereiche des Levels enthüllen sobald er den Bildschirmgrenzen näher kommt.

 

Die letzten beiden Codezeilen innerhalb der "while (1)"-Schleife machen es dem Player unmöglich, ausserhalb der Bildschirmgrenzen zu geraten und verbieten es den Panels zu sehr zu scrollen (-1600... 0 ist der passende Bereich für offset_x - Sie sehen gleich warum).

 

function panels_startup()

{

       while (1)

       {

               page1_pan.pos_x = offset_x;

               page2_pan.pos_x = page1_pan.pos_x + 800;

               page3_pan.pos_x = page2_pan.pos_x + 800;

               wait (1);

       }

}

 

Die letzte Funktion, die unsere Aufmerksamkeit verdient, ist eine Kleine. Sie hält die Panels aneinander fest indem sie 800 Pixel auf die vorangegangenen Panels aufaddiert (die Bitmaps, die für die Panels benutzt werden, haben 800x600 Pixel). Das bedeutet, dass wenn sich offset_x ändert (Sie erinnern sich an die Zahlen in der oberen, rechten Ecke des Bildschirms?), werden alle Panels gleichzeitig bewegt und erzeugen so eine sanft seitlich scrollende, nahtlose Welt. Nun, es wird nur dann eine nahtlose Welt sein wenn Ihre Panels schön aneinanderpassen - dafür zu sorgen, ist Ihr Job! Hierbei könnte das "clone brush"-Tool Ihrer Malanwendung zu Ihrem besten Freund werden ;)

 

Das ist alles für heute! Vergessen Sie nicht, sich das "Plug and Play"-Kapitel des Magazins anzuschauen. Es zeigt ein hübsches, voll funktionierendes 2D-Game.