Animation Sequences are used to instruct HeroEngine how to animate your character. An Animation Agent instructs a given channel of animation on what Animation Sequence to play. While ultimately ASQs are text files, they are typically edited using HeroBlades Animation Panel.
An Animation Sequence is actually a node on a Directed Acyclic Graph. In this way, an Animation Sequence can use other Animation Sequences as Inputs. This creates a graph (or tree) of sequences. This presents a powerful nomenclature for expressing complex and dynamic animations.
Consider this simple example:
Here we have three Animation Sequences. The first, named "WalkRun" uses a SpeedBlend to mix two animations together. As input, it takes a "Walk" and a "Run" animation. The SpeedBlend not only cross-fades between the two animations, but adjusts their play back speeds so that (if authored correctly) they blend perfectly between a walk cadence and a run cadence.
Animation Sequences can be chained together in this way to create complex and dynamic animations. An Animation Sequence can use any other Animation Sequence as one of its inputs. The only restriction is that you cannot create a circular dependency (an infinite-loop).
Each Animation Sequence is defined by an .ASQ file. Each of these is bound up into a collection in the Animation Set's
ANIMATION.DAT file. The name of the file (minus the .ASQ extension) becomes the name of the Animation Sequence. So, the sequenced named "combat_slash" would have a filename of
Here is an example of the Sunok's
! ! Animation Sequence Spec ! Version=1 [ABILITIES] Apply Animation .Animation=combat_attack_ranger_slasher.hgm .InitialSpeed=1 .InitialLoop=false .InitialAlign=true
Note: The version specification must match what the current HeroBlade expects. As of this writing, it is version 1.
Each Animation Sequence is defined by specifying one or more Animation Abilities. Here are the available Animation Abilites:
- Apply Animation
- Plays a specified animation file. (details)
- Blends between two sequences. (details)
- Does an Additive Blend. (details)
- Speed Blend
- Blends between two animations synchronizing playback speeds. (details)
- Select between multiple animations. (details)
- Rotate Bone
- Adjusts a given bone's rotation. (details)
- Issues callbacks to script with the animation note text at points specified by ration, time, or frame (details)
Sequencing Animation Abilities
An Animation Sequence must have at least one Animation Ability. It may, however, have more than one. When an Animation Sequence has more than one ability, they are applied simultaneously. So, for example:
Here is the
WALK.ASQ for a character:
! ! Animation Sequence Spec ! Version=1 [ABILITIES] Multiplex .AddSequence=walk_no_weapon (!HasWeapon) 10 .AddSequence=walk_weapon (HasWeapon) 10 .FilterController=IdleFilter Rotate Bone .BoneName=Bip01 Neck1 .StartRotation=(50,0,0) .ApplyToMotionVector=false .ScaleController=BodyTwistKnob Rotate Bone .BoneName=Bip01 Spine1 .StartRotation=(40,0,0) .ApplyToMotionVector=false .ScaleController=BodyTwistKnob Rotate Bone .BoneName=Bip01 Spine2 .StartRotation=(40,0,0) .ApplyToMotionVector=false .ScaleController=BodyTwistKnob
This Animation Sequence has four Animation Abilities. The first is a Multiplex Ability that selects between two sequences based on whether the character has a weapon in their hand or not. The remaining three abilities apply a rotation to three bones in the spine based on an external value (BodyTwistKnob). The purpose of this is so that when the character is running sideways, the upper body can be twisted in the classic "strafing" pose without having to author additional animations.
Note that all of this happens at once. The multiplexer has picked an animation and then the bones are twisted all in the same frame of animation.
Sequencing Consecutive Abilities
You may want to sequence abilities. In other words, you want one Animation Ability to complete, then do the next, and so on. This is done with the
Next keyword betwen abilities.
For example, here is an Animation Sequence for a complex attack:
! ! Animation Sequence Spec ! Version=1 [ABILITIES] Apply Animation .Animation=combat_jump_back.hgm .InitialSpeed=1 .InitialLoop=false .InitialAlign=false Next Apply Animation .Animation=combat_sideslash_open_end.hgm .InitialSpeed=1 .InitialLoop=false .InitialAlign=false Next Multiplex .AddSequence=combat_sideslash_followup_backslash 10 align .AddSequence=combat_sideslash_followup_thrust 10 align .AddSequence=combat_sideslash_followup_spin 10 align
In this example, the sequence first applys (plays) the animation in the file
combat_jump_back.(file extension). When that finishes, it then plays the
combat_sideslash_open_end.(file extension). After this, it then will immediately use the Multiplex ability to randomly select between three finishing parts to the animation.
The <cod>Next</code> keyword allows for a sequence to string together animation abilities one after another. This is a very powerful mechanism for compositing animation parts. Coupled with a Multiplex ability, you can interject random sub-elements into an animation sequence easily.
Animation Abilities often need access to external data, or the ability to expose data externally to the Animation Mixer itself. This is done through "knobs" (meaning like the knobs on a radio). There are two types of knobs:
- Float (called an fknob)
- Knob holds a floating-point value (decimal value, like 4.5)
- String (called an sknob)
- Knobs holds a string of text (like "howdy, my name is bob")
You specify a knob when you define your abilities, and give them a unique name. This named knob can then be changed externally (such as from an HSL script, a behave command, etc.). Furthermore, external systems can access the value of knobs (some abilities will not just use a knob value, but will also change a knob value to provide some feedback to external systems).
A knob name must be a single word, beginning with an alpha character. For example: "BlendAmount", "WalkSpeed", etc.
Different abilities can accept different knobs. For example, a Blend2 Ability lets you specify a fknob that controls how much to blend from sequence A to sequence B (a value between 0 and 1, so .5 would be a 50% blend).
You can modify a knob via the behave property of a character, as in this client-side HSL example:
var KnobName = "WalkSpeed" var KnobValue = 3.5 aCharacter["Behave"] = "fknob " + KnobName + " " + KnobValue
Or from the CLI, you could modify a knob on your character:
behave 0 fknob WalkSpeed 20
or, for a string knob:
behave 0 sknob "Try as you might"
Note that when you specify an fknob or sknob, it is created if it doesn't already exist. So a typo of a knob name in one of these commands (or in an Ability) can be a bit perplexing... there is no "knob not found" type error, because HeroEngine will just assume it's a new knob being introduced and add it. So be mindful of this gotcha.
Animation Ability Details
Each Animation Sequence is defined by one or more abilities. In the .ASQ file, each ability is introduced in the
[ABILITIES] section by its type name followed by properties as shown in the various examples on this page. All properties are in the form
- Main page: Parameter syntax
Where numeric values are used as a property value, you can use any normal parameter syntax. This lets you specify a specific value, a Gaussian random number, a timeline, a perlin, or a trigonometric function.
For example, the property InitialSpeed could be setup to have a random Gaussian value between .5 and 2 (with a standard deviation of .5 and a mean value of 0):
Plays a specified animation file. As such, this is always a "leaf node" on your Animation Sequence tree. This is also the most basic of sequence actions. Most animations will be specified by a single sequence with this ability.
Apply Animation .Animation=walk_male.hgm .InitialSpeed=1 .InitialLoop=true .InitialAlign=false .Preload=false
- Specify the animation file to play by name with the file extension. With no path specified, it assumes the same folder as the Animation Set (where this sequence file is located). A full FQN path can be used to specify an animation anywhere in the repository.
.Animation=crazywalk.<file extension>will cause
crazywalk.<file extension>to load and play. If no file extension is specified, the engine assumes .gr2 to support legacy sequence files.
- Specifies the playback rate of the animation, where 1 is to play back and normal speed (i.e. 1x playback). A value of 2 would play at double speed.
.InitialSpeed=.2causes the animation to playback at 20% normal speed.
.InitialSpeed=<.5,2,.5,0>causes the animation to playback at a random speed between .5X and 2X normal speed.
- Specifies if the animation loops. If true, so long as the Animation Sequence continues to play the animation will loop. If false, it will stop at the end and hold until the Animation Sequence itself ends.
.InitialLoop=truecauses animation to loop.
- If true, the animation plays from the beginning regardless of the Animation Sequences animation clock position. If false, plays from wherever in the animation the sequence's clock is positioned (which may not be the beginning). When an Animation Sequence plays, its clock starts at 0. However, a sequence might use the Next keyword to string together multiple animations. In this situation, the setting Align to true might be useful so the animations that are designed to piece together precisely start-to-end-start-to-end will line up properly. It should not be set (e.g. leave as "false") with SpeedBlends as the restriction on the internal clock results in technically correct, but unexpected speed values to be returned from the SpeedBlend.
- Causes the reference animation to load immediately whent his animation set is introduced to the game client, instead of loading on-demand (when the sequence is first "played"). Loading animation files happens asynchronously, so there can be a delay before the sequence is ready. If the animation file is not in the local repository cache, then a download request for the file will occur regardless of Preload being true or not. See Animation Sequence Loading below for more details.
.Preload=truecauses the animation file to load immediately on Animation Set introduction.
- Note: VDA is deprecated. This property is no longer needed or used.
Blends between two input Animation Sequences in a standard cross-fade. The amount of fade is controlled by a fknob. The discreet parameter lets you snap to full 0 or 1 value (full SequenceA or full SequenceB).
Blend2 .SequenceA=walk_male .SequenceB=walk_female .BlendController=MaleFemale .Discreet=false
In this example we have authored a distinctly male version of a walk and a distinctly female version of a walk. At .5 blend, we get an androgynous looking walk.
- Specifies the first sequence. When the fknob value is 0, this is played at 100% weight, when it is 1 it is played at 0% weight.
- Specifies the second sequence. When the fknob value is 0, this is played at 0% weight, when it is 1 it is played at 100% weight.
- Specifies the name of the fknob that controls the blend between SequenceA and SequenceB. The value should be between 0 and 1, and is clamped between these values.
.BlendController=malefemalespecifies an fknob named
malefemalethat controls the blend.
- If true, the animation will play either SequenceA (if the fknob < .5) or SequenceB (if the fknob >= .5), but not blend between them. A similar effect can be achieved with the Multiplex ability, but in that case you are not using a numeric value.
This action does an "Additive Blend", which is to say that it adds the contribution of one animation to another. The additive part is an animation sequence (or can be just to the current pose) and can be a single frame or an entire animation sequence. The animation data for each bone is added to input.
The affect of this additive blend can be modulated by a blend amount parameter or an fknob.
To accomplish an additive blend a reference pose animation is used. The reference pose is an animation that identifies the "root" position of all the bones (at that frame). The amount each bone adds during this operation is determined by how it varies from that reference. For example: Any bone that has an identical position/rotation in both the reference animation and the input of Sequence B contributes nothing. but if it's rotated 45 degrees on the Y axis from the reference, then that's the amount Y axis rotation the operation will apply.
Add .SequenceA=source_animation .SequenceB=additive_action .ReferenceAnimation=additive_reference .BlendController=AdditiveBlendKnob
In this example we are taking one sequence (A) and adding to it sequence (B). The amount of impact on each bone is how the sequence (B) varies from the reference animation
additive_reference. An fknobnamed "AdditiveBlendKnob" attenuates the amount of impact (where 1.0 would be 100%).
Add .SequenceB=additive_action .ReferenceAnimation=additive_reference .BlendAmount=.5
In this example, we have no sequence (A) which means that it takes as its input the current animation pose. This only works when such data exists in the sequence; in other words it cannot be the first ability. Presumably there is an Apply Animation ability preceding this one in the animation. Further, the amount of blend is not controlled by an fknob, but rather by a fixed amount of .5 (i.e. 50%). The BlendAmount property is actually a parameter so could have a more complex specification, such as a timeline.
If both the BlendController and BlendAmount properties are absent, then there will be a default 100% contribution.
- Specifies the source sequence to which SequenceB will be added. SequenceA is optional. If omitted, the current pose of the sequence will be used as the source. This only makes sense if some other ability precedes this one in the sequence (such as an Apply Animation, for example) so that there is current pose data to work with.
- Specifies an animation sequence that specifies the Additive contribution for each bone. The amount of contribution is determined by how the bone varies from the ReferenceAnimation pose (see below). This can be any length animation, including a single frame. Make sure that the sequence used loops.
- Specifies an animation file that is the pose (i.e., a single frame pose or a multi-frame animation) that the base for computing the additive difference. Essentially every frame of SequenceB is compared to this pose (or the coincident frame of animation, if this is more than one frame) to determine a delta for each bone that is used for add.
- Specifies the name of the fknob that controls the amount of Additve Blend. The value of this fknob can be anything, where 0 means no contribute, 1.0 means 100% and 2.0 would mean 200% contribution. This property is optional.
.BlendController=AdditiveAmountspecifies an fknob named
AdditiveAmountthat controls the additve blend.
- A parameter that allows you to specify a specific amount of blending as a parameter. This only works if the BlendController" parameter is omitted (as that has precedence).
.BlendAmount=.5specifies a 50% additive contribution.
.BlendAmount=<.0,1.0,.5,-1.0>specifies a Gaussian random contribution amount. In essence, this would cause it to vibrate between 0 and 100% randomly each frame (great for a procedural twitchy effect).
NOTE: If neither a BlendController nor a BlendAmount property is specified, then this ability will contribute at a default of 100%
- Causes the reference animation to load immediately when his animation set is introduced ot the game client, instead of loading on-demand (when the sequence is first "played"). Loading animation files happens asynchronously, so there can be a delay before the sequence is ready. If the animation file is not in the local repository cache then a download request for the file will occur regardless of Preload being true or not. See Animation Sequence Loading below for more details.
- See also: Character animation movement
Blends between two animations synchronizing playback speeds. This does a cross-fade as well as adjusting the speeds of the animations to preserve the cadence (making sure the walk foot falls and the run foot falls are synchronized, for example). This is generally used to blend a walk and a run sequence together.
It is important that the authoring of the animations be correct for this to give the desired results:
- For a walk animation, author so that the animation is trimmed to one-cycle (left foot down to left foot down). The translation of the character (via the Synthetic Root Bone) should be at the normal walk speed you want.
- The run animation should be done in exactly the same way. The translation will be farther of course. Be sure that the same starting foot is used (if it's starting left down in walk, it needs to start with left down in run).
- SequenceB (run, in this case) must translate faster than SequenceA (walk, in this example).
Here is how this would typically be structured:
Three sequences are used, a walk and run to Apply the associated animation are used as inputs into the SpeedBlend ability of the WalkRun Animation Sequence.
Speed Blend .SequenceA=walk .SequenceB=run .SpeedController=Speed .SequenceAFeedbackName=Feedback_WalkSpeed .SequenceBFeedbackName=Feedback_RunSpeed
What if you wanted to blend more than two things together based on speed? For example, you wanted to author discreet walk, jog, run and sprint animations and smoothly interpolate between them? Because Animation Sequences are constructed as a graph (a tree in this case), you could structure that this way:
This uses three sequences with the Speed Blend ability, and four sequences with Apply Animation for each of the discreet animation files. Notice all of the Speed Blends use the same fknob by name so everything stays in sync.
The blend is controlled by a fknob that specifies the desired speed of movement (in meters per second). The SpeedBlend will blend the two animations together and adjust their playbacks to achieve that speed of translation. The speed of the SequenceA and SequenceB animation is determined internally by sampling how far they translate in one second of time, yielding a meters per second value. The fknob speed controller can be set to any speed. If it is greater than SequenceB's speed, the animation will play speed up to match. Except for the fact that SequenceB has to be faster than SequenceA, there is no particular speed relationship between the two that has to be maintained.
So long as there is no foot sliding in the original authored animations, there will be none as of the SpeedBlend. Keep in mind that if you play back at a much greater speed than SequenceB, you will start to get a comical "speed up film run" effect. About 1.5x the speed of the SequenceB usually still looks acceptable. Running really slow will yield a slow motion effect in the same way but looks fine for slowing down to a stop.
- Specifies the first sequence, the "slower" of the two.
- Specifies the second sequence, the "faster" of the two.
- Specifies the name of the fknob that determines the blend. The value is specified in meters per second. The SpeedBlend will blend and adjust playback rates to achieve an animation that produces this rate of translation.
.SpeedController=Speedspecifies that the blend is controlled by a float knob named
- Specifies the name of a fknob that the SpeedBlend will set to the speed of SequenceA in meters/sec. In other words, this is an output knob as the SpeedBlend sets the value rather than uses the value. In this way, external systems can find out how fast the SequenceA speed is (say, how fast a normal "walk" is).
- Note: The current PlayerBehavior2 system depends on a SequenceAFeedbackName of "Feedback_WalkSpeed". This may vary with your implementation.
- Specifies the name of a fknob that the SpeedBlend will set to the speed of SequenceB in meters/sec. In other words, this is an output knob as the SpeedBlend sets the value rather than uses the value. In this way, external systems can find out how fast the SequenceB speed is (say, how fast a normal "run" is).
- Note: The current PlayerBehavior2 system depends on a SequenceBFeedbackName of "Feedback_RunSpeed". This may vary with your implementation.
- Other Properties
- Several properties have been deprecated. Properties like LowSpeedA and HighSpeedB are no longer needed or used.
Select between a set of sequences. The decision of which sequence to play is made once when the Sequence begins and sticks until it ends. You can define the probability of any particular sequence being selected, and using an expression language and a sknob you can filter which sequences are valid to pick from.
Here is a simple Multiplex ability that chooses randomly between three sequences with equal probability:
Multiplex .AddSequence=combat_sideslash_followup_backslash 10 align .AddSequence=combat_sideslash_followup_thrust 10 align .AddSequence=combat_sideslash_followup_spin 10 align
Each of the abilities is assigned a value of 10. All of the sequences values are added, and a random number is picked to determine which will be used. So here is the same set with a wildly different random distribution:
Multiplex .AddSequence=combat_sideslash_followup_backslash 100 align .AddSequence=combat_sideslash_followup_thrust 10 align .AddSequence=combat_sideslash_followup_spin 1 align
In this version, the
combat_sideslash_followup_backslash is much more likely to be picked everytime. The
combat_sideslash_followup_thrust sequence is about 10x less likely, and the
combat_sideslash_followup_spin one is only going to happen like 1% of the time.
Filtering the Multiplexers
Each Animation Sequence can be selectively filtered by an sknob. This is done with a simple expression syntax:
Multiplex .AddSequence=combat_sideslash_followup_backslash (Back) 10 align .AddSequence=combat_sideslash_followup_thrust (Thrust) 10 align .AddSequence=combat_sideslash_followup_spin (Spin) 10 align .FilterController=SlashController
In this example, the sequence that is picked is determined by the keywords in the sknob
SlashController. So, if the sknob contained the keyword "Back" then
combat_sideslash_followup_backslash would be the only sequence valid for selecting.
Slightly more complex:
Multiplex .AddSequence=combat_sideslash_followup_backslash (simple) 100 align .AddSequence=combat_sideslash_followup_thrust (simple) 10 align .AddSequence=combat_sideslash_followup_spin (complex) 10 align .FilterController=SlashController
Here, the first two sequences are valid if
SlashController contains the keyword "simple", but since the ...blackslash one has a value 100, it is 10x more likely to be selected than the ...thrust one. If the value of the
SlashController was "complex" then only the ...spin sequence is valid and that would be picked.
The FilterController sknob can have more than one keyword in it (separated by spaces), for example it could be "simple complex" and, in the above example, this would mean every sequence is valid. But consider this possibility:
Multiplex .AddSequence=combat_sideslash_followup_backslash (simple) 100 align .AddSequence=combat_sideslash_followup_thrust (simple & !complex) 10 align .AddSequence=combat_sideslash_followup_spin (complex) 10 align .FilterController=SlashController
In this case, the first sequence is valid if the keyword "simple" is present. The second one is valid if the keyword "simple" is present, but not valid if the keyword "complex" is present. In this case, we've used the and operator (&) as well as the not operator (!). So, this says "if 'simple' and not "complex'".
(blue & (red | green) & !purple)
Would mean that the keyword "blue" must be present as well as either "red" or "green" but not if "purple" is present.
One can specify on the absence of any keyword too:
This would mean "if no keywords are present", thus the sknob has a value of "" (empty).
Or you might say:
Which means if any keyword is present, but this is the same as not using a filtering expression at all and so isn't ever needed itself.
Align and Looping
align keyword specifies that the animation's start should align with the local clock. This is useful when using a sequence with multiple sequenced animations (the Next keyword).
loop keyword specifies that the sequence should loop.
.AddSequence=combat_sideslash_followup_backslash 10 align loop
Both of these manipulate how the selected animation sequence responds to the internal clock of the current sequence. The internals of that sequence can also be important to alignment and looping (for example, see the Apply Animation ability).
- You can specify any number of sequences to multiplex between, so this property can appear any number of times. Each has the format:
sequencename [(filter expression)] random [loop] [align]
.AddSequence=shiver (cold) 10 align loopAdds a candidate sequence that will cause a shiver sequence to play, if selected. It only occurs if the FilterController's sknob has the keyword "cold" however.
- All that is required is the sequence name and the random value. The random value of all sequences that pass their filter (if any) are added, which represents the "sides of the dice" that is rolled. Then this roll is used to determine what Animation Sequence is actually selected for the duration of this sequence's play.
alignkeywords allow you to control how the played sequence relates to this sequence's internal clock in the usual ways.
- Specifies the sknob that can be set externally to a space-delimited list of keywords. These are used in the filter expressions of each candidate sequence to determine if they are valid for selection.
.FilterController=KeywordListspecifies an sknob named "KeywordList".
Used to animate the rotation of a single bone of the character's skeleton. The amount of rotation can be scaled externally by an fknob.
NOTE: This ability currently only supports adjusting the offset by a static value (with the option to scale that by an fknob). Therefore only a subset of it's capabilities have been implemented so far.
Rotate Bone .BoneName=Bip01 Neck1 .StartRotation=(50,0,0) .ApplyToMotionVector=false .ScaleController=BodyTwistKnob Rotate Bone .BoneName=Bip01 Spine1 .StartRotation=(40,0,0) .ApplyToMotionVector=false .ScaleController=BodyTwistKnob Rotate Bone .BoneName=Bip01 Spine2 .StartRotation=(30,0,0) .ApplyToMotionVector=false .ScaleController=BodyTwistKnob
In this example, three bones are rotated (simultaneously) in the spine of the character. The first one rotates the head, the others add a smaller twist to the upper body. The amount of twist is controlled, ultimately by the fknob named "BodyTwistKnob". By adjusting this value between -1 and 1, the upper body of the character can be twisted to the left or right regardless of what other animations are playing. Note that the twist is nice and non-uniform, because each of the rotations is slightly different, so the knob is simply scaling the effect (keep in mind this value could even exaggerate the effect by going past 1 or -1).
Note that this same effect could also be done by blending in an animated pose (an animation with a single frame of animation) with the body twisted. However, this is much more computationally expensive than using the Rotate Bone Animation Ability.
- Specify the name of the bone to rotate. Note that bone names can have spaces in them, and this is fully supported.
- Specifies the starting amount of rotation in the form (heading,pitch,roll). Values are in degrees.
- Note: In the current implementation, this is the fixed amount of rotation.
- Note: Not implemented yet.
- Note: Not implemented yet.
- Note: Not Implemented yet.
- If true, the rotation will also affect the motion vector of the character. Usually you do not want to do this, but sometimes you may want a bone twist to also change the character's direction.
- Specifies an optional [#Knobs|fknob] who's value scales the rotation. If this value is 0, then the this ability would have no affect on the bone. A value of 1 will cause it to rate as specified in the StartRotation property. A value of -1 would reverse the rotation. A value of .5 would have half the affect on the bone, etc. This is useful to allow an external system to dictate the amount of a bone twist that occurs.
.ScaleController=BodyTwistKnobspecifies that the [#Knobs|fknob] named "BodyTwistKnob" will scale the effect of this bone rotation.
Notes provide the capability at specific points in an animation to provide a call into HSL script allowing game logic to perform actions that are outside the capabilities of the animation system itself.
- See also: Animation Notes
Animation notes are intended to replace/augment 3ds Max's ability to add animation note tracks.
! ! Animation Sequence Spec: swim_backwards ! 12/09/2009 14:18 ! Version=1 [ABILITIES] Apply Animation .Animation=swim_backwards.hgm .InitialSpeed=1 .InitialLoop=True .InitialAlign=False .Preload=False Notes .TrackTitle=Arms .Units=Ratio .FPS=30 .AddNote=0.268 "Stroke" .AddNote=0.5 "Stroke" .AddNote=0.7913386 "Stroke"
- Track title is an arbitrary grouping of conceptually related notes for organizational/display purposes
- Unit of scale that is going to be used by all notes in this TrackTitle. Valid options are Ratio, Seconds, and Frames
- Average FPS to use when using the Frames Unit, thirty is the default
- Map of indexing units to the note value to send to script at that point
Animation Sequence Loading
Animation sequence files are all loaded when the first character to use that Animation Set is introduced to the client. However, by default, none of the actual animations are loaded into memory. This is because, quite often, only a subset of the animations are actually needed. So, animations will load on demand. This means the moment an ApplyAnimation ability is executed that specifies that file for the first time, the client will load the animation data synchronously (blocking until it is loaded).
Preloading Animation Data
Loading on demand has its drawbacks, however. First, there can be a hitch in game play when it loads the file from disk. In order to avoid this, you can specify that an animation is to be preloaded. When you do this, the animation data will be loaded immediately. This is done asynchronously, so as not to hitch. The reason this is useful is because quite often you can get an animations in memory before they are needed. For example, when you are going into a new area, there will be creatures already wandering around (usually) and so you'll have them preloaded during the area load phase. Or when a character is introduced to a client, it can start preloading animations before the player gets close enough to see the creature.
The ApplyAnimation Ability can specify that it preloads an animation by setting the Preload property to true, as shown in this example:
! ! Animation Sequence Spec ! Version=1 [ABILITIES] Apply Animation .Animation=walk_male.hgm .InitialSpeed=1 .InitialLoop=true .InitialAlign=false .Preload=true
Uncached Animation Data
Loading animation data on-demand, or even preloading animation data, assumes that the animation data is in the local repository cache. There are two ways data might not be in the local cache:
- If the animation is new and hasn't been requested before
- The animation data has been updated (in which case it is purged from the local cache so it'll download upon the next request)
Fortuantely, when an Animation Set loads, it will detect if any of the required animations are not in the local cache and, if not, request them from the repository server immediately. This will start the download process.
Unfortunately, this doesn't ensure that they will be ready when needed. So, what happens when an animation data isn't available? This is where Animation Sequence Fallbacks come in...
Animation Sequence Fallback
When an animation sequence cannot load it's animation file, then it is said to be not ready. Right now, this can only happen to an Animation Sequence that has an ApplyAnimation ability becuase only the ApplyAnimation ability specifies an animation file. In the future, there may be more.
If a sequence chain has an animation that is not ready, then the playing of the sequence will simply fail as if the animation did not play. However, because the animation will eventually be downloaded, this sequence will eventually be available to play in the future (which might be the very next time, or if there is a delay in getting the file, could be seconds or minutes later before it's ready).
As an alternative, a Sequence can specify a Fallback sequence. If the sequence is not ready, it will instead play the fallbacksequence. If, in turn, this sequence is also not ready, it will follow the same behavior recursively: that sequence will attempt to fallback to another sequence if one is specified (be careful not to specify a cyclic loop!).
Here is how you would specify a fallback sequence with the
! ! Animation Sequence Spec ! A crazy wave ! Fallsback to a default wave if not ready ! Version=1 FallbackSequence=default_wave [ABILITIES] Apply Animation .Animation=wave_crazily.hgm .InitialSpeed=1 .InitialLoop=false .InitialAlign=false
Consider, for the moment, the power of this feature: You could, for example, have a ton of variations of character waving animations. But not wanting all that animation data in memory at once, you elect to preload only the default_wave sequence's animation. Then when you tell a character to play one of the variations, such as the crazy wave above, it will play that only if it is available in the local cache otherwise it will play the perfectly suitable substitute of the default wave instead. In this way, you could add a plethora of wave variations at any time to your game and you'll always get an appropraite behavior. The other wave animations will be downloaded asynchronously when the Animation Set is introduced, but they don't have to delay going into the game (as is common with normal patching schemes).
Sometimes it is perfectly acceptable to have no fallback. If roleplaying animation is not in the local cache yet, and no feedback is specified for its sequence, then it will simply fail to play anything. This is fine for most situations because it'll work probably by the next time the animation is needed.
Dynamic Sequence Updates
You can update an Animation Sequence dynamically in real-time. The new Animation Sequence will be downloaded asynchronously whenever the client detects it has changed (by updating it in the Repository via the Repository Browser). When you do this, the new Sequence will be held until no characters on the client are using it anymore. It cannot update a sequence currently in use, so it delays the update until it is free and clear.
This means you can easily work with Sequence files without restarting HeroBlade. If it's a default Idle-like animation, however, it may be "held" indefinitely until you make the character play some other animation. Just causing the character to move in some way should do the trick.