Skip to content

Animation Parameters

Wyatt Gillette edited this page Apr 28, 2022 · 8 revisions

Animation Parameters are variables that are defined within an Animator Controller that can be accessed and assigned values from scripts. This is how a script can control or affect the flow of the state machine. For example, a script can set a parameter to control a Blend Tree.

They can be of four basic types:

  • Integer - a whole number
  • Float - a number with a fractional part
  • Bool - true or false value
  • Trigger - a boolean parameter that is reset by the controller when consumed by a transition

Parameters can be assigned values from a script using functions in the AnimatorController class: setFloat, setInt, setBool, setTrigger and resetTrigger.

Usage Example 1: Int and Float parameters

Variables of type Float can be configured with the following conditions and require a threshold value:

  • AnimatorConditionMode.Greater
  • AnimatorConditionMode.Less

Variables of type Int can be configured with the following conditions and require a threshold value:

  • AnimatorConditionMode.Greater
  • AnimatorConditionMode.Less
  • AnimatorConditionMode.Equals
  • AnimatorConditionMode.NotEquals
// Create the controller and add it to the player node.
AnimatorController animator = new AnimatorController(animComposer);
player.addControl(animator);

// Create the parameters by which you want to control the transitions between states.
animator.addParameter("moveSpeed", AnimatorControllerParameterType.Float);

// Define states for animations.
AnimatorStateMachine sm = animator.getLayer(AnimComposer.DEFAULT_LAYER).getStateMachine();
AnimatorState idle = sm.addState("IdleState", "idle");
AnimatorState walk = sm.addState("WalkState", "walking_inPlace");

// Define the transitions and conditions for each state using the previously created parameters.
AnimatorStateTransition idleToWalk = idle.addTransition(walk);
// changes state when the 'moveSpeed' parameter is greater than 1 
idleToWalk.addCondition(AnimatorConditionMode.Greater, 1f, "moveSpeed");

AnimatorStateTransition walkToIdle = walk.addTransition(idle);
// changes state when the 'moveSpeed' parameter is less than 0.8 
walkToIdle.addCondition(AnimatorConditionMode.Less, 0.8f, "moveSpeed");

// Don't forget to set the initial state.
sm.setDefaultState(idle);

Now you can control the state machine through the parameters you defined earlier..

public class PlayerMovementControl extends AbstractControl {

    private Camera camera;
    private AnimatorController animator;
    private BetterCharacterControl bcc;

    private final Quaternion dr = new Quaternion();
    private final Vector3f cameraDir = new Vector3f();
    private final Vector3f cameraLeft = new Vector3f();
    private final Vector3f walkDirection = new Vector3f();
    private boolean _MoveForward, _MoveBackward, _TurnLeft, _TurnRight;

    ...

    @Override
    public void controlUpdate(float tpf) {

        camera.getDirection(cameraDir).setY(0);
        camera.getLeft(cameraLeft).setY(0);

        walkDirection.set(0, 0, 0);

        if (_MoveForward) {
            walkDirection.addLocal(cameraDir);
        } else if (_MoveBackward) {
            walkDirection.subtractLocal(cameraDir);
        }
        if (_TurnLeft) {
            walkDirection.addLocal(cameraLeft);
        } else if (_TurnRight) {
            walkDirection.subtractLocal(cameraLeft);
        }

        walkDirection.normalizeLocal();
        boolean isMoving = walkDirection.lengthSquared() > 0;

        if (isMoving) {
            // smooth rotation
            float angle = FastMath.atan2(walkDirection.x, walkDirection.z);
            dr.fromAngleNormalAxis(angle, Vector3f.UNIT_Y);
            spatial.getWorldRotation().slerp(dr, m_TurnSpeed * tpf);
            bcc.setViewDirection(spatial.getWorldRotation().mult(Vector3f.UNIT_Z));
        }

        bcc.setWalkDirection(walkDirection.multLocal(m_MoveSpeed));

        animator.setFloat("moveSpeed", bcc.getVelocity().length());
    }
}

Usage Example 2: Boolean parameter

Variables of type Boolean can be configured with the following conditions and do not need a threshold value that can be set to 0 as it will be ignored:

  • AnimatorConditionMode.If
  • AnimatorConditionMode.IfNot
AnimatorController animator = new AnimatorController(animComposer);
player.addControl(animator)

animator.addParameter("isRunning", AnimatorControllerParameterType.Bool);

// Define states for animations.
AnimatorStateMachine sm = animator.getLayer(AnimComposer.DEFAULT_LAYER).getStateMachine();
AnimatorState idle = sm.addState("IdleState", "idle");
AnimatorState run = sm.addState("RunnigState", "running_inPlace");

AnimatorStateTransition idleToRun = idle.addTransition(run);
// change state when 'isRunning' parameter is equals to true
// the threshold can be set to zero because it will be ignored
idleToRun.addCondition(AnimatorConditionMode.If, 0, "isRunning"); 

AnimatorStateTransition runToIdle = run.addTransition(idle);
// change state when 'isRunning' parameter is equals to false
// the threshold can be set to zero because it will be ignored
runToIdle.addCondition(AnimatorConditionMode.IfNot, 0, "isRunning"); 

// set the initial state.
sm.setDefaultState(idle);

// Then activate the transition in the PlayerControl
animator.setBool("isRunning", true);

You can now access the AnimatorController variables to perform other actions such as turning on / off the sound of footsteps

public class FootstepsControl extends AbstractControl {

    private AnimatorController animator;
    private AudioNode footstepsSFX;

    ...

    @Override
    public void controlUpdate(float tpf) {
        if (animator.getBool("isRunning")) {
            footstepsSFX.play();
        } else {
            footstepsSFX.stop();
        }
    }

}

Usage example 3: Trigger parameter

Trigger variables only work with AnimatorConditionMode.If and do not need a threshold value that can be set to 0 as it will be ignored. If you have to wait for an animation to finish before transitioning to another state, specify in the transition the percentage of completion between 0 and 1 that the animation must perform before changing state.

AnimatorController animator = new AnimatorController(animComposer);
player.addControl(animator);

animator.addParameter("isJumping", AnimatorControllerParameterType.Trigger);
		
// Define states for animations.
AnimatorStateMachine sm = animator.getLayer(AnimComposer.DEFAULT_LAYER).getStateMachine();
AnimatorState idle = sm.addState("IdleState", "idle");
AnimatorState jump = sm.addState("JumpState", "jump_inPlace");

AnimatorStateTransition idleToJump = idle.addTransition(jump);
// changes state when the 'isJumping' parameter is activated by the trigger 
// the threshold can be set to zero because it will be ignored
idleToJump.addCondition(AnimatorConditionMode.If, 0, "isJumping"); 

// execute 90% of the jump animation before returning to idle state
AnimatorStateTransition jumpToIdle = jump.addTransition(idle, 0.90f); 

// set the initial state.
sm.setDefaultState(idle);	

Then activate the trigger in the PlayerControl

public class PlayerControl extends AbstractControl implements ActionListener {

    @Override
    public void onAction(String name, boolean isPressed, float tpf) {
            if (name.equals(InputMapping.JUMP) && isPressed) {
                animator.setTrigger("isJumping");
            }
        }

        ...
}
Clone this wiki locally