Animation Agent Script

From HEWIKI
Jump to: navigation, search

Contents

The Animation Agent Script (.AAS file) controls a model’s physical behavior (the way that animations are applied to character movement). Animation sequences are executed based upon a variety of model inputs such as BaseMode, BasePosture, etc. Behaviors may be further refined through user-defined inputs.


Channels

A character will have one or more named animation channels. A channel masks off various bones (defined in Maya or 3ds Max) that it affects. All characters must have at least the one predefined channel named "AnimAllBody", that includes all bones by default.

The "AnimAllBody" channel must always have an animation playing, or the character will revert to root pose. The other channels, if any, may or may not have an animation playing as necessary.

Each channel's animation overrides the channel above it in the list based on the blend factors specified for each bone. So at 100%, the animation completely overrides. At 50%, it is a 50/50 crossfade.

Any animation sequence can be played on any channel.

From the HJ Sunok creature script we have:

channels
{
  AnimAllBody
  WeaponRightHand
  Impact	
}

In this example, we have three channels. The required "AnimAllBody" channel, and two others. The "WeaponRightHand" channel masks off just the bones of the hand and is perfect for controlling that hand's open and closed state by running a suitable single frame animation on that channel.

Inputs

Then there are the inputs to control behaviors. An input is essentially a named enumeration of values. A given input can be exactly one of the values specified at any given time.

The character controller often has very specific inputs that it expects. For example, the PlayerBehavior2 controller (default for Hero's Journey), expects inputs of BaseMode and BasePosture and others.

An input can only be changed externally (via a behave command or the character controller) unless it is marked as variable. In that case an input can be modified by the change command in the AAS itself.

The following code sample from monkeytok.aas shows the standard input definitions followed by user-defined variables. For instance, the variable Location was defined to allow behavioral adjustment dependent on whether the creature is flying or walking.

inputs
{
  BaseMode = Normal, Combat
  BasePosture = Idle, Turning, Moving
  IdleType = Normal
  MoveDirection = Forward, Backward
  TurnDirection = None, Right, Left
  TurnAmount = None, T45Degrees, T90Degrees, T135Degrees, T180Degrees
  variable AlreadyTurning =  true, false
  variable Attacking = Laser, Swipe, FlySlash, None
  variable CurrentMotion = Idle, TurningLeft, TurningRight, Forward, Backingup
  variable Special = None, Backflip, Howl, MonkeyBusiness, Heal, Fly, Land, Flips, Laser, Swipe, FlySlash
  variable ImpactHit = None, Blam
  variable Location = OnGround, Hovering  
  WeaponHand = Closed, Opened
}

Input values can be adjusted directly in the animation agent script:

change AlreadyTurning to False

Note that this only works if the channel is marked as variable, otherwise it is a run-time error.

Or through HSL scripts using the Behave command mechanisms:

For the server:

$BEHAVE._SendBehave(aCharacter, "input WeaponHand Opened")

On the client, you can manipulate the behave property directly:

creatureNode["Behave"] = "input WeaponHand Opened"

or use the _doBehave() method which allows a user-defined HE_DoBehave() method to override it:

$BEHAVE._doBehave(creatureNode, "input WeaponHand Opened")

Predefined inputs expected (required) by the PlayerBehavior2 character controller include:

Input Name Recognized Values
BaseMode Normal, Combat
BasePosture Idle, Turning, Moving, Dead, Prone, Kneeling
IdleType Normal
MoveDirection Forward, Backward
SideDirection Left, Right
TurnDirection None, Left, Right
TurnAmount None, T45Degrees, T90Degrees, T135Degrees, T180Degrees
WeaponHand Opened, Closed



Examples

The following examples show behave commands for the Humans and Suwari races in Hero's Journey:


Human/Suwari

Behave Description
input IdleType Normal Normal idle based on gender
input IdleType Sitting Character is seated, legs draped over ledge... useful only for screenshots right now. Turn off snap and place by hand.
input IdleType Conversation Femaleish "chatting with friends" idle
input IdleType Muted Special very-limited motion for use in character manager (varies by gender)
input IdleType Sneak Sneaking idle.
input IdleType Hammer Hammer pounding animation.
input IdleType Trowel Trowel animation
Input Attacking AttackName Valid AttackName: None, DownSlashRight, StepDownSlashRight, SideSlash, SpellCastLeft, SpellCastCrossarm, ComboFlyingSpinKick, SlashSpinSlash, JumpSlashBackSlash, SpellCastHealGroup, SpellCastSuperSpell, SpellCastSweep, SpellCastBuff, SpellCastGroundImpact, Impact, BowShoot, BowSlam, JumpSlashBackFlip, BackJumpSlashBackFlip, BackSlashSpinSlash, SoloFlyingSpinKick, BowShootLong, BowSnipeNock, BowSnipeRelease, BowShootHiLow, BowShootLongHiLow
input Special Option Valid Options: VictoryCheer, VictoryYes, Hammer, Trowel, Cower, Cry, Wave, Hug
input IdleType Sneak Rogueish still posture, listening around a corner
Kneel Character assumes a crouched/kneeling position.

Transitions

When an input changes value, a specific block of Animation Agent Script (an Action) can be designated to execute. This is done by specifying transitions of an input from one value to another and what named code block to execute.

Transitions allow the override of defined behaviors to handle special character states like stunned, paralyzed or dead. Transition blocks are defined with the keyword transition followed by name of the transitional input. The various state changes determine which Action will be executed.

Transition statement format:

from state1 to state2 = action

A full transition block:

transition BasePosture {

  from Idle to Dead = Die
  from Turning to Dead = Die
  from Moving to Dead = Die
 }


Actions

Actions are executable named code blocks. This is the action block for the death transition above:

action Die
{
  force(1) AnimAllBody
  {
    anim "combat_death"
    hold 1
    blend 0.1
    align false
    looping false
    change AlreadyTurning to False
    change CurrentMotion to Idle
    change Attacking to None
  }  
}

The main body of the animation agent falls under the Default action. This is a partial listing for the wood sprite.

action Default
{
  // Basic behavior for the whole body
 
  set(1) AnimAllBody
  {    
 
    when BaseMode {
    is Combat:
      when ImpactHit {
      is Blam:
        if (BasePosture = Idle) {
          anim "impact"
          blend 0.1
          hold 1
          looping false
          align false
          change ImpactHit to None
          stop
        }
      }
 
      when BasePosture {
      is Idle:
        anim "idle"
        align false
        blend 0.25
        hold 0.25 seconds recycle
        looping true
        change AlreadyTurning to False
        change CurrentMotion to Idle
      }
 
    is Normal:
      when Special {
      is IdleCrouch:
        anim "idle_crouch"
        looping true
        hold 1
        align true
        blend 0
        change Special to None
        change AlreadyTurning to False
        change CurrentMotion to Idle
        stop
    // AAS continues further...


AAS Keywords

ALIGN

The ALIGN keyword specifies if the Animation Sequence specified by the ANIM command will be "aligned" with the end of the currently playing animation on the channel (specified in the containing SET/FORCE construct).

The syntax is:

ALIGN [true|false]

So if you want the Animation Sequence to start from the beginning when the currently playing sequence ends, you'd use:

ALIGN TRUE

This is important when you have animations that are designed to match up at their "cut" point. So the ending of one leads precisely into the beginning of the next. Normally an Animation Sequence will play based on the global animation clock. So it might, for example, be half-way through the animation by "wall clock" when it starts. If you want this to occur, use:

ALIGN FALSE

Keep in mind that the specified Animation Sequence by the ANIM keyword may not start immediately, it depends on the cross-fade you want specified by the BLEND keyword.


This keyword is only valid within a SET/FORCE construct, and will only do something if an ANIM keyword is also encountered.


ANIM

See also: Character Behave Commands#ANIM

Play the specified Animation Sequence. The Animation Sequence must be defined in the ANIMATIONSET.DAT file.

Syntax:

ANIM “animation_sequence_name” 

Example:

ANIM “walkrun”

This keyword is only valid within a SET/FORCE construct. The SET/FORCE construct establishes which channel the Animation Sequence will operate on.

It is valid to specify an Animation Sequence of "" which means to play no sequence, or to clear the playing animation on a channel. For example:

ANIM ""  // Play nothing on this channel

This is valid for anything but the AnimAllBody channel which must always have some Animation Sequence playing on it. If not, the character will revert to "root pose" and an error message will be displayed.

Be sure to specify how long to "hold" the playing of the Animation Sequence with the HOLD keyword.


CALL

Used to invoke another Action in the agent script. After that action completes, execution continues with the next statement after the call (unless a stop is encountered along the way).

Syntax:

CALL {animation_actionblock_name}

Example:

CALL Die


CHANGE

Change a variable input value.

Syntax:

CHANGE variable TO value

Example:

Where the input CurrentMotion is defined as

variable CurrentMotion = Idle, TurningLeft, TurningRight, Forward, Backward

use

CHANGE CurrentMotion TO TurningLeft

To change the CurrentMotion input value to TurningLeft.

Note that only inputs marked as variable can be modified with the CHANGE command. Without the variable keyword, the inputs can only be changed externally (via the character behavior system, script, etc.).


HOLD

The HOLD keyword specifies the amount of time to "hold" the priority of the playing animation sequence on the current channel. After this amount of time has elapsed, the priority on the channel reverts to 0.

The syntax is:

HOLD percentage

This format lets you specify the hold time as a percentage of the duration of the animation sequence about to play (via the ANIM keyword). So that:

HOLD 1.0

Means to hold for the full duration of the Animation Sequence, or 100%. Likewise:

HOLD .5

Would mean to hold for half (or 50%) of the duration of the Animation Sequence.

You can also specify a precise amount of seconds to hold with this format:

HOLD .25 seconds

This means to hold for precisely one quarter of a second regardless of the length of the Animation Sequence.

HOLD .25 seconds recycle

Recycle modifies a looping sequence such that it is forced to reevaluate any decisions it made (such as evaluation of a multiplexer) to determine what sequence (animation) will ultimately be played. This is useful if you have a multiplexer animation for idles that occasionally adds in a flavor idle (such as the character stretching) that you do not want to happen repeatedly (in general).


This command is only valid within a SET/FORCE construct, and will only do something if an ANIM keyword is also encountered.


BLEND

The BLEND keyword specifies the amount of "Cross-Fade" to perform between the prior animation sequence on the current channel and a new sequence specified with an ANIM keyword.

The syntax is:

BLEND percentage

This format lets you specify the blend time as a percentage of the duration of the animation sequence about to play (via the ANIM keyword). So that:

BLEND 1.0

Means to blend for the full duration of the Animation Sequence, or 100%. Likewise:

BLEND .5

Would mean to blend for half (or 50%) of the duration of the Animation Sequence.

You can also specify a precise amount of seconds to blend with this format:

BLEND .25 seconds

This means to blend for precisely one quarter of a second regardless of the length of the Animation Sequence.

This command is only valid within a SET/FORCE construct, and will only do something if an ANIM keyword is also encountered.

IF/ELSE

Standard conditional logic structure.

Syntax:

IF (conditional phrase) {
    Executable statement block
}
ELSE IF (conditional phrase) {
     Executable statement block
}
ELSE {
     Executable statements block
}

Example:

 if (AlreadyTurning = true) {
   align true    
 }


SET/FORCE

The keywords SET and FORCE begin a code block for a particular specified channel. The code block is only executed if the specified priority is greater than (in the case of SET) or greater-than-or-equal to (in the case of FORCE) the priority of the animation currently playing on the animation channel. This also sets the priority for the channel once an animation is specified by the ANIM keyword.

Syntax:

set('''priority''') '''ChannelName''' {
 
}
 
 
 
 
force('''priority''') '''ChannelName''' {
 
}


So the structure:

set(5) AnimAllBody {
  ...
}

Will only execute if the current priority of the channel named "AnimAllBody" is less than 5. If FORCE(5) were used instead of SET(5) in this example, then the code block would execute if the priority was 5 or less.

This also establishes the priority for this channel at 5 (in this example) once an ANIM keyword is executed. The priority can be overriden with the PRIORITY keyword.

All commands related to an animation, such as ANIM, HOLD, LOOPING, etc. refer to the specified channel for this code block.


Managing the priorities of channels is the key to the AAS system. Using SET() and FORCE() establish a channel to be acted upon, but only if the priority of the currently running animation is low enough. Note that the priority on a channel automatically drops to 0 once it's hold time expires (see the HOLD keyword).

STOP

The stop keyword causes the execution of the script to halt at that point.

Syntax:

stop


WHEN/IS

Standard switch statement for case evaluation. If there is no case match, logic drops through to the case named DEFAULT.

Syntax:

WHEN switch_variable {
IS switch_value1:
     Executable statement block
IS switch_value2:
     Executable statement block
DEFAULT:
     Executable statement block
}

Example:

 when TurnDirection {
   is Right:
     when TurnAmount {
     is T45Degrees:
       anim "turn_right_45"
     is T90Degrees:
       anim "turn_right_90"
     is T135Degrees:
       anim "turn_right_135"
     is T180Degrees:
       anim "turn_180"
     }
     change CurrentMotion to TurningRight
   is Left:
     when TurnAmount {
     is T45Degrees:
       anim "turn_left_45"
     is T90Degrees:
       anim "turn_left_90"
     is T135Degrees:
       anim "turn_left_135"
     is T180Degrees:
       anim "turn_180"
     }
     change CurrentMotion to TurningLeft
   }


Creating a sequence name from an input

The Animation Agent Script (AAS) language also is the ability to create a sequence name from an input. Here is an example from CyberStrike Redux:

First, ensure that all animation sequences that are part of a logical group have the same prefix. In CSR, emotes are a logical group so they were all named like this:


emote_bashful.asq
emote_curtsey.asq
emote_flip.asq
... etc ...

The reason is that in the Animation Agent script, you can cut down a lot of code by mapping inputs to the ASQ name:

inputs
{
  variable EmoteType = None, Playing, bashful, curtsey, flip, jog_in_place, moonwalk, spin, wave
}


then later on...


if (EmoteType != None) {
    anim str("emote_",EmoteType)
    blend 0.1
    hold 1
    align false
    looping false
    change EmoteType to Playing
    stop
}

Notice how the str("emote_",EmoteType) did a string concatenation to achieve the different animation sequence names, such as: "emote_bashful"

This makes building your animation agent script easier because you then don't need a seperate WHEN/IS clause for every emote, for example. As your ASQs grow in number, this can be very helpful!

See also

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox