How do I face my character in the direction the player is moving?

This seems like it should be something simple, but how do I simply set the character the character is using in the direction the player is moving in? I’ve been playing with this topic all day and haven’t found anything that even remotely works. If anyone has played any Diablo style action adventure games, then you can imagine the way this functions. The rotation should happen on the y axis as the character on the screen adjusts to whatever direction the player is moving in.

All of the options I’ve looked at does some crazy rotation stuff with the transform, and that just seems overly complicated for what should be:

Moving left?
Character faces left.

Instantly looking right?
Character faces right.

Not sure what’s going on with this, but my theory says take whatever direction the movement vector is going, then look in that direction.

Anyone have any ideas?

3 Answers

3

You can set the rotation of the character using Quaternion.LookRotation.
For example…

GameObject character;

character.transform.rotation = Quaternion.LookRotation(Vector3.forward, Vector3.up);

That will make the character face forward. You can change the first Vector3 to any direction you want, and the character will face that direction

Jarz, beginners should really just use "LookAt" rather than touching quaternions for any reason

That's great if you want the character to look in one direction :P

Thank You So Much You Saved My Life :')

Apply this to your game object to look in the direction of your movementVector:

transform.LookAt(transform.position + movementVector);

EDIT: (I first responded in a comment then realized I should’ve edited my answer)

Your sample code helps us understand what you want to accomplish a bit better. I think there are a couple of reasons you’re not seeing what you want to see with your current code.

One issue I see is that you’re moving your CharacterController in a relative direction (using the direction = transform.TransformDirection(direction)), but rotating with the world absolute of Vector3(cordX, 0, cordZ), so the two won’t match.

And also, since your relative direction changes every single frame based on your new forward direction, your movement direction will probably just be spinning around your current location since, say, moving to the right relative to where you are will make you go in a tiny circle.

The error you see about the look rotation viewing vector being 0 is that you’re not checking for your direction vector to be (0,0,0), which will cause that error.

If you want the relative movement, you might want to use a damping so that you won’t spin in place every frame. I took your code and made a few modifications. Not sure if this is what you want, and I don’t know what else you have attached to this game object besides your CharacterController, but the following might do something like you want?

using UnityEngine;
using System.Collections;

public class CCTest : MonoBehaviour {
	
	public float rotateDegreesPerSecond = 180.0f;
	private Vector3 direction = Vector3.zero;
	public float moveSpeed = 10.0f;	
	public float gravity = 10.0f;
	
	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {
	
		CharacterController CharacterMove = GetComponent<CharacterController>();
		float cordX = Input.GetAxis("Horizontal");
		float cordZ = Input.GetAxis("Vertical");
		 
		if (CharacterMove.isGrounded) {
 
			direction = new Vector3(cordX, 0, cordZ);
			direction = transform.TransformDirection(direction);
		 
		}
		
		// If direction is not zero, rotate towards direction (via rotateDegreesPerSecond) and move CharacterController in current forward vector
		if(direction != Vector3.zero)
		{
			// Take care of direction being directly behind our current forward vector since the 
			// Quaternion.RotateTowards will continuously alternate between right and left rotations to get there,
			// resulting in never getting there, just wiggling around the current transform.rotation.
			if(Vector3.Angle(transform.forward, direction) > 179)
			{
				// This will cause us to always turn to the right to go the opposite direction
				direction = transform.TransformDirection(new Vector3(.01f, 0, -1));
			}
			transform.rotation = Quaternion.RotateTowards( transform.rotation, Quaternion.LookRotation(direction), rotateDegreesPerSecond * Time.deltaTime);

			Vector3 moveDirection = transform.forward;
			moveDirection.y -= gravity * Time.deltaTime;
			CharacterMove.Move(moveDirection * moveSpeed * Time.deltaTime);
		}
	}
}

Be careful with this one - movementVector.y must be zero or your dude will tilt. Hilarious, but probably not the intended effect. :)

dude you meant non-zero, right ?

Yeah, I didn't know what type of game OP needed this for, but sounded like it was using fairly simple movementVectors, like (1,0,0) or (-1,0,0), at least in his example. But like you said, if the game is only moving in XY plane, just make sure Y component is 0, and in any case, make sure your movement vector is not Vector.zero.

Thanks for the information, Whebert. Unfortunately, now the character won't move at all. I have to get some work done around the house, but once I finish I'll look more closely at what was done.

I threw the above code on a game object with a CharacterController attached, and it moved when I tested it with the WASD keys. If your object used to move with CharacterMove.Move, then I would think it should now.

I’m writing a game with Diablo-style movement.

I have placed the “ground plane” at height 0 and turned off its material renderer (so it’s invisible) There is no 3rd dimension (hills) in my game, but you could easily account for height in yours by adding a fixed value along the Y axis with your ground-based collider. (I have 0 hard coded at the appropriate spot.)

At any rate, here is the actual code that makes the character look at the mouse (and even better, I don’t do it right away, I do it over time so there’s a rotation speed.)

using UnityEngine;
using System.Collections;

public class MainMovement : MonoBehaviour {
	private float lookSpeed = 200;
	
	void Start () {
	}
	
	void FaceInput() {
		GameObject shipModel = GameObject.Find("ShipModel"); // Necessary because I have a few objects all packaged together in to one prefab and not all of it needs to rotate.
		Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
		RaycastHit hitLocation;
		if(Physics.Raycast(mouseRay, out hitLocation)){
			Vector3 deltaLook = new Vector3(hitLocation.point.X, 0, hitLocation.Z) - this.transform.position; // Here, 0 is a hard-locked Y value. This is where you'd account for terrain height if you wanted. Most likely by using the model's Y value - not the raycast Y value so that the model doesn't "tilt" up or down.
			Quaternion targetRotation = Quaternion.LookRotation(deltaLook);
			shipModel.transform.rotation = Quaternion.RotateTowards(shipModel.transform.rotation, targetRotation, Time.deltaTime * lookSpeed); // LookAt is immediate, RotateTowards will go over time
		}
	}
	
	void Update () {
		FaceInput();
	}
}