Feature des Monats: Kameras

Diesen Monat möchte ich Ihnen ein "Professional" Feature zeigen, das sehr nützlich ist, sowohl in Actionspielen, als auch in Sportspielen, Adventures, Strategiespielen... ich denke, jedes Spiel könnte eine Kamera gebrauchen. Acknex hat eine Menge verbessert und dies ist eines der neuen, heißen Features: die Fähigkeit, eine View auf ein Sprite zu rendern.

Praktischer Nutzen: lassen Sie das Footballspiel auf dem großen Screen anzeigen, werfen Sie ein Auge auf den Eingang Ihrer Festung, erstellen Sie Rückspiegel für Ihr Auto und vieles mehr!

Zunächst definieren wir eine View:

view remote
{
pos_x = 0;
pos_y = 0;
size_x = 128;
size_y = 64;
layer = 5;
flags = visible;
}

Wir müssen die x und y Größe auf die Größe des Sprites setzen (128 x 64 Pixel in meinem Beispiel). Ich habe den layer Wert auf 5 eingestellt, aber Sie können jeden kleinen Wert nehmen. Dies wird unser virtueller "Screen", aber wir brauchen noch eine Kamera, um zu sehen, was geschieht:

action camera1
{
my.invisible = on;
my.passable = on;
remote.x = my.x;
remote.y = my.y;
remote.x = my.x;
remote.pan = my.pan;
remote.tilt = my.tilt;
remote.roll = my.roll;
}

Wir können jedes Model für die Kamera benutzen: plazieren Sie diese in Wed, setzen Sie die Winkel und sie werden die View übertragen. Das sollte alles sein... fast, wir müssen noch das Bild auf einem Sprite anzeigen:

action monitor
{
my.oriented = on; // oriented sprite
remote.bmap = bmap_for_entity (my, 0);
}

Ich benutze ein orientiertes Sprite; die View wird auf die Bitmap von "my" gerendert, also auf die Bitmap, die für das Sprite benutzt wird, zu dem die Action gehört.

Blutlache

Dieser Code wird Ihnen beibringen, wie Sie Ihre Gegner bluten lassen können, wenn sie sterben. Ich habe ihn so leicht wie möglich gehalten:

define number_of_hits skill1;

action enemy_blood
{
var blood_coords; // local var
my.enable_entity = on;
my.enable_impact = on;
my.event = enemy_hit;
my.number_of_hits = 0;
while(my.number_of_hits == 0) // standing
{
ent_cycle("stand", my.skill20); // play "stand" animation
my.skill20 += 3 * time;
my.skill20 %= 100; // loop
wait (1);
}

Ich habe zunächst eine lokale Variable namens blood_coords definiert. Ich weiß, Sie trauen sich nicht zu fragen und daher werde ich gleich hier und jetzt erklären, was es mit diesen lokalen und globalen Variablen auf sich hat. Eine globale Variable ist außerhalb jeder Action oder Function definiert - sie wird nicht von geschweiften Klammern eingeschlossen. Auf eine globale Variable kann jede andere Function oder Action zugreifen. Es ist gut zu wissen, dass Sie "ammo1 += 100;" in die Konsole tippen können und 100 Kugeln für die Waffe erhalten, die ammo1 benutzt, richtig? Eine lokale Variable wird genauso definiert wie eine globale, aber diese Definition ist innerhalb einer Action oder Function, wie die in der Action enemy_blood. Eine lokale Variable ist nur innerhalb derjenigen Function oder Action bekannt, in der die Definition steht. Wenn Sie "blood_coords.x += 100;" in die Konsole tippen würde das nicht funktionieren. Lokale Variablen sind wie Entity Skills: Sie können sie nur in der Action oder Function nutzen, in der sie definiert sind. Also, zurück an die Arbeit. Die lokale Variable blood_coors wird auf die Stelle gesetzt, an der die Blutlache entstehen soll. Ich hätte eine globale Variable nehmen können, aber falls Sie mehreren Models diese Action geben, hätte jedes Model die gleiche globale Variable manipuliert, da alle darauf zugreifen können. Die lokale Variable blood_coords wird nur von ihrer eigenen Action bzw. Function erkannt, also wird der blood_coords Wert für einen der Feinde nicht mit dem für einen anderen Feind in Konflikt geraten.

Der Feind reagiert auf impact; schießen Sie auf ihn, um das enemy_hit Event auszulösen. Ich habe number_of_hits als einen Namen für Skill1 benutzt; solange diese Zahl 0 ist, wird der Feind seine "Stand" Animation in einer Schleife ausführen.

// the enemy was hit by a rocket - it must die
my.skill20 = 0;
while(my.skill20 < 60) // one shot animation, 60% of "death" because the last "death" frame is damaged - open the model in Med to see for yourself
{
ent_cycle("death", my.skill20); // play "death" animation
my.skill20 += 2 * time;
wait (1);
}
my.event = null; // don't react to other events from now on
// the enemy is dead here - time to create the blood pool
vec_set(blood_coords, my.x);
blood_coords.z -= 500;
trace_mode = ignore_me + ignore_models + ignore_sprites;
blood_coords.z = my.z - trace (my.x, blood_coords) + 2; // place the blood sprite 2 quants above the ground
ent_create(blood_pcx, blood_coords, create_blood);
}
Wenn number_of_hits größer als 0 ist, stirbt der Gegner; wir spielen seine "Death" Animation (nur 60% dieser Frames, weil das letzte Death Frame beschädigt ist - schauen Sie sich das Model in MED an, um es zu sehen). Wir setzen event auf null, tracen 500 Quants nach unten, um den Boden zu finden, setzen blood_coords.z zwei Quants über den Boden und erstellen das Blut Sprite mit Hilfe der Funktion create_blood:

function create_blood()
{
my.passable = on;
my.oriented = on;
my.tilt = 90;
my.flare = on;
my.ambient = 100;
my.bright = on;
while (my.scale_x < 5)
{
my.scale_x += 0.05 * time;
my.scale_y = my.scale_x;
wait (1);
}
}

Das Sprite ist passable, oriented und hat die Flags bright und flare gesetzt. Es wird seine Größe in x und y Richtung fünfmal erhöhen.

Die Funktion, die all dies auslöst ist:

function enemy_hit()
{
if (event_type == event_entity || event_type == event_impact)
{
if (you == player) // collided with the player?
{
return; // do nothing
}
else // hit by a rocket
{
my.number_of_hits += 1;
}
}
// add other events here
}

Wenn der Gegner mit einer Entity zusammengestoßen ist, prüft es ob es der Spieler war. Wenn der Gegner von einer Rakete getroffen wurde, wird number_of_hits erhöht und der Gegner stirbt.