Playing AI Animations: Difference between revisions

From The DarkMod Wiki
Jump to navigationJump to search
(New page: == Animation Channels == Each Actor has a set of animation channels (all AIs are deriving from Actors, by the way): * ANIMCHANNEL_TORSO * ANIMCHANNEL_LEGS * ANIMCHANNEL_HEAD * ANIMCHANNE...)
 
No edit summary
Line 22: Line 22:


== Animation States ==
== Animation States ==
The AI is always in a certain Animation State, which is usually the Idle state. Each Animation State has an accompanying script function (usually defined in ai_darkmod_base.script), whose task is to monitor the animation status and take the according actions. The Animation State of an AI can be changed by calling the scriptEvent '''animState''' or idAI::SetAnimState():
scriptEvent void animState(float channel, string stateFunction, float blendFrame);
void idActor::SetAnimState(int channel, const char *statename, int blendFrames);
When an animation state is entered, the according script function '''carrying the same name as the AnimState''' is looked up on the actor's scriptobject and called. The script is responsible for controlling the animation.
Let's have a look at this example:
void ai_darkmod_base::Torso_Surprise1() {
    // play the animation
    playAnim(ANIMCHANNEL_TORSO, "surprise1");
   
    while (!animDone(ANIMCHANNEL_TORSO, 4)) {
        waitFrame();
    }
   
    // finish up and start idling again
    finishAction("surprise");
    animState(ANIMCHANNEL_TORSO, "Torso_Idle", 4);
}
As you can see, this scriptEvent plays the animation, waits until its done playing and switches back to the Idle anim state after resetting a certain flag.
The important part is the '''while (!animDone)''' loop which basically waits until the animation is done playing. As soon as the anim is done, the script interpreter exits the loop and the actor is set back to the Idle state (to prevent the TORSO channel from becoming inactive).
If the programmer's intention is just to let the "surprise1" animation play on the torso channel and to fall back into the Idle animation state afterwards, it's enough to call:
actor->SetAnimState(ANIMCHANNEL_TORSO, "Torso_Surprise1", 4);
However, if the programmer intends to do something after the animation is done, things get more involved, that's what WaitStates are for:
== Animation WaitStates ==
In the previous example, you might wonder what the '''finishAction'''is supposed to do. The main reason for this call is to allow the SDK code to check whether the animation is done playing. As there is no equivalent to '''eachFrame''' in the SDK code, we must rely on flags being set. The flags are not set automatically (don't ask me why), this is done by the calling code, so let's look at how it's done:
TODO
TODO


{{ai}}
{{ai}}
[[Category:Coding]]
[[Category:Coding]]

Revision as of 00:32, 8 November 2007

Animation Channels

Each Actor has a set of animation channels (all AIs are deriving from Actors, by the way):

  • ANIMCHANNEL_TORSO
  • ANIMCHANNEL_LEGS
  • ANIMCHANNEL_HEAD
  • ANIMCHANNEL_EYELIDS
  • (ANIMCHANNEL_ALL)

Each channel can play an animation independently from the other channels, hence it's possible to play the walk animation on the LEGS channel and the cough animation on the TORSO.

Playing Animations

The most basic way to play an animation is to call the script event playAnim (via script) or Event_PlayAnim (SDK). Both take the desired animation channel and the animation's name as argument:

scriptEvent float playAnim(float channel, string animName);
void idActor::Event_PlayAnim(int channel, const char *animname);

However, for most applications this is not enough. When a channel is done playing the anim, it will stop playing anything, which might cause the AI's hands to hang around uselessly (in the case of the TORSO channel). Because of this, Animation States were introduced:

Animation States

The AI is always in a certain Animation State, which is usually the Idle state. Each Animation State has an accompanying script function (usually defined in ai_darkmod_base.script), whose task is to monitor the animation status and take the according actions. The Animation State of an AI can be changed by calling the scriptEvent animState or idAI::SetAnimState():

scriptEvent void animState(float channel, string stateFunction, float blendFrame);
void idActor::SetAnimState(int channel, const char *statename, int blendFrames);

When an animation state is entered, the according script function carrying the same name as the AnimState is looked up on the actor's scriptobject and called. The script is responsible for controlling the animation.

Let's have a look at this example:

void ai_darkmod_base::Torso_Surprise1() {
   // play the animation
   playAnim(ANIMCHANNEL_TORSO, "surprise1");
   
   while (!animDone(ANIMCHANNEL_TORSO, 4)) {
       waitFrame();
   }
   
   // finish up and start idling again
   finishAction("surprise");
   animState(ANIMCHANNEL_TORSO, "Torso_Idle", 4);
}

As you can see, this scriptEvent plays the animation, waits until its done playing and switches back to the Idle anim state after resetting a certain flag.

The important part is the while (!animDone) loop which basically waits until the animation is done playing. As soon as the anim is done, the script interpreter exits the loop and the actor is set back to the Idle state (to prevent the TORSO channel from becoming inactive).

If the programmer's intention is just to let the "surprise1" animation play on the torso channel and to fall back into the Idle animation state afterwards, it's enough to call:

actor->SetAnimState(ANIMCHANNEL_TORSO, "Torso_Surprise1", 4);

However, if the programmer intends to do something after the animation is done, things get more involved, that's what WaitStates are for:

Animation WaitStates

In the previous example, you might wonder what the finishActionis supposed to do. The main reason for this call is to allow the SDK code to check whether the animation is done playing. As there is no equivalent to eachFrame in the SDK code, we must rely on flags being set. The flags are not set automatically (don't ask me why), this is done by the calling code, so let's look at how it's done:

TODO