workshop 21

Top  Zurück  Weiter

Workshop 21: Modelle. Animierte Modelle.

Wenn Sie vorhaben, ein Game zu erstellen, werden Sie für Ihre Fahrzeuge, Charaktere etc. Modelle verwenden wollen. Sie können Ihre Levels außerdem aber noch ein wenig aufpeppen indem Sie z. B. Modelle an die Wände hängen, so wie ich das mit dem Fackel-Modell gemacht habe:

w21_01

Um nicht animierte Modelle in Ihrem Game zu verwenden, brauchen Sie nun wahrlich kein Genie zu sein; mit WED's"Add model" laden sie solche Modelle einfach ins Level und schieben sie dann dahin, wo Sie sie haben wollen. Allerdings sieht so ein nicht flackernde Fackel stinklangweilig aus. Wie aber verwenden wir diese so prima aussehenden animierten Modelle? Es gibt zwei Typen von animierten Modellen:

1) Modelle, die Animationsframes verwenden (auch Vertex-Animationen genannt).

2) Modelle, die ein Skelett haben und also über Knochen animiert werden (Bones-Animation).

Der erste Modell-Typus wird, genauso wie ein Sprite, mithilfe von Frames animiert. Die Tatsache, dass ein Modell ein 3D-Objekt ist, sollte dabei allerdings nicht übersehen werden. Ich starte jetzt den kostenlosen Modell-Editoren, MED. Werfen wir einen Blick auf ein Modell, welches Animationsframes verwendet:

w21_02w21_03w21_04

w21_05w21_06w21_07

Die Animationen können sowohl als Schleife (für stehen, gehen, laufen usw.) als auch als One-Shot-Animationen (für Springen, Ducken etc.) abgespielt werden. Sie können für Ihre Modelle ruhig viele Frames benutzen, der von animierten Modellen benötigte Video-Speicher hängt nämlich hauptsächlich von der Größe seiner Skin ab; die Anzahl seiner Animationsframes hat, bis Sie einmal bei Hunderten von Animationsframes angekommen sind, dagegen nur wenig Einfluss.

Ein normales Modell hat verschiedene Animationen und in MED sehen die Frame-Namen so aus:

w21_08

Ok, MED stellt die verschiedenen Framebereiche nicht verschiedenfarbig dar (ich habe da mit einem Paintprogramm nachgeholfen) aber es ist mir wichtig, klarzumachen, dass jede Animation einen eigenen Namen haben sollte. Wenn Sie für ein Modell zum Beispiel verschiedene Sterbeanimationen ("death") haben, könnten Sie diese in etwa so benennen:

- deatha1... deatha30 (die erste "death"-Animation hat 30 Frames)

- deathb1... deathb5 (die zweite "death"-Animation hat 5 Frames)

- rip1... rip8 (die dritte "death"-Animation hat 8 Frames)

Damit versuche ich klarzumachen, dass der Name einer Animation nicht allzu wichtig ist, es aber ein ureigener Namen für jede einzelne Animation sein muss. Wie schreiben wir nun den Code, der diese Animationen anwendet? Starten Sie Lite-C, öffnen Sie workshop21 und starten Sie script21.c:

w21_09

Die Wache links spielt ihre "walk"-Animation ab, die auf der rechten Bildschirmseite hingegen macht gar nichts! Ok, warten wir noch ein paar Sekunden...

w21_10

Aha! Die Wache links führt eine Animationsschleife (walk) durch und die rechte Wache hat eine One-Shot-Animation abgespielt (death)! Untersuchen wir also die Skript-Datei:

///////////////////////////////
#include 
#include 

///////////////////////////////

var walk_percentage;
var death_percentage;

function main()
{
	video_mode = 7;
	level_load ("work21.wmb");
	wait (2); // warte, bis das Level geladen ist
	camera.z = 120; // wähle eine angenehme Höhe
	camera.tilt = -15; // und einen tilt-Winkel für die Kamera
}

action walking_guard()
{ 
	while (1) 
	{ 
		ent_animate(my,"walk",walk_percentage, ANM_CYCLE); // "walk" Animationsloop
		walk_percentage += 3 * time_step; // 3 = Animationsgeschwindigkeit für"walk"
		wait (1); 
	} 
} 

action dead_guard()
{ 
	wait (-5); // warte 5 Sekunden
	while (1) 
	{ 
		ent_animate(my, "death", death_percentage, 0); // "death" one-shot-Animation 
		death_percentage += 3 * time_step; // 2  = Animationsgeschwindigkeit für"death"
		wait (1); 
	} 
}
Ich mochte lite-C von Anfang an, denn mit einigen wenigen Code-Zeilen kann man eine Menge erreichen. Werfen Sie einen Blick auf die Aktion, die die gehende Wache animiert:

action walking_guard()
{
  while (1)
  {
    ent_animate(my, "walk", walk_percentage, ANM_CYCLE); // "walk"-Animationsschleife
   
walk_percentage += 3 * time_step; //3 = Animationsgeschwindigkeit für "walk"
   
wait (1);
  
}
}

Da unsere "walk"-Animation ständig laufen muss, verwenden wir eine while (1)-Schleife. Gehen wir zur nächsten Code-Zeile:

ent_animate(my, "walk", walk_percentage, ANM_CYCLE);

Diese Anweisung animiert die Entity "my" (die, der diese Aktion zugewiesen ist) und benutzt dazu ihre "walk"-Animationsschleife mit der durch die Variable namens walk_percentage vorgegebenen Geschwindigkeit und spielt die Animation aufgrund des anm_cycle-Parameters in einem Zyklus (einer Schleife) ab. Hier ist die allgemeine Formel der ent_animate-Anweisung:

ent_animate(entity_name, animation_name, animation_percentage, animation_mode);

- "entity" ist der Name der Entity, die animiert wird. "My" brauchen Sie hier nicht, wenn Sie nicht wollen. Definieren Sie zuerst einen ´pointer´ auf eine Entity und schon können Sie auch ihren Namen verwenden:

Beispiel:

ENTITY* kung_fu_master;
ent_animate(kung_fu_master, "rofl", masters_speed, ANM_CYCLE);

- "animation_name" bezeichnet den Namen der Animation aus MED (aber ohne die zu den Frames gehörigen Figuren). Denken Sie daran, den Animationsnamen in Anführungszeichen zu setzen, sonst bekommen Sie eine Fehlermeldung. Noch einmal: Sie können in MED irgendeinen beliebigen Namen für die Animation nehmen, aber auch in Ihrer Skriptdatei müssen Sie genau denselben Namen verwenden:

Bsp:: ent_animate(my, "smelling", nose_speed, ANM_CYCLE);

- "animation_percentage" stellt den Prozentsatz der Animation dar. Es ist eine einfache var, die, wenn Sie das Modell animieren wollen, ihren Wert ändern muss. Wenn animation_percentage 0 ist, stellt das Modell seinen ersten Animationsframe dar und ist animation_percentage = 100, wird das Modell seine letzte Animationsrate zeigen.

Unser Wache-Modell hat nur 4 Animationsframes fürs gehen (walk1... walk4) aber die Animation in unserem Demo sieht überhaupt nicht ruckelig aus! Wenn Sie einen Blick auf die Bilder unten werfen, werden Sie feststellen, dass es tatsächlich so aussieht, als hätte die Wache viel mehr Animationsframes! Dieses Feature nennt sich "smooth frame interpolation" und wird von Lite-C gemacht. Die Engine berechnet dabei Zwischen-Animationsframes, setzt sie zwischen die existierenden Frames und sorgt so dafür, dass die Animation, selbst wenn das Modell nur wenige Frames hat, sehr viel weicher aussieht

w21_12 w21_13 w21_14

w21_15 w21_16 w21_17

w21_18 w21_19 w21_20

w21_21 w21_22

Die Variable namens "walk_percentage" aus unserem Beispiel erhöht ständig ihren Wert und darum ist unser gehendes Modell animiert. Zum Erhöhen oder Verringern der Animationsgeschwindigkeit spielen Sie, wenn Sie wollen, ein wenig mit der "3".

- "animation_mode" sagt der Engine ob sie die Animation in einer Schleife (animation_mode == ANM_CYCLE) oder als One-Shot-Animation ((animation_mode = 0) abspielen soll. Wächst in einer zyklischen Animation der Wert von animation_percentage über 100, wird sie einfach wieder mit dem ersten Frame weitermachen, eine One-Shot-Animation wird dagegen mit dem letzten Frame aufhören.

Wenn Sie vorhaben Ihre Modelle mithilfe von Animationsframes zu animieren, ist das alles, was Sie über ent_animate wissen müssen. Zur Vertiefung des Ganzen werfen wir nun aber noch einen Blick auf die Aktion, die dem Modell mit der One-Shot-Sterbeanimation zugewiesen ist:

action dead_guard()
{
   wait (-5); // warte für 5 Sekunden
  
while (1)
  {
    ent_animate(my, "death", death_percentage, 0); // "death" one-shot-Animation
   
death_percentage += 2 * time_step; // 2 = Animationsgeschwindigkeit für "death"
   
wait (1);
  
}
}

Der Sterbe-Kerl wartet 5 Sekunden bevor die Animation startet. Beim Aufruf von wait() mit einem negativen Parameter wartet die Engine wie Sie wissen, die angegebene Anzahl von Sekunden anstelle von Framezyklen. Benutzen etwas in der Art von wait (10);, um kürzere Wartepausen zu haben (in meinem Beispiel 10 Frames).

Die ent_animate-Zeile spielt die death-Animation mithilfe der Variablen death_percentage ab. Da animation_mode auf Null gesetzt ist, handelt es sich um eine One-Shot-Animation. Wollen Sie die Animationsgeschwindigkeit erhöhen oder verringern, spielen Sie ein wenig mit der "2" herum.

Ich habe für die sterbende Wache eine while (1)-Schleife genommen. Diese Schleife wird weiterlaufen auch wenn das Modell sein letztes "death"-Animationsframe abgespielt hat und macht weiter nichts, als ein wenig CPU-Leistung zu vergeuden. Eine etwas elegantere Version der Aktion sieht so aus:

action dead_guard()
{
   wait (-5); //warte für 5 Sekunden
  
while (death_percentage <= 100) // death_percentage geht hier nur von 0 bis 100
  
{
    ent_animate(my, "death", death_percentage, 0); // "death" one-shot-Animation
   
death_percentage += 2 * time_step; // 2 = Animationsgeschwindigkeit für "death"
   
wait (1);
   
}
}

Die obige while-Schleife läuft solange death_percentage kleiner als oder gleich groß wie 100 ist und stoppt sobald death_percentage größer als 100 ist (das letzte "death"-frame ist abgespielt) und gestattet der CPU, diese (nun nutzlose) while-Schleife zu vergessen.

Haben Sie unsere kleine Hausaufgabe vermisst? Haben Sie tatsächlich? Na dann versuchen Sie doch, eine einfache Aktion für ein mit der "walk"-Animation animiertes Modell zu erstellen, das sich gleichzeitig mithilfe von "c_move" bewegt. Benutzen Sie die Aktion walking_guard als Grundlage (die "walk"-Animation ist darin bereits als Schleife definiert) und fügen Sie dann innerhalb der while(1)-Schleife eine einzige Zeile ein in der "c_move" verwendet wird.

Lösung: fügen Sie die Codezeile in die Aktion walking_guard ein:

action walking_guard()
{
  while (1)
 {
  c_move (me, vector(2 * time_step, 0, 0), nullvector, GLIDE);
  ent_animate(me, "walk", walk_percentage, ANM_CYCLE); // "walk" Animations-Loop
  
walk_percentage += 3 * time_step; // 3 = Animationsgeschwindigkeit für "walk"
   
wait (1);
 
}
}

Weiter: Weiterführende Modell-Animation. Bones (Knochen)