I am using a mixture of in place and “not in place” animations, so I want to use root motion for those. When working on movement with a character controller I noticed a strange behaviour after activating apply root motion on the animator. The character moves extremely slow and I have to increase the speed drastically to get the wanted results, but the movement becomes janky. This also happens for the Starter Asset - Third Person Character Controller from the asset store.
This code to smooth the speed transition of the character seems to be the problem:
float currentSpeed = new Vector3(controller.velocity.x, 0.0f, controller.velocity.z).magnitude;
if (currentSpeed < targetSpeed - speedOffset || currentSpeed > targetSpeed + speedOffset)
{
movementSpeed = Mathf.Lerp(currentSpeed, targetSpeed, Time.deltaTime * SpeedChangeRate);
movementSpeed = Mathf.Round(movementSpeed * 1000f) / 1000f;
}
else
{
movementSpeed = targetSpeed;
}
This works until you activate root motion. After some debugging I noticed that the currentSpeed is always 0 because of it. Controller velocity only changes when it is moved by an animation otherwise even if moving by script the velocity magnitude stays 0;
Is this intended to work like this ? The documentation states: The velocity returned is simply the difference in distance for the current timestep before and after a call to CharacterController.Move or CharacterController.SimpleMove. This code uses Move() but the velocity is still 0… so what gives.
My workaround was to implement my own velocity calculation like so:
Vector3 previousPosition = transform.position;
controller.Move(moveDirection.normalized * movementSpeed * Time.deltaTime);
float distance = Vector3.Distance(previousPosition, transform.position);
currentSpeed = distance / Time.deltaTime;
Now the movement seems to work correctly with root motion.
Can anyone give me some insight into this? Is using a mix of root motion and script based movement bad practice?