- Home /
Bug in rotation when going to opposite quadrant
Hi All,
I have been breaking my head on this problem. The behavior I want to achieve is to rotate the player(up vector) towards the target position (which is mouseclick).
Seems to be quite simple and I have got it working except for a bug. So, for every click of mouse, I set the targetPos to the mouse position. I also set the scale of the player to +ve or -ve depending on the targetPos. Then I start the below coroutine to rotate and move the player to the targetPos. A correction has been added for the scaling when moving in opposite direction.
The player rotation is ok when the click is in y<0. The problem happens when I click in a y>0 region and only when the previous click in the opposite quadrant with respect to the player. The weird part is that if I click again (while the corouting is running), the rotation becomes correct.
I can't seem to figure out the bug in the code. Please help!
Here is the scaling code
transform.localScale = new Vector3(playerXScale * Mathf.Sign(transform.position.x - targetPos.x),
transform.localScale.y, transform.localScale.z);
And here is the rotation ad movement coroutine
//transform.rotation = Quaternion.Euler(0f, 0f, 0f);
Vector3 diff = targetPos - transform.position;
diff.Normalize();
float rot_z = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
float eulerZ = 180 * (1 + Mathf.Sign(transform.localScale.x)) / 2;
transform.rotation = Quaternion.Euler(0f, 0f, rot_z - eulerZ);
while (Vector3.Distance(targetPos , transform.position) > 0.05f && transform.position.y<=0)
{
transform.position = Vector3.MoveTowards(transform.position, targetPos , speed * Time.deltaTime);
yield return null;
}
transform.rotation = Quaternion.Euler(0f, 0f, 0f);
Edit1: Here is a standalone monobehaviour that you can use to attach to a game object to debug. This does show similar bug but clicking twice rotates the player again.
public class test : MonoBehaviour
{
Vector3 targetPos;
float playerXScale;
private void Start()
{
targetPos = transform.position;
playerXScale = transform.localScale.x;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
targetPos.z = transform.position.z;
StopAllCoroutines();
StartCoroutine("doMove");
}
transform.localScale = new Vector3(playerXScale * Mathf.Sign(transform.position.x - targetPos.x),
transform.localScale.y, transform.localScale.z);
}
IEnumerator doMove()
{
Vector3 diff = targetPos - transform.position;
diff.Normalize();
float rot_z = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg+90;
float eulerZ = 180 * (1 + Mathf.Sign(transform.localScale.x)) / 2;
transform.rotation = Quaternion.Euler(0f, 0f, rot_z - eulerZ);
while (Vector3.Distance(targetPos, transform.position) > 0.05f)
{
transform.position = Vector3.MoveTowards(transform.position, targetPos, 2 * Time.deltaTime);
yield return null;
}
transform.rotation = Quaternion.Euler(0f, 0f, 0f);
}
}
On what plane are you trying to rotate the object?
Its a 2D game. so rotation is about the z-axis. Trying to rotate in the viewport plane.
Answer by WinterboltGames · Aug 17, 2020 at 01:34 PM
Since you're rotating a 2D sprite (i.e. rotating on the Z-axis only).
Use the following code:
Vector3 rotation = Quaternion.FromToRotation(Vector3.right, (targetPosition- transform.position).normalized).eulerAngles;
transform.eulerAngles = new Vector3(0.0f, 0.0f, rotation.z);
Thanks. Your code should have worked fine if I wasn't changing my x-scale to flip the player direction.
However the code works fine if I use Vector3.up (since it wont be affected by x scale). I will have to modify my animations (swim$$anonymous$$g) to be with respect to the up vector, and handle the rotation in the code. I am not sure if that will lead to complexity later.