Previous: Sprites. Animated sprites

Models. Animated models.

If you plan to create a game, you will want to use models for your vehicles, characters, and so on. Well, you could even spice up your levels by hanging some models on the walls, just like I did with the torch model from the picture below:

 

You don't have to be a rocket scientist if you plan to use non-animated models in your game; use WED's "Add model" to place them in the level and move them where you want them. But how can we use those great looking, animated models? There are two types of animated models:

1) Models that use animation frames.

2) Models that use bones for animation.

The first type of models uses animation frames, just like a sprite; don't forget that a model is a 3D object, though. I'll start Med; let's take a look at a model that uses animation frames:

The animations can be played in a loop (for standing, walking, running, and so on) or we can have one-shot animations (for jumping, ducking, and so on). You can use many animation frames for your models; the amount of video memory that is used by an animated model is given mostly by the size of its skin; its number of animation frames has little influence.

A regular model has several animations, and this is how the frame names look in Med:

Ok, so Med won't show you the frame ranges using different colors (I did that using a painting program) but the point I'm trying to make is this: any animation should have a distinct name. If you have several "death" animations for a model, you could name them this way:

- deatha1... deatha30 (the first "death" animation has 30 frames)

- deathb1... deathb5 (the second "death" animation has 5 frames)

- rip1... rip8 (the third "death" animation has 8 frames)

What I'm trying to say here is that the name of the animation isn't that important, but it has to be a distinct name for every animation. So how do we write the code that uses these animations? Start WED, open work21.wmp and run it using script21.wdl:

The guard on the left side of the screen is playing its "walk" animation, but the guard on the right side of the screen doesn't do anything! Ok, let's wait for a few more seconds then...

I see! The guard on the left is performing a looped animation (walk) and the guard on the right has performed a one-shot animation (death)! Let's examine the script file:

I liked C-Script form its very beginning because you can do a lot of stuff using only a few lines of code; take a look at the action that animates the walking guard:

action walking_guard
{
    while (1)
    {
       ent_animate(my, "walk", walk_percentage, anm_cycle); // "walk" animation loop
       walk_percentage += 3 * time_step; // 3 = animation speed for "walk"
       wait (1);
    }
}

We are using a while (1) loop because our "walk" animation must play all the time; let's discuss the following line of code:

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

This instruction animates the "my" entity (the entity that has the action attached to it) using its "walk" animation loop, with the speed given by the variable named "walk_percentage", and plays the animation in a cycle (in a loop) because of the anm_cycle parameter. Here is the general form of the "ent_animate" instruction:

ent_animate(entity, animation_name, animation_percentage, animation_mode);

- "entity" is the name of the entity that will be animated. You don't have to use "my" here if you don't want to; define a pointer to an entity first and you will be able to use its name too:

Ex: ent_animate(kung_fu_master, "rofl", masters_speed, anm_cycle);

- "animation_name" is the name of the animation taken from Med (but without the figures associated to the frames). Don't forget to enclose the name of the animation with quotes; otherwise, you will get an error message. Once again, you can use any name for the animation in Med, but you must use the same names in your script file:

Ex: ent_animate(my, "smelling", nose_speed, anm_cycle);

- "animation_percentage" is the percentage of the animation. This is a simple var that must change its value if you want to animate the model; if animation_percentage is 0, the model displays its first animation frame and if animation_percentage = 100 the model will displays its last animation frame.

Our guard model has only 4 animation frames for walking (walk1... walk4) but the animation doesn't look choppy at all in our demo! In fact, if you take a good look at the pictures below, you will notice that the guard appears to have much more animation frames! This feature, named smooth frame interpolation, is built inside A6; the engine computes intermediate animation frames and places them between the existing frames, making the animation look much smoother even if the model has only a few frames.

The variable named "walk_percentage" from our example increases its value all the time, and this is why our walking model is animated; play with "3" if you want to increase or decrease the animation speed.

- "animation_mode" tells the engine if it has to play the animation in a loop (animation_mode = anm_cycle) or if it needs to play a one-shot animation (animation_mode = 0).

That's all you need to know about "ent_animate" if you plan to animate your models using animation frames. And to make the things even more clear, let's take a look at the action that is attached to the model that plays its one-shot "death" animation:

action dead_guard
{
    sleep (5); // wait for 5 seconds
    while (1)
    {
       ent_animate(my, "death", death_percentage, 0); // "death" one-shot animation
       death_percentage += 2 * time_step; // 2 = animation speed for "death"
       wait (1);
    }
}

The dead guy will wait for 5 seconds before starting the animation; I have used this line of code because your monitor might need 1 or 2 seconds to change from its current video resolution to 800 x 600 pixels, and I didn't want you to miss a single "death" animation frame.

The "ent_animate" line will play the "death" animation using the "death_percentage" variable. This is a one-shot animation, because "animation_mode" is set to zero. Play with "2" if you want to increase or decrease the animation speed.

I have used a while (1) loop for the dead guard; this loop will continue to run even if the model has played its last "death" animation frame, doing... nothing, but wasting a little bit of CPU power. A more elegant version of the action would look like this:

action dead_guard_2
{
    sleep (5); // wait for 5 seconds
    while (death_percentage <= 100) // death_percentage will range from 0 to 100 here
    {
       ent_animate(my, "death", death_percentage, 0); // "death" one-shot animation
       death_percentage += 2 * time_step; // 2 = animation speed for "death"
       wait (1);
    }
}

The while loop above will run for as long as death_percentage is smaller than or equal to 100, and it will stop as soon as death_percentage grows over 100 (the last "death" frame was played). I invite you to paste the action at the end of the script21.wdl file; attached it to one of the guards, build the level again and you will see that it plays the one-shot "death" animation as expected.

Didn't you miss our little homework? You actually did? Then why don't you try to create a simple action for a model that is animated using its "walk" animation and moves using "c_move" at the same time? Use action walking_guard as a base (it is playing the "walk" animation in a loop already) and then add a single line that moves the entity using "c_move" inside the while(1) loop.

Solution: add a line of code to action walking_guard:

action walking_guard_2
{
    while (1)
    {
        c_move (my, vector(2 * time, 0, 0), nullvector, glide); // note the time-corrected speed
        ent_animate(my, "walk", walk_percentage, anm_cycle); // "walk" animation loop
        walk_percentage += 3 * time_step; // 3 = animation speed for "walk"
        wait (1);
    }
}

 

Next: Advanced model animation. Bones