Hello there, we are experiencing some problems with our blend tree setup inside our Rootmotion Playercontroller. Our idle is outside of the walk/run blendtree and we are using start and stop motions. Everything is fine really, except for if you want to strafe from left to right too quick and especially when trying to transition from walking forward to backward and trice versa. It looks really stuttery and feels uncomfortable in those cases. We looked into the kubold playmaker controller and we are trying to copy it one by one just with C# code. Animator and transitions are all the same between us and theirs. It’s a problem that has been bugging us for a while now with multiple playercontrollers, with the only way to fix this beeing to include the idle animation inside the walk blendtree, but for this project we want to know how it’s really done. Any ideas?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BasicPlayerController : MonoBehaviour
{
#region Vabrialen
// Grounded
public Collider mCharacterCollider;
public float mGroundedOffset = 0.1f;
float mDisstanceToTheGround;
Animator mAnimator;
Transform mCamera;
Rigidbody mRigidbody;
// Input Settings
float mHorizontal;
float mVertical;
float mRunFactor = 0.5f;
float InputMagnitude;
float InputAngle;
Vector3 rDirection;
bool IsFalling = false;
#endregion
#region Start
private void Start()
{
mAnimator = this.GetComponent<Animator>();
mCamera = Camera.main.transform;
mRigidbody = this.GetComponent<Rigidbody>();
if (mAnimator == null || mRigidbody == null ||
mCharacterCollider == null)
return;
mAnimator.speed = 1.05f;
mAnimator.applyRootMotion = true;
mDisstanceToTheGround = mCharacterCollider.bounds.extents.y;
}
#endregion
#region Update
private void Update()
{
CheckGrounded();
ControllerInput();
}
#endregion
#region LateUpdate
// Maybe FixedUpdate ???
void LateUpdate()
{
if (mAnimator == null || mCamera == null)
return;
rDirection = new Vector3(mHorizontal, 0, mVertical);
InputMagnitude = rDirection.magnitude;
InputAngle = Vector2.SignedAngle(new Vector2(transform.forward.x, transform.forward.z), new Vector2(Camera.main.transform.forward.x, Camera.main.transform.forward.z));
InputAngle += Vector3.SignedAngle(transform.TransformVector(rDirection), transform.forward, Vector3.up);
InputAngle = InputAngle * -1;
mAnimator.SetFloat("InputMagnitude", InputMagnitude *= mRunFactor);
if (InputMagnitude > 0.2f)
{
RotateToCameraDirection(mCamera);
mAnimator.SetFloat("WalkStartAngle", InputAngle);
mAnimator.SetFloat("WalkStopAngle", InputAngle);
mAnimator.SetFloat("Horizontal", rDirection.x *= mRunFactor, 0.25f, Time.deltaTime);
mAnimator.SetFloat("Vertical", rDirection.z *= mRunFactor, 0.25f, Time.deltaTime);
mAnimator.SetFloat("InputAngle", InputAngle, 0.15f, Time.deltaTime);
}
mAnimator.SetBool("IsFalling", !IsFalling);
}
#endregion
#region Functions
private void RotateToCameraDirection(Transform mLookTransform)
{
Quaternion rotation = Quaternion.LookRotation(mLookTransform.forward);
rotation = new Quaternion(0.0f, rotation.y, 0.0f, rotation.w);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * 5f);
}
public bool CheckGrounded()
{
bool IsGrounded = Physics.Raycast(mCharacterCollider.bounds.center, Vector3.down, mDisstanceToTheGround + mGroundedOffset);
return IsFalling = IsGrounded;
}
public void OnAnimatorMove()
{
Vector3 rootMotion = mAnimator.deltaPosition;
Vector3 currentVelocity = mRigidbody.velocity;
Vector3 animatorVelocity = rootMotion / Time.deltaTime;
animatorVelocity.y = currentVelocity.y;
mRigidbody.velocity = animatorVelocity;
Vector3 animatorAngularVelocity = mAnimator.angularVelocity;
mRigidbody.angularVelocity = animatorAngularVelocity;
}
#endregion
#region Input
public void ControllerInput()
{
mHorizontal = Input.GetAxisRaw("Horizontal");
mVertical = Input.GetAxisRaw("Vertical");
// Test Running
mRunFactor = Input.GetKey(KeyCode.LeftShift) ? mRunFactor = 2.0f : mRunFactor = 0.5f;
}
#endregion
}