Cutscene Kamera code

So funktioniert es: sie drücken R (record) und bewegen die camera um den Spieler (oder woimmer sie hin möchten), die ganze Zeit werden die Koordinaten der Camera (x,y,z,pan,tilt und roll) in einem riesigen Array gespeichert. Drücken sie nochmal R und die Aufzeichnung wird beendet - eine kleine Datei (cutdata.txt) wird auf ihre Festplatte gespeichert. Jetzt können sie diese laden und abspielen wann immer sie wollen. Lassen sie uns einen Block auf den Code werfen:

view cutscene_camera{}
var start_pos[6];

action cutscene_on
{
    start_pos[0] = my.x;
    start_pos[1] = my.y;
    start_pos[2] = my.z;
    start_pos[3] = my.pan;
    start_pos[4] = my.tilt;
    start_pos[5] = my.roll;

    waitt (64);

    camera.visible = off;
    cutscene_camera.size_x = screen_size.x;
    cutscene_camera.size_y = screen_size.y;
    cutscene_camera.pos_x = 0;
    cutscene_camera.pos_y = 0;
    cutscene_camera.x = my.x;
    cutscene_camera.y = my.y;
    cutscene_camera.z = my.z;
    cutscene_camera.visible = on;
    on_mouse_right = null;
    while (1)
    {
       cutscene_camera.x += 30 * cos(cutscene_camera.pan) * (mouse_right - mouse_left) * time;
       cutscene_camera.y += 30 * sin(cutscene_camera.pan) * (mouse_right - mouse_left) * time;
       cutscene_camera.z += 100 * sin(cutscene_camera.tilt) * (mouse_right - mouse_left) * time;
       cutscene_camera.pan -= 20 * (mouse_force.x) * time;
       cutscene_camera.tilt += 25 * (mouse_force.y) * time;
       if (key_r == 1 && index == 0) // if we press r and we aren't recording already
       {
           record_data();
       }
       if (key_p == 1) // if we press p
       {
            play_data();
       }
       wait (1);
   }
}

Als erstes müssen sie eine Entity im Level platzieren und ihr die Aktion cutscene_on zuweisen; ihre Position sollte nahe an der letztendlichen Cutscene Position liegen. Wir speichern die anfängliche Position (x,y,z,pan,tilt und roll) in start_pos[6] und dann warten wir 4 Sekunden um sicher zu gehen das der Splashscreen verschwunden ist. Ich habe einen neuen View mit dem Namen cutscene_camera hinzugefügt der den alten view (camera) ersetzen soll. Der neue cutscene_camer View wird mit Hilfe der Maus und ihrer Tasten bewegt (inklusive der rechten Maustaste) also musste ich alle Rechtsklickaktionen entfernen. Der Code der die cutscene_camera bewegt ist Simpel (werfen sie einen Blick auf die Kameras im AUM 4 - ich habe dort einen ähnlichen Code). Sie wundern sich vielleicht was es mit dem (mouse_right - mouse_left) auf sich hat. Wenn wir die rechte Maustaste drücken, mouse_right = 1 wird sich die Kamera nach hinten bewegen und wenn wir die linke Maustaste drücken, mouse_left = 1 wird sich die Kamera nach vorne bewegen. Wenn beide Tasten gedrückt werden wird sich die Kamera nicht bewegen da mouse_right - mouse_left = 0 (das passiert auch wenn keine Taste gedrückt ist).

if (key_r == 1 && index == 0)
{
     record_data();
}
if (key_p == 1)
{
     play_data();
}

Wenn wir R drücken und nicht schon aufgenommen wird, wird die Aktion record_data aufgerufen. Wir müssen P drücken um die zuletzt gespeicherten Daten zu laden und abzuspielen.

Die Funktion record_data speichert die Koordinaten der Kamera in ein Array und speichert diese in die Datei welche dieses beinhaltet auf der Festplatte.

var cutscene_position[60000];

function record_data()
{
    index = 0;
    while (index < 60000)
    {
        cutscene_position[index] = 0;
        index += 1;
    }
    index = 0;
    while (key_r == 0 && index < 59994)
   {
        cutscene_position[index+0] = cutscene_camera.x;
        cutscene_position[index+1] = cutscene_camera.y;
        cutscene_position[index+2] = cutscene_camera.z;
        cutscene_position[index+3] = cutscene_camera.pan;
        cutscene_position[index+4] = cutscene_camera.tilt;
        cutscene_position[index+5] = cutscene_camera.roll;
        index += 6;
        wait (1);
   }
   filehandle = file_open_write("cutdata.txt");
   temp = 0;
   while (temp <= index)
   {
       file_var_write(filehandle, cutscene_position[temp]);
       temp += 1;
   }
   file_close(filehandle);
   beep;
}

Als erstes löschen wir den Inhalt des Arrays um sicher zu gehen das es keine Daten der letzten Aufnahme mehr beinhaltet. Ich habe ein Array mit 60.000 Elementen benutzt, wir nehmen 6 davon in jedem Frame (x,y,z,pan,tilt und roll) das reicht also für 10.000 Frames, sogar wenn das Spiel mit 100 FPS läuft reicht dies für 100 Sekunden (erhöhen sie die Anzahl der Elemente nach ihren Bedürfnissen).

Die Aufnahme wird gestoppt indem sie wieder R drücken oder wenn das Array voll ist. Der erste Befehl nachdem die While-Schleife gestartet wurde ist die Datei cutdata.txt zu öffnen (oder sie zu erstellen und zu öffnen falls diese noch nicht existierte). Die Daten der cutscene_camera Aktion sind hier gespeichert. Am Ende verdeutlicht uns ein Beep das die Aufnahme fertig ist.

Die letzte Funktion öffnet die Datei cutdata.txt, liest seinen Inhalt und stellt die Position der cutscene_camera jedes Frame wieder her:

function play_data()
{
    filehandle = file_open_read("cutdata.txt");
    index = 0;
    temp = 0;
    while (key_l == 0 || temp < 59994)
    {
         cutscene_camera.x = file_var_read(filehandle);
         cutscene_camera.y = file_var_read(filehandle);
         cutscene_camera.z = file_var_read(filehandle);
         cutscene_camera.pan = file_var_read(filehandle);
         cutscene_camera.tilt = file_var_read(filehandle);
         cutscene_camera.roll = file_var_read(filehandle);
         if (cutscene_camera.x + cutscene_camera.y + cutscene_camera.z + cutscene_camera.pan + cutscene_camera.tilt + cutscene_camera.roll == 0)
         {
              index = 0;
              cutscene_camera.x = start_pos[0];
              cutscene_camera.y = start_pos[1];
              cutscene_camera.z = start_pos[2];
              cutscene_camera.pan = start_pos[3];
              cutscene_camera.tilt = start_pos[4];
              cutscene_camera.roll = start_pos[5];
              return;
         }
         temp += 1;
         wait (1);
     }
}

Die Kamera stoppt wenn wir das Ende der Datei erreicht haben (temp > 59994) oder wenn wir die ersten Null-Elemente im Array gefunden werden (werfen sie einen Blick auf die If-Verzweigungen), nun wird die Kamera in ihre ursprüngliche Position zurückversetzt. Es gibt zwei kleine Panels für das Aufnehmen (rot) und für das Abspielen (grün).

 

Tasten neu belegen
 
Die Möglichkeit Tasten neu zu belegen kann sowohl in A4 als auch in A5 implentiert werden, aber mit A5 ist dies viel einfacher. Ich habe ein kleines Stand-Alone Beispiel erstellt welches eine wmb Box durch ein kleines Level bewegt, sie können die Bewegungstasten durch ein klick auf ein Panel jederzeit ändern.

Als erstes werden wir einige Strings, Variablen, ein Panel und einen Text definieren:

string empty_str, "          ";
string up_str, "Move up";
string down_str, "Move down";
string left_str, "Move left";
string right_str, "Move right";
var left_key;
var right_key;
var up_key;
var down_key;
entity* player;

panel redefine_pan
{
   bmap redefine_map;
   pos_x = 510;
   pos_y = 10;
   flags = refresh, overlay, visible;
   on_click = change_keys();
}

text redefine_txt
{
   pos_x = 10;
   pos_y = 10;
   font = comic_font;
   string = empty_str;
}

Die main Funktion ist ziemlich simpel:

function main()
{
    fps_max = 50; 
    d3d_panels = on; 
    load_level (<redeftst.wmb>);
    wait (2);
    camera.x = 0;
    camera.y = 0;
    camera.z = 490;
    camera.tilt = -90; 
    mouse_map = pointer_map;
    mouse_mode = 2;
    while(1) 
    {
        mouse_pos.x = pointer.x;
        mouse_pos.y = pointer.y;
        wait(1);
    }

}

Wir setzen die Kameraposition und -winkel, danach setzen wir den Mauscursor und machen in sichtbar (mouse_mode = 2) die Funktion main endet mit einem Code der die Maus bewegt. Die Aktion welche zu dem Spieler referiert ist eine einzige Zeile:

action set_player
{
 player = me; 
}
 
Jedes Mal wenn wir auf den redefine_pan Panel klicken wird die Funktion change_keys aufgerufen:

function change_keys()
{
     redefine_txt.visible = on;

     redefine_txt.string = up_str;
     while (key_any == 0) {wait(1);}
     while (key_any == 1) {wait(1);}
     up_key = key_lastpressed;
     key_set(up_key, move_up);

     redefine_txt.string = down_str;
     while (key_any == 0) {wait(1);}
     while (key_any == 1) {wait(1);}
     down_key = key_lastpressed;
     key_set(down_key, move_down);
 
     redefine_txt.string = left_str;
     while (key_any == 0) {wait(1);}
     while (key_any == 1) {wait(1);}
     left_key = key_lastpressed;
     key_set(left_key, move_left);

     redefine_txt.string = right_str;
     while (key_any == 0) {wait(1);}
     while (key_any == 1) {wait(1);}
     right_key = key_lastpressed;
     key_set(right_key, move_right);

     redefine_txt.visible = off;
}
 
Lassen sie uns einen Blick auf den Code für "Nach oben bewegen" werfen - die anderen Codes sind alle ziemlich ähnlich:

redefine_txt.visible = on;
sie machen den Text sichtbar

redefine_txt.string = up_str;
zeigen den "Nach oben bewegen" String

while (key_any == 0) {wait(1);}
warten bis eine Taste gedrückt wird

while (key_any == 1) {wait(1);}
warten bis sie losgelassen wird

up_key = key_lastpressed;
speichern die zuletzt gedrückte Taste in der up_key Variable

key_set(up_key, move_up);
und teilt die Funktion move_up der Taste zu

Ich habe eine simple move_up Funktion benutzt, ohne Kollisionserkennung. Sie wollen so eine Funktion sicherlich nicht in ihrem Spiel verwenden.

function move_up()
{
     while (key_pressed(up_key) == 1)
     {
          player.x += 10 * time;
          wait (1);
     }
}

Solange die Taste die in up_key gespeichert wurde gedrückt wird, bewegt sich der Spieler (die Box) nach oben. Die Funktionen welche die Box nach unten, nach links und nach rechts sind ähnlich.