Confusion about animation blending, weights

I’m attempting to use animation weights to blend some animations, instead of using the locomotion system.

I understand the general concept I suppose, that the weights of all currently enabled animation clips should add up to 1.0 (right?), so if i for instance, enabled a walk and a run animation, and set them to both have 0.5 weight, it should be a blend of half the walk and half the run?

Basically, what I’m trying to do is dynamically play a walk forward and a strafe animation based on the character’s forward and sideways velocity (so that when the player is moving forward at full speed, the walk animation should be at 100%, and when the player is moving sideways at full speed, the side-strafe animation should be at 100%. Therefore, if he’s moving diagonally, they should be at some combination in between so it looks like hes side-stepping forward diagonally).

The speed calculations were easy, with the CharacterController velocity and some dot products with transform.forward and transform.right, now I just don’t know how to blend the weights smoothly and also smoothly blend back to the idle animation when he’s not moving.

This is about as far as I’ve gotten, save some failed experiments. Note that I’m not currently worried about the reverses (walk backward, strafe left), I just wanted to get the blending worked out before I started adding more states:

public var maxForwardSpeed : float = 5.0;
public var maxSidewaysSpeed : float = 3.0;

private var myController : CharacterController;

function Start(){

	myController = GetComponent(CharacterController);
    
    animation["walk"].enabled = true;
    animation["walk"].weight = 0;
    animation["strafeRight"].enabled = true;
    animation["strafeRight"].weight = 0;
    
}

function Update(){

    var charVelocity = myController.velocity;
    charVelocity.y = 0;
    
    var forwardMotion = Vector3.Dot(transform.forward, charVelocity);
    var sidewaysMotion = Vector3.Dot(transform.right, charVelocity);

    animation[walk].weight = forwardMotion/maxForwardSpeed;
    animation["strafeRight"].weight = sidewaysMotion/maxSidewaysSpeed;
    
}

The example in the docs about leaning doesn’t really help me, I don’t quite understand the need to use normalizedTime instead of just changing the weights.

I figured this out, also added in the functionality to blend in a run animation when the forward speed is greater than 50%; the math was a little funky to figure out the curve. I’m also controlling the animation playback speeds based on the acceleration/velocity, it results in some really nice looking animation:

public var maxForwardSpeed : float = 5.0;
public var maxSidewaysSpeed : float = 3.0;

private var myController : CharacterController;

function Start(){

    //in my setup, the animated player model is a child object of the controller
    myController = transform.parent.GetComponent(CharacterController);
    
    animation["walk"].enabled = true;
    animation["walk"].weight = 0;
    animation["walk"].layer = 1;
    
    animation["run"].enabled = true;
    animation["run"].weight = 0;
    animation["run"].layer = 1;
    
    animation["strafeRight"].enabled = true;
    animation["strafeRight"].weight = 0;
    animation["strafeRight"].layer = 1;
    
    animation["idle"].enabled = true;
    animation["idle"].weight = 0;
    animation["idle"].layer = 1;
    
    animation.SyncLayer(1);
    
}

function Update(){

    var charVelocity = myController.velocity;
    charVelocity.y = 0;
    
    var forwardMotion = Vector3.Dot(transform.forward, charVelocity);
    var sidewaysMotion = Vector3.Dot(transform.right, charVelocity);
    
    var v = forwardMotion/maxForwardSpeed;
    v *= 2;
    var walkWeight = 1.0 - Mathf.Abs(v - 1.0);
    var runWeight = Mathf.Max(0.0, v - 1.0);
    var strafeWeight = sidewaysMotion/maxSidewaysSpeed;
    
    animation["walk"].weight = walkWeight;
    animation["run"].weight = runWeight;
    animation["strafeRight"].weight = strafeWeight;
    animation["idle"].weight =  1.0 - walkWeight - runWeight - strafeWeight;
    
    animation["walk"].speed = forwardMotion/(maxForwardSpeed/2);
    animation["run"].speed = forwardMotion/maxForwardSpeed;
    animation["strafeRight"].speed = sidewaysMotion/maxSidewaysSpeed;
	  
}

If you want to add walking in reverse and strafing left, just use the absolute value of forwardMotion/sidewaysMotion, but make sure you save a boolean or something first as to whether or not it was negative, and then depending on that boolean, multiply the appropriate animation’s speed by -1.

Animations need to be on separate layers to play at the same time (to blend them.) The weights don’t need to add to 1. They are passed down from higher layer to lower. Each gets that much of the remainder, or all that’s left if on the bottom.

Ex:

animation["strafeRight"].layer = 2; // in Start. Can now mix strafe and walk/idle
// "walk" and "idle" still on layer 0
animation.Play("walk");
animation.Play("strafeRight");

// Update:
// cheap way to get 0-1 weight based on sideSpeed:
animation["strafeRight"].weight = Mathf.Abs( Input.getAxis("Horizontal") );
// NOTE: walk/idle auto-gets the rest. No need to set weight

// "standard" fade from idle/walk. Same layer, so playing one turns off the other
if( notmoving ) animation.CrossFade("idle");
else animation.CrossFade("walk");
// NOTE: strafeRight is always playing, but at weight 0 if you aren't strafing

i suggest you just create a “side-stepping forward diagonally” animation like what bootcamp demo did, they created an animation for each,its looks like hard but it works for me. I also added characterstate there.

Good for you then, good way to start.