Planet Survivors

In diesem Monat habe ich alle Level zusammengenommen, damit sie in der korrekten Reihenfolge gespielt werden können, habe noch Code hinzugefügt, der dafür sorgt, dass das Zusammenspiel funktioniert und noch einige Bugs behoben. Es gibt eine Menge neuen Code, aber sehen wir uns die Gameplay-bezogenen Elemente an.

Die Action beginnt mit einem 3D Weltraum-Shooter, in dem Sie Asteroiden zerstören müssen:

Nach ein paar Minuten landet das Schiff auf einer Plattform:

Der Spieler muß nun ein kleines Logikrätsel lösen, um weiterzukommen, er muß 3 Zeilen oder Spalten mit identischen Farben erzeugen.

Falls der Spieler die Aufgabe löst, erhält er Munition und Schildenergie und das Schiff hebt wieder ab:

Diesmal ist es ein 2D-Ballerspiel aus der Vogelperspektive mit 3 verschiedenen Gegnern und einem Endgegner am Ende des Levels:

Danach gerät der Spieler in ein Feld unzerstörbarer Asteroiden, so dass das Schiff stark beschädigt wird:

Danach gibt es eine Bruchlandung auf einem Planeten:

Der Spieler kann aus dem Schiff entkommen, schnappt sich ein Gewehr und bereitet sich auf zwei neue Gegnertypen vor: grüne Riesenameisen und einige außerirdische Raketenwerfer:

Der Spieler findet ein neues Schiff und hebt ab, womit das Spiel endet. Im Shooter-Level kann der Spieler fliegen, wenn Sie nach oben sehen, daher können Sie über die Hügel fliegen und das Level innerhalb von wenigen Minuten beenden (wenn Sie die Aliens töten).

Und nun beantworte ich die am häufigsten gestellte Frage: wie kann ich das Rätsel systematisch also nicht durch Ausprobieren lösen? Ich wende meine Lösung auf das Rätsel an, wie es im Spiel vorkommt, aber die Methode funktioniert mit jeder Ausgangsposition.

1) Erzeugen Sie zunächst ein 2 mal 2 Feld mit passenden Farben:

Die gute Nachricht ist, dass Sie von nun an nur noch mit den rot gekennzeichneten Feldern spielen müssen und Ihr Feld so lassen können:

Schauen wir uns die Farben der ersten beiden Zellen der oberen Zeile an: blau, gefolgt von grün. Daher muß die untere Reihe ebenfalls mit blau starten und mit grün weitergehen. Wir bringen das blaue Feld aus der unteren Reihe einen Schritt nach links:

Und nun bringen wir die grüne Zelle nach unten:

Wir haben jetzt die gleiche Sequenz (blau, grün) unten erzeugt, also schieben wir die Zellen nach links:

Fertig! Das Level ist gelöst und der Spieler kann weitermachen; wir haben zwei Zeilen angepaßt und die dritte Zeile damit automatisch auch. Vergessen Sie nicht, dass es mehr Munition und Schildenergie gibt, wenn Sie das Level schnell lösen. I nächsten Monat geht es um das Laden der Level und das Abspeichern.

###

Entities auf Schienen

Der Zweck dieses Artikels ist schnell erklärt: wir hätten gern Code für eine Entity, die “weiß”, wie man der Straße folgt. Sie können diesen Code für NPCs nutzen oder Fußgänger, die auf dem Bürgersteig gehen, für Züge und für vieles mehr. Schauen wir uns erst die Methode an und dann den Code, der sie umsetzt.

Wir haben ein blaues Fahrzeug und berechnen die Koordinaten zweier Punkte vor dem Model: front_left und front_right. Dann führen wir einmal pro Frame einen trace nach unten aus, um die Textur zu erfahren. Ist dies die Textur für unsere Straße / Schienen, dann geschieht nichts; andernfalls drehen wir das Fahrzeug bis der trace die korrekte Textur zurückliefert. Auf diese Weise bleibt das Fahrzeug auf dem korrekten Pfad, ohne das wir einen Pfad im WED definieren müssen. Falls Sie Fußgänger benutzen wollen, die auf dem Bürgersteig bleiben, aber keine komplexe KI programmieren wollen, dann ist dieser simple Code die Lösung für Sie.

var danger_zone = 0;

define none 0;
define left 1;
define right 2;

function main()
{
fps_max = 60;
level_load(level_wmb);
wait (3);
camera.x = -3500; // choose a convenient camera position
camera.y = -2100;
camera.z = 1000;
camera.pan = 31; // and angles
camera.tilt = -20;
}

Ich habe “none”, “left” und “right” als 0, 1 und 2 definiert. Die main Funktion lädt das Level und stellt eine geeignete Position für die Kamera ein.

action train
{
var train_speed;
var front_left;
var front_right;
while (1)
{
train_speed.x = 20 * time;
train_speed.y = 0;
train_speed.z = 0;
ent_move (train_speed, nullvector);
front_right.x = my.x + 400 * cos(my.pan) + 300 * sin(my.pan);
front_right.y = my.y + 400 * sin(my.pan) - 300 * cos(my.pan);
front_right.z = my.z;
vec_set (temp.x, front_right.x);
temp.z -= 1000; // trace 1000 quants below
trace_mode = ignore_me + ignore_passable + ignore_models + ignore_sprites + scan_texture;
trace (my.x, temp);
if ((str_cmpi ("metalplain4", tex_name) == 0) && (danger_zone == none)) // if the texture below the train isn't named "metalplain4"
{
danger_zone = right;
my.pan += 2 * time; // rotate the train toward left, play with this value
}
else
{
danger_zone = none;
}

Der Zug bewegt sich mit 20 * time Quants pro Frame. Front_right wird 400 Quants vor den Zug plaziert und 300 Quants zur Seite (im Verhältnis zum Origin). Wir tracen 1000 Quants nach unten und prüfen, ob die korrekte Textur darunterliegt(metalplain4 in meinem Beispiel) und ob danger_zone 0 ist oder nicht. Danger_zone ist eine Variable, die von der ersten “Antenne” gesetzt wird, die vom Pfad abkommt. Ist diese gleich 0 (none), ändern wir den Pan des Zuges und setzen danger_zone auf “right”; 2 * time gibt die Drehgeschwindigkeit, ändern Sie diesen Wert gegebenenfalls. Sobald der Zug (bzw. front_right!) wieder auf dem Pfad ist, wird danger_zone wieder auf none zurückgesetzt, damit front_left oder front_right im Notfall die Kontrolle übernehmen können.

front_left.x = my.x + 400 * cos(my.pan) - 300 * sin(my.pan);
front_left.y = my.y + 400 * sin(my.pan) + 300 * cos(my.pan);
front_left.z = my.z;
vec_set (temp.x, front_left.x);
temp.z -= 1000; // trace 1000 quants below
trace_mode = ignore_me + ignore_passable + ignore_models + ignore_sprites + scan_texture;
trace (my.x, temp);
if ((str_cmpi ("metalplain4", tex_name) == 0) && (danger_zone == none)) // if the texture below the train isn't named "metalplain4"
{
danger_zone = right;
my.pan -= 2 * time; // rotate the train toward right, play with this value
}
else
{
danger_zone = none;
}
wait (1);
}
}

Das Gleiche geschieht für front_left; das einzige, was Sie sich jetzt vielleicht fragen ist: wofür brauchen wir die danger_zone Variable? Die Antwort ist simpel: wir möchten nicht, dass front_left und front_right zur gleichen Zeit die Kontrolle übernehmen; die Variable stellt sicher, dass der Zug wieder zurück auf den Weg kommt, bevor sie andere Drehungen erlaubt.

Ich habe große Werte (400 und 300 Quants) für front_left und front_right benutzt, daher folgt der Zug dem Track eher auf einem Zickzack-Kurs. Für einen engeren Pfad müssen Sie diese Werte einfach reduzieren, insbesondere die 300.