Animation system¶
The animation system can animate hierarchies of entities and shapes, e.g., a character or a chest the player should be able to open. Animations can also be layered and blended hierarchically, making it possible to, for example, apply a hit animation, which only affects the upper body, on top of a running walk cycle.
Preparing entities for animation¶
If you want to prepare a hierarchy of entities and shapes for animating, all entities participating in the animation must be tagged with an Animation Node component. Animation Nodes only have a single property that assigns each node a symbolical name, which is then used to map the animation data to the runtime transformation data.
The following screenshot shows a character with a simple rig defined by tagging each of the participating entities using an Animation Node component:
As shown in the screenshot above, the hierarchy defined by the Animation Nodes is visualized in the editor. Nodes participating in the animation (which which thus own an Animation Node component) are visualized in green. Nodes which are not directly animated, are visualized in gray.
After this process, playing a matching animation on the entity hierarchy is possible.
Playing animations via the editor¶
The simplest way to test an animation is via the editor. To play an animation, select the root entity of the hierarchy you want to animate. Right-click on the entity in the World Inspector, select [Animations] => [Play Animation]
, and choose an animation that fits the given hierarchy of entities. You can also use the [Animations]
context menu to loop, layer, and stop animations.
Working with the animation system¶
When working on your game, you can play, layer, suspend, and stop animations via the native C or Lua API.
Note
To see the animation system in action, check out the animation sample in our repository.
Here’s a simple snippet that showcases the usage of the animation system via a Lua script:
Node.load()
Math.load()
AnimationSystem.load()
function OnActivate(entity)
-- The time passed since this script was activated
Time = 0.0
-- Retrieve the node of the entity this script is attached to
local n = Node.get_component_for_entity(entity)
-- Prepare the description for the animation we want to play
local desc = AnimationSystem.AnimationDesc()
-- The name of the animation to play
desc.animation_name = "anination_a"
-- Loop the animation until we stop it manually
desc.looping = true
-- Play the animation on the root node node of the hierarchy
-- we've retrieved earlier
AnimInstanceA = AnimationSystem.play_animation(n, desc)
-- Prepare an animation to layer on top of the base animation
desc.animation_name = "animation_b"
desc.looping = true
-- Player the animation at twice the speed
desc.play_speed = 2.0
-- Blend it out initially, so we can blend it in manually later on
desc.blend_weight = 0.0
-- Play the second animation
AnimInstanceB = AnimationSystem.play_animation(n, desc)
end
function OnTick(entity)
-- Advance time
Time = Time + delta_t
-- As an example, blend the layered animation in and out
AnimationSystem.set_blend_weight(AnimInstanceB, Math.sin(Time) * 0.5 + 0.5)
end
function OnDeactivate(entity)
AnimationSystem.stop_animation(AnimInstanceA)
AnimationSystem.stop_animation(AnimInstanceB)
-- Alternatively, stop all animations on the root node
-- local n = Node.get_component_for_entity(entity)
-- AnimationSystem.stop_animations(n)
end
In the example, we’re playing a base animation on the node of the entity the script is attached to. In addition, we’re playing an animation on top, which is initially blended out and won’t affect the base layer animation. Over time, using the sine function, we’re gradually blending in and out of the top layer animation. When the component is deactivated, either when the entity gets destroyed or the component itself, we’re stopping both animations.
Working with the animation system via the native C API works analogously.