Get character to face direction of movement C#

This is the code I currently have to handle movement of a character:

if (Input.GetKey("w")){
			transform.position = new Vector3 (transform.position.x, transform.position.y, transform.position.z + (float)0.1);
		}
		if (Input.GetKey("s")){
			transform.position = new Vector3 (transform.position.x, transform.position.y, transform.position.z - (float)0.1);
		}
		if (Input.GetKey("a")){
			transform.position = new Vector3 (transform.position.x-(float)0.1, transform.position.y, transform.position.z);
		}
		if (Input.GetKey("d")){
			transform.position = new Vector3 (transform.position.x+(float)0.1, transform.position.y, transform.position.z);
		}

However the character always faces the same direction and not where it goes.

For that I’m trying to use:

transform.LookAt(new Vector3());

However I can’t get it to work.

One of the ideas I had was to get vector coordinates of the current and the previous position of X and Z and put them inside that new Vector3 while Y=0 but I always get spazing out movement and weird physics.

PS: I’m using a Rigidbody

hi there, instead of (float)0.1 use 0.1f and to make the character look at the direction he’s moving look into Transforms, Vector3’s Eulers and so on. The easiest way to do it in your case is to modify the transform’s rotation to make it look from 90 to 90 degrees to the direction it’s walking.

transform.eulerAngles = new Vector3(0, 90, 0);
//or
transform.eulerAngles = new Vector3(0, 0, 0);
//and so on

Also your movement it’s not FrameRate dependable, which means that on slow hardware it’ll move way slower than on other new devices. use Time.deltaTime as a multiplier for your movement modifications.

//add the rotation change here
transform.position = new Vector3 (transform.position.x-Speed, transform.position.y, transform.position.z) * Time.deltaTime;
1 Like

Isn’t 90 too much, I think 45 would be much better.

this is, you are moving left, right, forward and backwards. that’s 90 degrees rotation.

oh I see, but won’t that look weird if I walk diagonally?

Here is one way to resolve this:

  1. At the beginning of the move calculate an angle between your forward vector and (position_you_are_moving_towards - position_of_your transform). See the code I usually use for that.
  2. Rotate your transform by that angle. (transform.Rotate(up, angle_from_step_one):wink:
	public static float getAngle(Vector3 fr, Vector3 to, Vector3 up)
	{
// http://answers.unity3d.com/questions/24983/how-to-calculate-the-angle-between-two-vectors.html		
		
		// the vector perpendicular to referenceForward (90 degrees clockwise)
		// (used to determine if angle is positive or negative)
		Vector3 referenceRight= Vector3.Cross(up, fr);
	 	 
		// Get the angle in degrees between 0 and 180
		float angle = Vector3.Angle(to, fr);
	 
		// Determine if the degree value should be negative. Here, a positive value
		// from the dot product means that our vector is the right of the reference vector
		// whereas a negative value means we're on the left.
		float sign = (Vector3.Dot(to, referenceRight) > 0.0f) ? 1.0f: -1.0f;
	 
		float finalAngle = sign * angle;
		
		return finalAngle;
		
	}

Looks like a good idea, thanks, going to give it a go.

So it’s something like this for move up:

transform.Rotate(Vector3.up, Vector3.Angle(Vector3.forward, new Vector3(transform.position.x,transform.position.y,transform.position.z) -  new Vector3(transform.position.x,transform.position.y,transform.position.z + (float)0.1)));

No.

  1. You need to use the forward vector of your character transform.
  2. Don’t use Vector3.Angle - it doesn’t take care of the sign - use the code I provided earlier.

With gravity activated it goes to (0,0,0) and then moves and if I disable gravity it just sits in (0,0,0), I get the same result using my code

any ideas ?

Sorry. I’m not sure I understand. Are you saying that when you try to move your character now it just goes to (0,0,0) and doesn’t move from there? If yes, can you post you current code that performs movement and rotation?

transform.translate is the best solution for you!

if I use your code or my version I get the same result but I tried to different things:

  • gravity on - when I move the character goes to (0,0,0) and then moves quickly in a random direction (probably has to do with the terrain been at (0,0,0) so the object get’s sliced by it)

  • gravity off - when I move the character it goes to (0,0,0) and stops.

My version:

		if (Input.GetKey("w")){
			transform.position = new Vector3 (transform.position.x, transform.position.y, transform.position.z + (float)0.1)* Time.deltaTime;
			transform.Rotate(Vector3.up, Vector3.Angle(Vector3.forward, new Vector3(transform.position.x,transform.position.y,transform.position.z) -  new Vector3(transform.position.x,transform.position.y,transform.position.z + (float)0.1)));
		}
		if (Input.GetKey("s")){
			transform.position = new Vector3 (transform.position.x, transform.position.y, transform.position.z - (float)0.1)* Time.deltaTime;
			transform.Rotate(Vector3.up, Vector3.Angle(Vector3.forward, new Vector3(transform.position.x,transform.position.y,transform.position.z) -  new Vector3(transform.position.x,transform.position.y,transform.position.z - (float)0.1)));
		}
		if (Input.GetKey("a")){
			transform.position = new Vector3 (transform.position.x-(float)0.1, transform.position.y, transform.position.z)* Time.deltaTime;
			transform.Rotate(Vector3.up, Vector3.Angle(Vector3.forward, new Vector3(transform.position.x,transform.position.y,transform.position.z) -  new Vector3(transform.position.x + (float)0.1,transform.position.y,transform.position.z )));
		}
		if (Input.GetKey("d")){
			transform.position = new Vector3 (transform.position.x+(float)0.1, transform.position.y, transform.position.z)* Time.deltaTime;
		transform.Rotate(Vector3.up, Vector3.Angle(Vector3.forward, new Vector3(transform.position.x,transform.position.y,transform.position.z) -  new Vector3(transform.position.x - (float)0.1,transform.position.y,transform.position.z)));
		}

Your code and my code have the same result.

Can you be more specific ? I may be wrong but doesn’t transform.translate deal only with postion?

12doze12 - the main problem with your code is that it multiplies your new position by deltaTime. That puts your position always very close to (0,0,0). Your code should look something like this (assuming 10 as your speed):

       if (Input.GetKey("w")){
			Vector3 pos = new Vector3 (transform.position.x, transform.position.y, transform.position.z + 10f * Time.deltaTime);
            transform.Rotate(Vector3.up, Vector3.Angle(transform.forward, pos - transform.position);
            transform.position = pos;
        }

Also, you are still not using the getAngle method I listed earlier :slight_smile: . As I said, Vector3.Angle is not going to work 100% of the time.

It works but the orientations are wrong:

-move left - point down
-move right - point up
-move up - point right
-move down - point left

Also this doesn’t work diagonally …

Why don’t you build a Vector3 instead of applying to transform.position at each step and then do a transform.LookAt(destination) before moving there?

This is the code and it’s now working, however it still has the problem of only having 4 orientations:

if (Input.GetKey("w")){
			transform.position = new Vector3 (transform.position.x, transform.position.y, transform.position.z + (float)0.1);
			transform.LookAt(new Vector3(transform.position.x,5,transform.position.z - 0.1F));
		}
		if (Input.GetKey("s")){
			transform.position = new Vector3 (transform.position.x, transform.position.y, transform.position.z - (float)0.1);
			transform.LookAt(new Vector3(transform.position.x,5,transform.position.z + 0.1F));
		}
		if (Input.GetKey("a")){
			transform.position = new Vector3 (transform.position.x-(float)0.1, transform.position.y, transform.position.z);
			transform.LookAt(new Vector3(transform.position.x + 0.1F,5,transform.position.z ));
		}
		if (Input.GetKey("d")){
			transform.position = new Vector3 (transform.position.x+(float)0.1, transform.position.y, transform.position.z);
			transform.LookAt(new Vector3(transform.position.x - 0.1F,5,transform.position.z));
		}

Probably not the best solution but I made the same for diagonals (still doesn’t looks smooth obviusly):

if (Input.GetKey("w")  Input.GetKey("d")){
			transform.position = new Vector3 (transform.position.x + (float)0.1, transform.position.y, transform.position.z + (float)0.1);
			transform.LookAt(new Vector3(transform.position.x - 0.1F ,5,transform.position.z - 0.1F));
		}
		if (Input.GetKey("w")  Input.GetKey("a")){
			transform.position = new Vector3 (transform.position.x - (float)0.1, transform.position.y, transform.position.z + (float)0.1);
			transform.LookAt(new Vector3(transform.position.x + 0.1F ,5,transform.position.z - 0.1F));
		}
		if (Input.GetKey("s")  Input.GetKey("a")){
			transform.position = new Vector3 (transform.position.x - (float)0.1, transform.position.y, transform.position.z - (float)0.1);
			transform.LookAt(new Vector3(transform.position.x + 0.1F ,5,transform.position.z + 0.1F));
		}
		if (Input.GetKey("s")  Input.GetKey("d")){
			transform.position = new Vector3 (transform.position.x + (float)0.1, transform.position.y, transform.position.z - (float)0.1);
			transform.LookAt(new Vector3(transform.position.x - 0.1F ,5,transform.position.z + 0.1F));
		}

Anyway, thanks to everyone that helped me, especially cdevl. Thanks, :slight_smile: