First, let's talk about weights. When you put together states and layers, you'll likely use a weight based blending to bring together multiple sources. For state transitions, the weighting is mostly out of your hands as it is time-based, but for other types of weighting (such as the blending between two layers or a lerp node in a state's blend tree) you'll often find yourself wanting to directly modify it on the fly based on the current state of your game/application. Again, you run into a problem here... How to reach into an animation system and access that BlendTreeSource object or LayerBlender when it might be created and maintained outside of your control (e.g. such as by our JSON based "scripting" system.)
To address this, we've taken the actual weight value away from these types of objects and moved it to a map in the AnimationManager. The blend object itself instead maintains a key used to pull the weight from the manager. In this way, you merely have to know the key you are altering and have a link to the manager it lies under, letting your aritist/animator/tool tweak things to their heart's content.
Shifting gears, so far our animations have been all about moving skeleton joints around, but the animation system was actually built to handle any generic sample-based data set. To take advantage of that, a new type of channel called a TriggerChannel was added to give you a String-based, trigger-callback system that can be plugged into existing animations or added as standalone clips.
Here's how a trigger channel works. The channel is made up of multiple (nullable) String "samples" that change over time. For example, it might have no sample at time index 0. Then at 2 it might have a sample called "left_step" and at 4 a sample called "right_step" and at 5, null again. As the animation this channel belongs to plays, the current sample String is collected. The applier logic has access to this current string and can then act on it.
Our default applier logic acts on the string by executing callbacks associated with the given String. The callback is only called on unique samples, so while in the current sample, it will only be called once. Your callback logic can then be whatever you like... play a sound, a particle effect, trigger a different animation, etc. In the case of the above left_step, right_step, it might be programmed to play footstep sounds on the appropriate time sequences. If this was a channel in our walk state, then walking would also trigger the footstep sounds.
TriggerChannels are created/setup only in Java code currently, but they will soon be added to the JSON-based input system as well.
Here's an excerpt from AnimationDemoExample showing how you might put this together. The method shown makes a channel that has a "punch_fire" sample set at the mid point of the given source clip. The trigger callback adds (in the update queue) particles to the scene:
private void addFireballTrigger(final SimpleAnimationApplier applier, final
AnimationClip punchClip) {
final float max = punchClip.getMaxTimeIndex();
final TriggerChannel triggerChannel = new TriggerChannel("punch_fire", new
float[] { 0, max / 2, max / 2 + 0.25f }, new String[] { null, "fist_fire", null });
punchClip.addChannel(triggerChannel);
applier.addTriggerCallback("fist_fire", new TriggerCallback() {
public void doTrigger() {
GameTaskQueueManager.getManager(_canvas.getCanvasRenderer()
.getRenderContext()).update(
new Callable() {
@Override
public Void call() throws Exception {
addParticles();
return null;
}
});
}
});
} Here's a video of Ardor3D's AnimationDemoExample in action:
Finally, let's cap this series of posts off with a webstart of the AnimationDemoExample in Ardor3D. Note that I left it loading from the original Collada files, so it takes a few seconds to start. Also, it's been a while since I've packaged things for webstart, so bear with me if it doesn't work for some reason.
You'll need Java 6.0. (Mac users may need to save the jnlp to disk, then right click and open with Java Web Start.) Drag the scene with the left mouse to rotate the camera. WASD to move.