Rotate sprite to face direction

Hi.

Guess question is a common one, but I haven’t been able to find a solution that works in my case.

I have a 2D game which operates on the X and Y axis. Z is depth.

My gameobjects move around based on a direction, which is a Vector2.

My problem is that I can’t make the gameobjects/sprites rotate to face the direction they are moving. They look up all the time.
Have tried different solution, but nothing have worked correctly yet - even though this should be, in my mind, a pretty simple thing to do.

Here is my script on the gameobjects. It does a little more than move, but even though that snot the interesting thing here, I choose to show the entire script so it’s hopefully easier to help :slight_smile:

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(Rigidbody2D))]
public class WanderMovement : MonoBehaviour 
{
	private float _speed = 6.0f;
	private Transform _transform;
	public Vector2 _direction;
	private bool _isColliding = false;
	private float _rotationAngle = 0f;
	private Vector3 _lastPosition;

	void Start () 
	{
		_transform = rigidbody2D.transform;
		_lastPosition = _transform.position;

		//Start moving in random direction
		_direction = new Vector2(Random.Range(-1.0f, 1.0f),
		                         Random.Range(-1.0f, 1.0f));
		_direction.Normalize();
	}

	void FixedUpdate () 
	{
		if(_isColliding == false)
		{
			_lastPosition = _transform.position;
			_rotationAngle = 0f;

		}
		else
		{
			_transform.position = _lastPosition;
			_rotationAngle -= 50.0f * Time.deltaTime;

			_direction = Quaternion.AngleAxis(_rotationAngle, Vector3.forward) * _direction;
			_direction.Normalize();

			_isColliding = false;
		}


		_transform.Translate(_direction * _speed * Time.deltaTime);
		Debug.DrawRay(_transform.position, _direction, Color.red);

	}

	void OnTriggerEnter2D(Collider2D other)
	{
		_isColliding = true;
	}

	void OnTriggerStay2D(Collider2D other)
	{
		_isColliding = true;
	}
}

A couple issues I can spot are that you’re using non-physics movement on a physics object inside of FixedUpdate. You should be using Rigidody2D.AddForce() to move your gameobject around and not Translate because Translate does not take into account any physics. You may or may not even need physics so this could just be a use-case issue and you’re actually doing what you intend so feel free to ignore me. :stuck_out_tongue:

Secondly, you can either set the rotation using transform.Rotate() which accepts a Vector3 (and rotates on the Z axis) or using Rigidbody2D.AddTorque() – Again, if you are not wishing to use physics movement the ignore this.

Hopefully this helps you on your way.
Cheers,
Mike

Well, I’m aware how I set the rotation, it’s calculating the right value that’s the problem :slight_smile:

The reason I have the rigidbody2D is because I need the triggers to fire. As far as I know, I need a rigidbody2D for that.

But I will take your other input into account, but right now, that’s not the problem :slight_smile:

Sorry, yes, you’re correct about triggers. Here’s what I’ve come up with.

Add this underneath isColliding = false in your FixedUpdate, line 42 I think.

Vector3 newDir = Vector3.RotateTowards(_transform.forward, _direction, _speed, 0.0F);
newDir = new Vector3(0,0,newDir.z);
_transform.rotation = Quaternion.LookRotation(newDir);

This should rotate your gameobject in the direction it’s moving.

Hmm, might work but I get a:

Look rotation viewing vector is zero
UnityEngine.Quaternion:LookRotation(Vector3)
WanderMovement:FixedUpdate() (at Assets/GameAssets/Scripts/WanderMovement.cs:54)

Am doing this now, but doesn’t seem to work…?

Vector3 newDir = Vector3.RotateTowards(_transform.forward, _direction, _speed, 0.0f);

if(newDir != Vector3.zero)
{
newDir = new Vector3(0,0,newDir.z);
Debug.Log("Newdir: " +newDir);
_transform.rotation = Quaternion.LookRotation(newDir);
}

Ok, fixed the error/warning now…but they still don’t rotate… :frowning:

Vector3 newDir = Vector3.RotateTowards(_transform.forward, _direction, _speed, 0.0f);
newDir = new Vector3(0,0,newDir.z);

if(newDir != Vector3.zero)
{
Debug.Log("Newdir: " +newDir);
_transform.rotation = Quaternion.LookRotation(newDir);
}

Hmm, seem to be a error on the page here, so can’t update the post above.

The problem, right now, seem to be that newDir is always Zero.

Vector3 newDir = Vector3.RotateTowards(_transform.forward, _direction, 100f, 0.0f);
newDir = new Vector3(0,0,newDir.z);

Back to the drawing board. Will report back with results.

Man, you really ARE THE Unitylover! :smile:

Love it - thanks man! :smile:

Do you use BitBucket (Git) If so, I can give you access? So you can run it yourself…it’s a REALLY simple game right now…but might be easier if you can see it?

Seriously, no one knows how to rotate a sprite based on a Vector2 direction?

Hmm, am I building this game totally wrong since no one knows it?

:slight_smile:

I have not used BitBucket but am not opposed to it. I really want to help you with this because the solution will benefit us both. I haven’t had much success today but my Unity time got cut short due to Christmas madness :wink: Shoot me a PM if you want and we can work on this problem together.

Cheers,
Mike

This is the code i use to fire a bullet from my boss character (a position) to my player(another position)

//Create the bullet and set its position to the bosses position
GameObject newBul = (GameObject)Instantiate (Bullet);
newBul.name = “BossBullet”;
newBul.transform.localPosition = CurrentObject.transform.localPosition;
//a counter to make sure the boss can only shoot once every 0.75 seconds
timesincelastfire = Time.timeSinceLevelLoad + 0.75f;

//set up the position of the player (my scene is set up so that -3.2f is the center)
Vector3 poos = new Vector3 (Player.transform.localPosition.x, 0,Player.transform.localPosition.y-3.2f);
//rotate the object to point in the right direction
Quaternion rot = Quaternion.LookRotation (newBul.transform.position - poos, Vector3.forward);

newBul.transform.rotation = rot;

newBul.transform.eulerAngles = new Vector3 (0, 0, newBul.transform.eulerAngles.z + 90);

Thanks, but sadly I can’t make it work.

:frowning:

If you guys are still trying to fix this problem I have a great link that really explained it well and helped me understand it

Skip down to the bottom part and he explains movement and rotation with the zombie sprite. If you’re looking for a quick fix, this is the code I am running currently and it looks rather good. Note that sprite will stick to the mouse which is good for me but might not suit you. I apologise for the comments in advanced (they help me understand the code better I am very much still a beginner). One last note, you might have to remove that -90 i have on the line with atan on it, my sprite was facing upwards so needed -90 for it to look the correct way.

var moveSpeed:float = 0.2;
var turnSpeed:float = 20;
var lastMousePos = Vector3(3,3,3);
var mousePosition:Vector3;
var moveDirection:Vector3;

function Start () 
{
	moveDirection = Vector3.right;
}

function Update () 
{	
	// HANDLES MOVEMENT (SPRITE STICKING TO THE MOUSE)
	// stores the current position of the sprite
	var currentPosition:Vector3;
	// stores the sprites current position into the current position variable
	currentPosition = transform.position;
	// stores the position of the mouse in the mouse position variable
	mousePosition = Input.mousePosition;
	// changes the mouse position variable to match the mouses position in relation to the camera
	mousePosition = Camera.main.ScreenToWorldPoint(mousePosition);
	// actually transforms the sprites position using the lerp function, which slowly moves the sprite between
	// the first vector position and the second vector position at the rate of moveSpeed		
	transform.position = Vector2.Lerp(transform.position, mousePosition, moveSpeed);

	// HANDLES ROTATION
	// vector3 named move toward that will help calculate the angle we need to look toward
	var moveToward: Vector3;
	// gets the mouse position relative to the camera and stores it in movetoward
	moveToward = Camera.main.ScreenToWorldPoint( Input.mousePosition );
	// moveDirection (variable announced at top of class) becomes moveToward - current position
	moveDirection = moveToward - currentPosition;
	// make z part of the vector 0 as we dont need it
	moveDirection.z = 0; 
	// normalize the vector so its in units of 1
	moveDirection.Normalize();
  	// if we have moved and need to rotate
	if (moveDirection != Vector3.zero)
	{
		// calculates the angle we should turn towards, - 90 makes the sprite rotate
		var targetAngle:float = Mathf.Atan2(moveDirection.y, moveDirection.x) * Mathf.Rad2Deg - 90;
		// actually rotates the sprite using Slerp (from its previous rotation, to the new one at the designated speed.
		transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.Euler (0, 0, targetAngle), turnSpeed * Time.deltaTime);
	}
}
2 Likes