I’m using the following code for my player controller:
public class PlayerController : MonoBehaviour
{
//Components
[SerializeField] Camera gameCamera;
[SerializeField] Rigidbody playerbody;
//Physics Constants
private float acc = 0.0703125f;
private float frc = 0.0703125f;
private float top = 9f;
//Inputs
public Vector3 moveInput;
public Vector3 localizedInput;
//Coroutines
Coroutine turnCoRt;
//On Move is called when activity from the Move InputAction is detected.
public void OnMove(InputValue value)
{
Vector2 rawInput = value.Get<Vector2>();
moveInput = new Vector3(rawInput.x, 0, rawInput.y);
if (moveInput != Vector3.zero)
{
//Get direction of input relative to the camera direction.
localizedInput = GetLocalizedInput();
if (turnCoRt != null) StopCoroutine(turnCoRt);
turnCoRt = StartCoroutine(Turn());
}
else
{
//Get direction of input relative to the camera direction.
localizedInput = Vector3.zero;
if (turnCoRt != null) StopCoroutine(turnCoRt);
}
}
//Update is called once per frame.
private void Update()
{
localizedInput = GetLocalizedInput();
}
// FixedUpdate is called once per fixed timestep frame.
void FixedUpdate()
{
if (moveInput != Vector3.zero)
{
Accelerate(acc);
}
else
{
Decelerate(frc);
}
}
void Accelerate(float acc)
{
if (playerbody.velocity.magnitude < top)
{
if (playerbody.velocity.magnitude + acc < top)
{
playerbody.AddForce(acc * localizedInput, ForceMode.VelocityChange);
}
else
{
playerbody.AddForce((top - playerbody.velocity.magnitude) * localizedInput, ForceMode.VelocityChange);
}
}
}
void Decelerate(float dec)
{
if (playerbody.velocity.magnitude > 0)
{
if (dec < playerbody.velocity.magnitude)
{
playerbody.AddForce(dec * -playerbody.velocity.normalized, ForceMode.VelocityChange);
}
else
{
playerbody.velocity = Vector3.zero;
}
}
}
Vector3 GetLocalizedInput ()
{
Vector3 camVector = Vector3.ProjectOnPlane(gameCamera.transform.forward, transform.up).normalized;
Quaternion camRotation = Quaternion.FromToRotation(Vector3.forward, camVector);
Vector3 result = camRotation * moveInput;
return result;
}
IEnumerator Turn ()
{
for (float r = 0; r < 1; r += Time.deltaTime)
{
if (r > 1) r = 1;
transform.rotation = Quaternion.Slerp(Quaternion.LookRotation (transform.forward, transform.up), Quaternion.LookRotation (localizedInput, transform.up), r);
playerbody.velocity = transform.forward * playerbody.velocity.magnitude;
yield return null;
}
for (; ; )
{
transform.rotation = Quaternion.LookRotation(localizedInput, transform.up);
playerbody.velocity = transform.forward * playerbody.velocity.magnitude;
yield return null;
}
}
}
This gives the desired effect most of the time but occasionally, when holding left or right to turn, the character will be rotated 180 degrees around the Y axis for a single frame before returning to the intended rotation on the next. Can anybody figure out what’s causing it?