- Home /
Rotate Character towards Movement Direction
Might seem like a relatively simple thing but it's just not working for me, all the answers I've found online do not work.
I want my character to face the direction he moves when strafing, moving forwards, or backwards. Quaternion.LookRotation causes him to spin rapidly and I can't feed a transform.Rotate(moveDirection) into Y only when he needs to move for both X and Z
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(Rigidbody))]
public class PlayerMovement : MonoBehaviour
{
public CharacterController characterController;
public Animator anim;
public Camera cam;
public float moveSpeed = 5f;
public float turnSpeed = 15f;
public float gravity = 21f;
private float h;
private float v;
private float s;
private float mh;
private float mv;
private float deadZone = 0.1f;
private Vector3 moveDirection = Vector3.zero;
private Vector3 turnDirection = Vector3.zero;
void Awake()
{
//need access to the character controller and animator
anim = GetComponentInChildren<Animator> ();
characterController = GetComponent<CharacterController> ();
cam = Camera.main;
}
void Update()
{
//cache the inputs
h = Input.GetAxis ("Horizontal");
v = Input.GetAxis ("Vertical");
s = Input.GetAxis ("Strafe");
mh = Input.GetAxis ("Mouse X");
mv = Input.GetAxis ("Mouse Y");
moveDirection = Vector3.zero;
//check if it's grounded, otherwise player cannot move, also check for the deadzone
if(characterController.isGrounded)
{
ProcessVerticalMovement(v);
ProcessHorizontalMovement(h, mh, s);
//normalize the diagonal inputs to prevent values above 1
if (moveDirection.magnitude > 1)
{
moveDirection.Normalize ();
}
moveDirection = transform.TransformDirection(moveDirection);
}
//set the animator's Speed float to the magnitude of the moveDirection to allow for the run animation to play
anim.SetFloat ("Speed", moveDirection.magnitude);
//calculate gravity
moveDirection.y -= gravity * Time.deltaTime;
//move the character
characterController.Move (moveDirection * moveSpeed * Time.deltaTime);
transform.Rotate(turnDirection * Time.deltaTime);
transform.Rotate (0f, moveDirection.x, 0f);
//transform.rotation = Quaternion.LookRotation(moveDirection);
}
void ProcessVerticalMovement(float v)
{
if (v > deadZone || v < -deadZone)
{
moveDirection = new Vector3 (0f, 0f, v);
}
}
void ProcessHorizontalMovement(float h, float mh, float s)
{
//if player is holding RMB while horizontal input then strafe
if((s > deadZone || s < -deadZone) || (Input.GetButton("CameraTurn") && (h > deadZone || h < -deadZone)))
{
Debug.Log ("strafing");
if(s > deadZone || s < -deadZone)
{
moveDirection.x = s;
}else
moveDirection.x = h;
}
//if player is pressing horizontal input then turn, or if player has RMB down (but not horizontal input) then turn
if(Input.GetButton("CameraTurn") && (mh > deadZone || mh < -deadZone))
{
turnDirection = new Vector3(0f, mh * 200f, 0f);
}else if(!Input.GetButtonDown("CameraTurn") && (h > deadZone || h < -deadZone))
{
turnDirection = new Vector3(0f, h * turnSpeed, 0f);
}else
turnDirection = Vector3.zero;
}
}
If he faces the direction and he's moving backward - isn't that forward?
Answer by gfoot · Jan 15, 2014 at 01:08 AM
The problem is probably that your user input is interpreted relative to the transform, and on the basis of that input you also update the transform's orientation - which means that on the next frame, the user's input is interpreted differently again. Unless the user input is straight up, it's going to spin on the spot really quickly.
If this really is the behaviour you want, but you want it to happen slower, then you could use Quaternion.LookRotation in the way you are now to work out which way you'd like the character to face, then use Quaternion.RotateTowards or similar to limit the rate at which the character actually turns. This means that an input that's slightly to the side will still cause the character to turn continuously, but at a much slower rate, and the player will have ample opportunity to control the turning and straighten up when the character has turned enough.
Quaternion wanted_rotation = Quaternion.LookRotation(moveDirection);
transform.rotation = Quaternion.RotateTowards(transform.rotation, wanted_rotation, MaxTurnSpeed * Time.deltaTime);
MaxTurnSpeed is measured in degrees per second - try starting with something like 200 and see how it feels.
That causes the character to rotate facing the ground (90 on x), then when I move him he spins all over the place.
I had to re-write my sidestep system but in the end I got it working using this method. Thanks