Unbegrenze Level

Dieser Artikel handelt davon, ein Level zu erstellen, das nie endet. Naja, man kann das Spiel natürlich jederzeit beenden, aber es kann auch ewig weitergehen, wenn Sie möchten. Das System wird “treadmill” genannt und so funktioniert es:

- Wir erstellen ein Level mit 9 Prefabs, die so angeordnet werden, wie es das Bild zeigt. Jedes Prefab hat eine andere Textur (ich habe sie “one” bis “nine” genannt) und in meiner Demo wird die entsprechende Zahl auf der Textur selbst angezeigt, damit Sie erkennen, wie der Effekt funktioniert. Beachten Sie bitte, dass die grünen Quadrate und Zahlen normalerweise nicht Teil des Levels sind, die habe ich eingefügt:

- Wir plazieren den Spieler (in meinem Beispiel ein Auto-Model) in der Mitte (in meinem Fall in Prefab 5).

- Der Code erledigt den Rest. :)

Wenn Sie ein neues Level erstellen, sollte die Map mindestens einen Block enthalten, sonst wird die Engine einen Fehler melden.

Sehen wir uns den Code an:

function main()
{
level_load(start_wmb);
fps_max = 60;
}

entity* tile1;
entity* tile2;
entity* tile3;
entity* tile4;
entity* tile5;
entity* tile6;
entity* tile7;
entity* tile8;
entity* tile9;

action tile_1 // just name these prefabs
{
tile1 = me;
}

..................

action tile_9
{
tile9 = me;
}

Die main Funktion ist das Übliche. Jede Sektion hat eine Action, die dem Prefab einen sinnvollen Namen gibt (tile1 bis tile9).

action car
{
var car_speed;
while ((tile1 == null) || (tile1 == null) || (tile3 == null) || (tile4 == null) || (tile5 == null) || (tile6 == null) || (tile7 == null) || (tile8 == null) || (tile9 == null)) {wait (1);}
player = me;
while (1)
{
if(car_speed != 0) // can't rotate the car if it isn't moving
{
my.pan -= 0.2 * key_force.x * car_speed * time;
}
car_speed = 3 * key_force.y * time + max (1 - time * 0.2, 0) * car_speed;
ent_move (car_speed, nullvector);
if (key_t == 0) // normal 3rd person camera view
{
camera.x = player.x - 300 * cos(player.pan);
camera.y = player.y - 300 * sin(player.pan);
camera.z = player.z + 100;
camera.pan += 0.2 * ang (player.pan - camera.pan);
camera.tilt = -10;
}
else // press and hold "T" to get a top view
{
camera.x = player.x;
camera.y = player.y;
camera.z = 8000;
camera.pan = player.pan;
camera.tilt = -90;
}
if (total_frames % 31) // trace twice a second, starting with the 1st frame
{
trace_below(); // trace the name of the texture below the car
}
wait (1);
}
}

Diese Action wird dem Spieler (also dem Auto) zugewiesen; sie wartet bis die 9 Teile des Levels geladen wurden und erlaubt dann die Kontrolle des Fahrzeugs mit Hilfe der Pfeiltasten. Meine Action ist sehr simpel gestrickt, weil ich wollte, dass Sie schnell umherfahren und sich umsehen können; für Ihr eigenes Projekt sollten Sie lieber Ihre Player Action nehmen. Mit der Shift Taste können Sie die Geschwindigkeit übrigens verdoppeln.

Die Action hat auch 2 Kamerasichten: eine isometrische Sicht und eine Sicht von oben. Drücken und halten Sie die “T”-Taste, um alles aus der Vogelperspektive zu betrachten.

Die obige Action ruft die Funktion “trace_below” zwei Mal pro Sekunde auf:

function trace_below()
{
vec_set(temp.x, player.x);
temp.z -= 10000; // trace 10,000 quants below the car
trace_mode = ignore_me + ignore_passable + ignore_models + ignore_sprites + scan_texture;
trace (player.x, temp);
if (str_cmpi ("one", tex_name)) // if the texture below the car is named "one" in wad
{
tile2.x = tile1.x;
tile2.y = tile1.y - 2048;
tile3.x = tile1.x - 2048;
tile3.y = tile1.y - 2048;
tile4.x = tile1.x + 2048;
tile4.y = tile1.y;
tile5.x = tile1.x + 2048;
tile5.y = tile1.y - 2048;
tile6.x = tile1.x - 2048;
tile6.y = tile1.y;
tile7.x = tile1.x + 2048;
tile7.y = tile1.y + 2048;
tile8.x = tile1.x;
tile8.y = tile1.y + 2048;
tile9.x = tile1.x - 2048;
tile9.y = tile1.y + 2048;
}
.....................
if (str_cmpi ("nine", tex_name)) // if the texture below the car is named "nine" in wad
{
tile1.x = tile9.x + 2048;
tile1.y = tile9.y - 2048;
tile2.x = tile9.x;
tile2.y = tile9.y - 2048;
tile3.x = tile9.x - 2048;
tile3.y = tile9.y - 2048;
tile4.x = tile9.x + 2048;
tile4.y = tile9.y;
tile5.x = tile9.x - 2048;
tile5.y = tile9.y + 2048;
tile6.x = tile9.x - 2048;
tile6.y = tile9.y;
tile7.x = tile9.x + 2048;
tile7.y = tile9.y + 2048;
tile8.x = tile9.x;
tile8.y = tile9.y + 2048;
}
}

Diese Funktion leistet die ganze harte Arbeit, glauben Sie mir! Es wird ein trace zwischen dem Spieler und einem Punkt ausgeführt, der 10.000 Quants tiefer liegt, der den Namen der Textur zurückliefert, die gefunden wurde. Falls dieser Name “one” ist, fährt der Spieler gerade auf dem ersten Prefab, also werden einige der Prefabs hinter dem Spieler so umgeordnet, dass genug Platz bleibt. Jedes Prefab hat eine Größe von 2048 mal 2048 Quants, also müssen sie um Vielfache davon bewegt werdne, um nahtlos aneinanderzuliegen. Das wird für alle 9 Prefabs ausgeführt und der Code ordnet die Prefabs jedes Mal so um, dass die Illusion (oder Realität?) eines nie endenden Levels erzeugt wird. Wenn Sie verstehen wollen, wie alles funktioniert, starten Sie das Level, drücken und halten Sie die “T”-Taste und fahren Sie mit den Pfeiltasten herum.

Der Spieler startet im Segment 5 und hier sehen Sie, was geschieht, wenn er auf in eine benachbarte Region fährt:

Sind Sie etwas verwirrt? Schauen wir uns das Beispiel im ersten Bild an. Der Spieler ist im 5. Segment und fährt irgendwann auf das erste. In diesem Moment werden die Segmente in seinem Rücken (3, 6, 9, 8 und 7), die er nicht sieht, vor ihn bewegt – das sind die roten Quadrate. Das heißt, der Spieler wird nicht sehen, was vor sich geht und wir erhalten, was wir wollen – ein unendliches Level. Was geschieht, wenn der Spieler zurück auf das 5. Segment fährt? Nichts Besonderes, die Teile werden wieder zurückbewegt.

Moment noch, ich habe noch zwei weitere Tricks:

action sky_sphere
{
my.passable = on;
while (player == null) {wait (1);}
while (1)
{
my.x = player.x;
my.y = player.y;
wait (1);
}
}

Die erste Idee besteht darin, eine große Sky Sphere zu nehmen, die sich mit dem Spieler bewegt und den Eindruck eines riesigen Levels vermittelt. Die passierbare Kugel wartet, bis der Spieler existiert und übernimmt dann seine Koordinaten in jedem Frame.

function toggle_fog() // toggles fog if you press the "F" key
{
fog_color = (fog_color == 0); // set fog_color to 0 (no fog) or 1
camera.fog_start = 500; // the fog starts at 500 quants
camera.fog_end = 2500; // and ends at 2500 quants
}

on_f toggle_fog;

Der zweite Trick besteht darin, Nebel zu benutzen; der Nebel ist Ihr Freund, weil er die Übergänge verbirgt, die vor sich gehen. In meinem Beispiel kann mit Hilfe der "“"”Taste Nebel eingeschaltet werden. Falls Ihre Segmente größer sind als 2048 Quants (was sie sein sollten), können Sie dünneren Nebel verwenden (also einen größeren Wert für camera.fog_end) und bessere Ergebnisse erzielen:

Was kann man noch tun? Wir könnten Terrains für das Level benutzen, das aneinanderpaßt und / oder verschiedene Teile des Levels die gleichen Segmente benutzen lassen. Zurück zu unserem Beispiel.

Nehmen wir an, dass unser Auto auf dem ersten Segment steht und sich nach rechts bewegt, wie durch den gelben Pfeil angedeutet. Zu einem bestimmten Zeitpunkt wird dieses Segment nach 1’ bewegt, wo drei Bäume stehen (die blauen Punkte) und dann, wenn der Spieler weiterfährt, wird das Segment an die Position 1’’ bewegt, wo vier Bäume stehen. Diese Bäume wurden im WED auf die passende Höhe in die Luft gesetzt, aber wenn Segment 1 sich unter sie bewegt, sieht alles ganz natürlich aus. Sie können Bäume, Häuser etc. in Ihrem Level verwenden. Eine gute Design-Methode wäre es, das erste Segment ein paar Mal zu kopieren, alles zu plazieren und dann alle Segmente zu entfernen mit Ausnahme des Originals.