0
\$\begingroup\$

I'm trying to get my 2D character to rotate around colliders based on the current ground normal (sort of like in Mario Galaxy) detected by Physics2D.CircleCast, which I believe automatically interpolates the normals between two surfaces sharing a convex edge (e.g. the sharp edges of a BoxCollider2D). I also want my character to maintain a constant forward direction, in this case, transform.right.

To achieve this I'm setting my transform.eulerAngles.z to the value created by Vector2.Angle(hit.normal, Vector2.up), but the problem is that this value is only accurate half of the time. If my character is moving around a circle, for example, only one half of the circle will provide an accurate rotation; the second half of the circle rotates me in the opposite direction. I'm not very comfortable with rotations or quaternions, but I've noticed that my z rotation will go from 0 to -180 on the "correct" half of the circle, and then start going in reverse again (-179, -178, etc.) on the other half. I've also noticed that the value shown in the inspector for my z rotation is not the same as the value I get when logging it to the console (console says 270, inspector shows -90).

using UnityEngine;
using DG.Tweening;

[RequireComponent(typeof(BoxCollider2D))]
public class RotationTest : MonoBehaviour
{
    [SerializeField]
    private float speed = 5;
    [SerializeField]
    private LayerMask rayMask;

    private BoxCollider2D boxCollider;

    private void Awake()
    {
        boxCollider = GetComponent<BoxCollider2D>();
    }

    void Update()
    {
        CheckForTerrainAndRotate();
    }

    private void CheckForTerrainAndRotate()
    {
        Vector2 direction = transform.right;
        transform.Translate(speed * direction * Time.deltaTime, Space.World);

        float circleCastRadius = boxCollider.bounds.extents.x + 0.05f;
        RaycastHit2D hit = Physics2D.CircleCast(transform.position, circleCastRadius, -transform.up, 5, rayMask);

        if (!hit)
        {
            transform.eulerAngles = Vector3.zero;
            return;
        }

        // Sets rotation using transform's euler angles
        transform.DORotate(new Vector3(0, 0, -Vector2.Angle(hit.normal, Vector2.up)), 0.1f, RotateMode.Fast);
    }
}

I'm using the DOTween library to handle lerping between two rotations, but am also having the same issue without it.

\$\endgroup\$
4
  • \$\begingroup\$ Vector2.Angle: Note: The angle returned will always be between 0 and 180 degrees, because the method returns the smallest angle between the vectors. Maybe you need Vector2.SignedAngle \$\endgroup\$
    – Mangata
    Jun 16 at 7:27
  • \$\begingroup\$ @Mangata This actually works; I didn't even know about Vector2.SignedAngle. But I still don't understand the discrepancy in z rotation between what I see in the inspector and in Debug.Log. \$\endgroup\$ Jun 16 at 7:46
  • \$\begingroup\$ The values in inspector are euler angles. The actual rotation of transform is a quaternion. They are different values in memery, and they affect each other. Euler angles are "normalized" when generated from quaternions so that each value is in [0,360). 270 and -90 are same actually. \$\endgroup\$
    – Mangata
    Jun 16 at 9:36
  • \$\begingroup\$ @Mangata I recommend posting this as an Answer. \$\endgroup\$
    – DMGregory
    Jun 16 at 10:48

1 Answer 1

1
\$\begingroup\$

Vector2.Angle:

Note: The angle returned will always be between 0 and 180 degrees, because the method returns the smallest angle between the vectors.

Maybe you need Vector2.SignedAngle:

Note: The angle returned will always be between -180 and 180 degrees, because the method returns the smallest angle between the vectors.

Why the value shown in the inspector for my z rotation is not the same as the value I get when logging it to the console?

Because the values in inspector are euler angles. The actual rotation of transform is a quaternion. They are different values in memery, and they affect each other. Euler angles are "normalized" when generated from quaternions so that each value is in [0,360). So 270 and -90 are same actually.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .