Character System
This module is a high-level impementation of a character with 3rd-person camera (both player-controlled and NPC). It has configuration file in XML format.
The character can be split into the following parts:
- Physical model
- Visual appearance (skin)
- Animation tree
- Camera
- Controls
Character Logic
Orientation
There is a set of parameters describing orientation of a character in space:
- Position is a coordinates of the character in space
- Angle is an orientation of the character relatively to Z axis
- Yaw is an azimuth angle of aiming (from -180 to 180 degrees)
- Pitch is a zenith angle of aiming (from -180 to 180 degrees)
Movement
There is a set of parameters describing movement of the character in space:
- Velocity is a velocity vector of the character
- Speed is a speed of the character in XOY plane
- SpeedZ is a vertical speed of the character
- RotationSpeed is a speed of Angle changing
During movement of the character in XOY plane its Angle is smoothly changed according to the direction of the movement.
If there is no movement, Angle will be changing if difference between Angle and Yaw is greater than a threshold value (turn_angle_threshold). Rotation will take place with turn_speed speed by turn_angle_threshold steps, so rotation angle will be always divisible by turn_angle_threshold (you can use this fact to create a good-looking animation of in-place turns).
States
There is a set of built-in states of the character.
MoveState:
- MOVE_STATE_IDLE means that the character isn't moving in XOY plane
- MOVE_STATE_WALK means that the character is moving with walking pace
- MOVE_STATE_RUN means that the character is moving with running pace
GroundState:
- GROUND_STATE_STAND means that the character is standing on the ground
- GROUND_STATE_CROUCH means that the character is crouching
- GROUND_STATE_JUMP means that the character is jumping (or falling)
JumpState:
- JUMP_STATE_UP means that the character is moving up
- JUMP_STATE_FLY means that the character is not moving in Z direction
- JUMP_STATE_DOWN means that the character is falling down
ActionState:
- ACTION_STATE_IDLE means that the character is doing nothing
- ACTION_STATE_FIRE means that the character is firing (or attacking somehow else)
- ACTION_STATE_USE means that the character is using an item
Height
There is a set of parameters affecting height of the character (height of its collision capsule):
- height_stand is a height of a standing character
- height_crouch is a height of a crouching character
- height_change_speed is a speed of changing of height during switching from standing to crouching state or vice versa
Actor
Actor is responsible for physical parameters of the character: movement speed, jump height, collision shape and so on. The character is approximated by a capsule in terms of collision detection.
Configuration
<actor>
<min_velocity>10</min_velocity>
<max_velocity>20</max_velocity>
<min_friction>0</min_friction>
<max_friction>1</max_friction>
<damping>1</damping>
<jumping>220.0</jumping>
<turn_speed>120</turn_speed>
<turn_angle_threshold>90</turn_angle_threshold>
<move_rotation_speed>30</move_rotation_speed>
<idle_speed_threshold>0.2</idle_speed_threshold>
<ground_threshold>0.1</ground_threshold>
<acceleration>4</acceleration>
<mass>60</mass>
<turning>90</turning>
<height_stand>7</height_stand>
<height_crouch>5</height_crouch>
<height_change_speed>5</height_change_speed>
<radius>1.7</radius>
<physical>1</physical>
<collision_mask>1</collision_mask>
<min_angle>-60</min_angle>
<max_angle>89</max_angle>
</actor>
- min_velocity is a speed of walking
- max_velocity is a speed of running
- min_friction is a friction ratio while walking
- max_friction is a friction ratio while running
- damping is a damping ratio
- jumping is a jump ratio (affects jump height)
- turn_speed is a speed of turning after rotating camera over threshold angle
- turn_angle_threshold is a threshold angle, if angle between Angle and Yaw is less than it, the character will not turn
- move_rotation_speed is a turning speed while moving
- idle_speed_threshold is a minimal speed, after that the character is treated as moving
- ground_threshold is a distance, up to which the character is considered to be on the ground. It is measured downwards from the bottom point of the character. If intersection with the ground occurred within the set distance, character walking animation will still be played. If intersected ground is further than this distance, a character will be considered flying.
- acceleration is the character acceleration while moving
- mass is mass of the character
- turning is a turning speed in degrees per second
- height_stand is a height of the standing character (affects collision detection)
- height_crouch is a height of the crouching character
- height_change_speed is a speed of changing of height during switching from standing to crouching or vice versa
- radius is a radius of the capsule, which approximates the character for collision detection
- physical is a flag, which controls whether the actor should interact with the environment as a physical object (1) or not (0), enables or disables its rigid body
- min_angle is a minimum Pitch angle at which the camera can rotate
- max_angle is a maximum Pitch angle at which the camera can rotate
Skin
Skin is responsible for visual appearance of the character. Animation is a sequence of frames, which describes transformations of the skin's skeleton bones.
<skin>
<node>demos/character/nodes/agent.node</node>
<scale>6 6 6</scale>
</skin>
Locator
Locator is a binding point, which is associated with one of the bones of the Skin's skeleton.
Configuration
<locators>
<locator name="camera">Camera_bone</locator>
<locator name="weapon">agent_pistol_rhand</locator>
</locators>
Value inside locator tag is a target bone name.
Attachment
Attachment is an arbitrary object (weapon, ammo, effects, etc), which is binded to a Locator.
Configuration
<attachments>
<attachment name="pistol" locator="weapon">demos/character/nodes/pistol.node</attachment>
</attachments>
Value inside attachment tag is a node file name, locator attribute points to name of a previously defined locator.
Camera
Camera describes a 3rd person view, following the character.
Configuration
<camera locator="camera">
<anchor>0 0 7.5</anchor>
<shift>0 0 0</shift>
<fixed_distance>1</fixed_distance>
<distance>15.0</distance>
<distance_change_speed>20.0</distance_change_speed>
<type>1</type>
<collision>1</collision>
<min_angle>-28</min_angle>
<max_angle>89.9</max_angle>
<radius>0.5</radius>
<turning>90</turning>
<z_near>0.1</z_near>
<z_far>10000</z_far>
<fov>60</fov>
<collision_mask>-1</collision_mask>
<min_distance>10</min_distance>
<max_distance>15</max_distance>
<zoom_step>2</zoom_step>
</camera>
locator attribute of the node points to name of a previously defined locator. Relative transformations of a bone associated with the locator affects the camera position (they are added to the camera transformations). Scale of the bone multiplies camera FOV.
This can be used for camera shaking while running and changing of FOV in aiming mode, for example. Since transformations of locators are controlled by animation graph, one can create different camera behaviour according to the character states.
Other options:
- anchor sets coordinates of a point in local space of the actor the camera is turning around
- shift is a shift of the camera position in local space of the camera
- fixed_distance is a flag, which controls whether distance from the anchor to the camera can be changed or not
- distance is a radius from the anchor to the camera
- distance_change_speed is a speed of changing distance from the anchor to the camera
-
type defines the camera behaviour:
- 0 means that both Yaw and Pitch angles are fixed (they depends on the Actor position)
- 1 means that Pitch angle is fixed
- 2 means that Yaw angle is fixed
- 3 means that both Yaw and Pitch angles aren't fixed
- collision defines whether collision detection of the camera with other objects should be performed or not
- min_angle is a minimal pitch angle
- max_angle is a maximal pitch angle
- radius is a radius of sphere representing the camera during collision detection
- turning is a turning speed in degrees per second
- z_near is a distance to the near clipping plane
- z_far is a distance to the far clipping plane
- fov is a field of view
- collision_mask is a collision mask for the camera's collision sphere
- min_distance is a minimal distance between the actor and the camera
- max_distance is a maximal distance between the actor and the camera
Animation Graph
Animation Graph describes logic of the character animation in form of a graph. It must contain single root Combiner (its outgoing Animation Flow is applied to the Skin).
Configuration
<animation_graph>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_walk_fwd.sanim</animation>
</combiner>
</animation_graph>
Example
Here is an example of full-featured Animation Graph (see corresponding configuration file):
Animation Flow
Animation Flow is a directed edge of an Animation Graph.
Combiner
Combiner is a node of an Animation Graph, which can be connected with other nodes. It can contain several ingoing Animation Flows and a single outgoing. There can also be Combiner Inputs and Combiner Events associated with the Combiner.
Common Configuration
<combiner type="...">
<inputs>
<input name="speed" type="function" scale="3" shift="0">Character::getSpeed</input>
</inputs>
<events>
<event on="activate" callback="CombinerAnimation::setPhase">
<arg type="function">Character::getStepPhase</arg>
</event>
<event on="update" callback="Character::setStepPhase">
<arg type="function">CombinerAnimation::getPhase</arg>
</event>
</events>
... custom data ...
</combiner>
type attribute sets type of the Combiner, it can have one of the following values:
- inputs node is a container node for Combiner Inputs
- events node is a container for Combiner Events (animation feedback)
Combiner Input
Combiner Input is an input for parameter, which contols logic of the Combiner. So Combiner's internal logic can be controlled by outside environment.
There are two types of Inputs: const (constant value) and function (a value returned from a function call). Each Input has its own name.
Const Input
A constant value.
<input name="speed" type="const">5</input>
Function Input
A sequence of values returned by a function.
<input name="pos_x" type="function" scale="0.5556" shift="50" min="0" max="100" smooth="400">Character::getYaw</input>
You can tweak the value by setting scale, shift, min, max parameters, result will be calculated according to the following formula:
result = clamp(value * scale + shift,min_value,max_value);
delta = sign(old_delta) * min(abs(old_delta),dt * smooth)
- old_delta is a difference between previous and current values
- delta is a difference between current and next values
- dt is a time period passed since last update of the parameter
Combiner Event
It is possible to assign a function call to an event occured in a Combiner. Therefore it's possible to create a logic depending on animation (animation feedback).
For example one needs to lock controls while the character is flying in the air. Let's assume that we have a Combiner in Animation Graph, which is active while the character has no contact with surface. The following is one of the CombinerSwitch's flows, which detects whether the character is staying or flying:
<!-- jump -->
<case value="2" blend_speed="5">
<combiner type="...">
<events>
<event on="activate" callback="Character::setControlEnabled">
<arg type="const">0</arg>
</event>
<event on="deactivate" callback="Character::setControlEnabled">
<arg type="const">1</arg>
</event>
</events>
... some combiner logic ...
</combiner>
</case>
Parameters:
-
on is an event type. There is a set of standart events (however, it can be extended, depending on Combiner's type):
- activate means that the Combiner is switched into active state
- deactivate means that the Combiner is switched off
- update occurs every frame
- callback is a target function name to be called
- arg is a parameter passed to the target function (there can be multiple "arg"'s, they are passed in the order of occurrence in the Event definition); syntax is similar to Combiner Input (so you can use both constant and function-produced values)
Built-In Combiners
CombinerAnimation
Description
This Combiner returns current frame of an animation loaded from a file. If the Combiner is active, it's playing animation with given speed.
Example
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_ready.sanim</animation>
<inputs>
<input name="speed" type="const">1.0</input>
</inputs>
</combiner>
Parameters
- animation is a file name
- start is a starting frame number
- end is an ending frame number (-1 means the last)
Inputs
The Combiner has only one Input, speed (frames per second, default value is 1.0, negative values are also acceptable for reverse playback).
CombinerBlend
Description
This Combiner mix two Animation Flows according to blend coefficient (if the coefficient is equal to 0.0, so outgoing Animation Flow will be the same as the first ingoing Animation Flow, if it's equal to 1.0, then outgoing Animation Flow will be the second ingoing one)
The Combiner works according to these formulas:
pos = lerp(src_pos,dst_pos,weight);
rot = slerp(src_rot,dst_rot,weight);
scale = lerp(src_scale,dst_scale,weight);
Example
<combiner type="blend">
<inputs>
<input name="weight" type="const">0.5</input>
</inputs>
<flows>
<flow>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_walk_fwd.sanim</animation>
</combiner>
</flow>
<flow>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_ready.sanim</animation>
</combiner>
</flow>
</flows>
</combiner>
Inputs
weight sets blending proportion (default value is 0.5, acceptable values are from 0 to 1).
CombinerAdd
Description
This Combiner sum up two Animation Flows.
The Combiner works according to these formulas:
pos = src_pos + dst_pos * weight;
rot = slerp(src_rot,src_rot * dst_rot,weight);
scale = slerp(src_scale,src_scale * dst_scale,weight);
Example
<combiner type="add">
<inputs>
<input name="weight" type="const">0.5</input>
</inputs>
<flows>
<flow>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_walk_fwd.sanim</animation>
</combiner>
</flow>
<flow>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_ready.sanim</animation>
</combiner>
</flow>
</flows>
</combiner>
Inputs
weight can be from 0.0 (outgoing Animation Flow is equal to the first ingoing one) to 1.0 (outgoing Animation Flow is a sum of ingoing ones), default value is 1.0.
CombinerSub
Description
This Combiner substract the second Animation Flow from the first one.
The Combiner works according to this formula:
res = Add(src,Invert(dst));
Example
<combiner type="sub">
<inputs>
<input name="weight" type="const">0.5</input>
</inputs>
<flows>
<flow>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_walk_fwd.sanim</animation>
</combiner>
</flow>
<flow>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_ready.sanim</animation>
</combiner>
</flow>
</flows>
</combiner>
Inputs
weight can be from 0.0 (outgoing Animation Flow is equal to the first ingoing one) to 1.0 (outgoing Animation Flow is equal to the first ingoing one minus the second one), default value is 1.0.
CombinerSubstitute
Description
Substitutes the first ingoing Animation Flow with transformations of bones from the second one, to be used for combination of animations. It's especially useful if one needs to override animation for some specific bones only.
Example
<combiner type="substitute">
<flows>
<flow>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_walk_fwd.sanim</animation>
</combiner>
</flow>
<flow>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_ready_torso.sanim</animation>
</combiner>
</flow>
</flows>
</combiner>
CombinerInvert
Description
Inverts an Animation Flow.
The Combiner works according to these formulas:
pos = -src_pos;
rot = inverse(src_rot)(-src_rot);
scale = 1.0/src_scale;
Example
<combiner type="invert">
<flows>
<flow>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_ready.sanim</animation>
</combiner>
</flow>
</flows>
</combiner>
CombinerIdentity
Description
Sends ingoing Animation Flow as outgoing one without modifications.
Example
<combiner type="identity">
<flows>
<flow>
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_ready.sanim</animation>
</combiner>
</flow>
</flows>
</combiner>
CombinerNull
Description
Generates empty outgoing Animation Flow, to be used for debugging purposes only.
Example
<combiner type="null"/>
CombinerSwitch
Description
Chooses one of the Animation Flows according to an Input parameter.
Input parameters are casted to int. If no case fits value of the input parameter, default one is used. Blending into the new state is performed with given speed.
Example
<!-- stand idle -->
<combiner type="switch">
<inputs>
<input name="case" type="function" scale="1" shift="0">Character::getRotationSpeedSign</input>
</inputs>
<switch>
<!-- stand -->
<case value="0" blend_speed="3">
<combiner type="animation">
<inputs>
<input name="speed" type="const">10</input>
</inputs>
<animation start="0" end="-1">demos/character/animation/agent_idle_ready.sanim</animation>
</combiner>
</case>
<!-- turninig left & right -->
<default blend_speed="5">
<combiner type="animation">
<inputs>
<input name="speed" type="function" scale="-0.455" shift="0">Character::getRotationSpeed</input>
</inputs>
<animation start="0" end="-1">demos/character/animation/agent_idle_turn_lft_90.sanim</animation>
</combiner>
</default>
</switch>
</combiner>
Parameters
- value is a condition of transition to a state (it's ignored for default case)
- blend_speed is a blending duration in 1/second
Inputs
case defines the input parameter, which is checked for matching with cases of the switch statement.
Events
Root combiners of each case have the following events:
- blend_in_start occurs when blending into a state is started
- blend_in_end occurs when blending into a state is completed
- blend_out_start occurs when blending from a state is started
- blend_out_end occurs when blending from a state is completed
CombinerLine
Description
This Combiner allows creation of a complex animations, which depends on a parameter.
For example, one needs to keep orientation of the character's torso while playing animations of running in different directions. In this case there should be animations of running forward, backward and to the left, to the right. Plus one has to pass angle between torso orientation and movement direction as an Input parameter. See the following example to get an idea of such CombinerLine usage.
Example
<!-- run -->
<combiner type="line">
<inputs>
<input name="pos" type="function">Character::getRelativeMoveAngle</input>
</inputs>
<line min="-180" max="90">
<!-- move backward -->
<key pos="-180">
<combiner type="animation">
<animation start="0" end="-1">run_backward.sanim</animation>
</combiner>
</key>
<!-- strafe left -->
<key pos="90">
<combiner type="animation">
<animation start="0" end="-1">run_left.sanim</animation>
</combiner>
</key>
<!-- move forward -->
<key pos="0">
<combiner type="animation">
<animation start="0" end="-1">run_forward.sanim</animation>
</combiner>
</key>
<!-- strafe right -->
<key pos="-90">
<combiner type="animation">
<animation start="0" end="-1">run_right.sanim</animation>
</combiner>
</key>
</line>
</combiner>
Parameters
line node has the following parameters:
- min is a minimal acceptable value of the input parameter
- max is a maximal acceptable value of the input parameter
Each key node has pos parameter, which sets a position of the key on the line.
If min or max values of the line aren't defined, they will be calculated automatically according to the available keys. Even if min and max values are set, pos values of a key can be out of the range (thus you can use only required range of values).
Inputs
pos is a current position on the line.
CombinerGrid
Description
This Combiner allows creation of a complex animations, which depends on two parameters. Keys are distributed equidistantly on a 2D grid.
For example, it can be used for complex animation of aiming (it requires 9 poses of aiming).
Example
<combiner type="grid">
<inputs>
<input name="pos_x" type="function" shift="90" min="0" max="180" smooth="400">Character::getYaw</input>
<input name="pos_y" type="function" shift="90" min="0" max="180" smooth="400">Character::getPitch</input>
</inputs>
<grid num_keys_x="3" num_keys_y="3" max_x="180" max_y="180">
<key pos_x="0" pos_y="0">
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_anim_rt_up_torso.sanim</animation>
</combiner>
</key>
<key pos_x="1" pos_y="0">
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_anim_fwd_up_torso.sanim</animation>
</combiner>
</key>
<key pos_x="2" pos_y="0">
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_anim_lt_up_torso.sanim</animation>
</combiner>
</key>
<key pos_x="0" pos_y="1">
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_anim_rt_torso.sanim</animation>
</combiner>
</key>
<key pos_x="1" pos_y="1">
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_anim_fwd_torso.sanim</animation>
</combiner>
</key>
<key pos_x="2" pos_y="1">
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_anim_lt_torso.sanim</animation>
</combiner>
</key>
<key pos_x="0" pos_y="2">
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_anim_rt_down_torso.sanim</animation>
</combiner>
</key>
<key pos_x="1" pos_y="2">
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_anim_fwd_dwn_torso.sanim</animation>
</combiner>
</key>
<key pos_x="2" pos_y="2">
<combiner type="animation">
<animation start="0" end="-1">demos/character/animation/agent_idle_anim_lt_down_torso.sanim</animation>
</combiner>
</key>
</grid>
</combiner>
Parameters
grid parameters:
- num_keys_x is a number of the grid elements in X direction
- num_keys_y is a number of the grid elements in Y direction
- max_x is a position of the last key of the grid in X direction
- max_y is a position of the last key of the grid in Y direction
- pos_x is a position of a key in X direction
- pos_y is a position of a key in Y direction
Inputs
- pos_x is a current position on the grid in X direction (default value is 0)
- pos_y is a current position on the grid in Y direction (default value is 0)
Usage
Extending Base Character
To create a character with extended logic you have to inherit your own class from Unigine::Character and extend its update() method. Plus you can add some code to save and load some extra data.
#include <scripts/character/character.h>
namespace Custom {
class CustomCharacter : Unigine::Character {
// constructor
CustomCharacter(string name) {
Unigine::Character::init(name);
}
// update character
void update(float ifps) {
Unigine::Character::update(ifps);
custom_character_logic();
}
// save character
void save(Xml xml) {
Unigine::Character::save(xml);
custom_character_save(xml);
}
// load character
void load(Xml xml) {
Unigine::Character::save(xml);
custom_character_load(xml);
}
};
}
Creating a Character
You need to call initCharacter() function to initialize the character system.
// world initialization function
int init() {
Unigine::initCharacter();
// now you create your character and place it somewhere in the world:
character = new Custom::CustomCharacter("demos/character/agent.character");
character.setPosition(vec3(23.7,-48.5,0.0));
}
Updating the Character
You have to call update() function every frame to get the character working.
// world update function
int update() {
float ifps = engine.game.getIFps();
character.update(ifps);
}
Using Parameters from the Configuration File
You can use parameters of the current character or Combiner because calling functions from namespace of the class takes active context into the account.
class Foo {
int getBarValue() {
return call("Bar::getValue");
}
};
class Bar {
Foo foo;
int value;
Bar(int value_) {
value = value_;
foo = new Foo();
}
int getValue() {
return value;
}
Foo getFoo() {
return foo;
}
int getFooBarValue() {
return foo.getBarValue();
}
};
Bar bar10 = new Bar(10);
Bar bar20 = new Bar(20);
int value;
// the following fragment doesn't work:
Foo foo = bar10.getFoo();
engine.console.print("value = %d\n",foo.getBarValue());
// this one works:
engine.console.print("value = %d\n",bar10.getFooBarValue());
engine.console.print("value = %d\n",bar20.getFooBarValue());
Here is an example of access to a parameter of the base character:
<input name="speed" type="function" scale="3" shift="0">Character::getSpeed</input>
Another example of access to an arbitrary character:
<input name="speed" type="function" scale="3" shift="0">Custom::CustomCharacter::getMyCustomParameter</input>
Character Parameters API
- int Unigine::Character::isControlEnabled() indicates whether controls is locked or not
- int Unigine::Character::isTurnEnabled() indicates whether angle between Angle and Yaw is greater than turn_angle_threshold
- float Unigine::Character::getStepPhase() returns phase of a step (to be used for sync of running and walking phases, etc)
- float Unigine::Character::getSpeed() returns speed of the character in XOY plane
- float Unigine::Character::getSpeedZ() returns vertical speed of the character
- float Unigine::Character::getYaw() returns azimuth angle of aiming relatively to Angle
- float Unigine::Character::getPitch() returns zenith angle of aiming
- float Unigine::Character::getAngle() returns Angle value
- float Unigine::Character::getRotationSpeed() returns changing speed of Angle's value
- float Unigine::Character::getRotationSpeedAbs() returns modulo of changing speed of Angle's value
- float Unigine::Character::getRotationSpeedSign() returns sign of changing speed of Angle's value
- int Unigine::Character::getJumpState() returns JumpState
- int Unigine::Character::getGroundState() returns GroundState
- int Unigine::Character::getMoveState() returns MoveState
- int Unigine::Character::getActionState() returns ActionState
Character Events API
Here is the list of character functions, which can be used as events:
- void Unigine::Character::setControlEnabled(int state) is used to enable/disable controls
- void Unigine::Character::setTurnEnabled(int state)is used to enable/disable in-place turns
- void Unigine::Character::setStepPhase(float step_phase_) sets phase of the step
There are also Combiner's functions, which can be used as events:
- float Unigine::CombinerAnimaiton::getPhase() gets phase of the animation (return values are from 0.0 to 1.0, where 0.0 means the first frame and 1.0 is for the last one)
- void Unigine::CombinerAnimaiton::setPhase(float phase) sets phase of the animation
Phase Sync
You can sync phases of walking and running by the following method:
<!-- stand run -->
<case value="2" blend_speed="5">
<combiner type="animation">
<inputs>
<input name="speed" type="function" scale="1.7" shift="0">Character::getSpeed</input>
</inputs>
<events>
<!-- get a current step phase to the current combiner when the combiner becomes active -->
<event on="activate" callback="CombinerAnimation::setPhase">
<arg type="function">Character::getStepPhase</arg>
</event>
<!-- set a current step phase to the current character when the combiner is updated -->
<event on="update" callback="Character::setStepPhase">
<arg type="function">CombinerAnimation::getPhase</arg>
</event>
</events>
<animation start="0" end="-1" speed="10">demos/character/animation/agent_run_fwd.sanim</animation>
</combiner>
</case>