Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
734 views
in Technique[技术] by (71.8m points)

c# - Unity - 2D Aim at Mouse, while restricting min/max rotation and factoring in parent rotation

So, I have a ship with a "Hardpoint" attached to it that weapons can be placed on to. Once placed, they aim at the mouse position and have a restricted rotational range: See here

The rotational range is based off minAngle and maxAngle, and are calculated by the eulerAngles.z of the parent hardpoint slot, plus/minus the angle modifier (in this case, 20). I had to do some weird rotational voodoo (see OneEightyToThreeSixty() in the code snippet) to get the mouse look angle to match the same format as the minAngle/maxAngle.

angle was coming in as -180 -> 180 degrees instead 0 -> 360 like the hardpoint's rotation. Wrote a method to convert it to 360 during runtime.

I've rewritten this script more times than I can count, but ultimately I'm hit with this issue.

As you can see, for 270 degrees of the 360 rotation, the aiming and restrictions work totally fine. But at the top right quarter of the rotation, it all goes haywire.

I've tried so many different implementations but they all seem to have this consistent issue. I cannot figure out what I'm missing. Here's the code:

public class HardpointSlot : MonoBehaviour
{
    public HardpointController ship;
    public GameObject hardpoint;

    public float minAngle;
    public float maxAngle;
    public float angle;
    public float offsetAngle;
    public bool switched;

    void Update()
    {
        AimAtMouse();
    }

    public void AimAtMouse()
    {
        Vector3 dir = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);

        angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;

        minAngle = (transform.eulerAngles.z - 20) + 90f;
        maxAngle = (transform.eulerAngles.z + 20) + 90f;

        angle = OneEightyToThreeSixty(angle);
        if (angle < minAngle)
        {
            angle = minAngle;
        }
        else if (angle > maxAngle)
        {
            angle = maxAngle;
        }

        hardpoint.transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
    }

    public float OneEightyToThreeSixty(float angle)
    {
        float newAngle = 0f;

        if (angle >= 0 && angle <= 180)
        {
            return angle;
        } else
        {
            return newAngle = 360 + angle;
        }


    }
}

So quick recap:

  • Hardpoint needs to look at mouse but only if its within its aim range bounds, which is calculated by the baseAim offset (20) and the rotation of the parent hardpoint slot.
  • Works for 270 degrees of rotation but not for the last 90.

Any ideas? Am I missing something very obvious?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I would take another approach, making use of Vector3.SignedAngle to get the angle from the neutral direction to the mouse direction. Then, use Mathf.Clamp to clamp it between the boundaries and then Quaternion.AngleAxis to create the resulting direction. Finally, use Quaternion.LookRotation to assign the rotation to the hardpoint's transform:

public class HardpointSlot : MonoBehaviour
{
    [SerializeField] HardpointController ship;
    [SerializeField] GameObject hardpoint;

    [SerializeField] float minAngle;
    [SerializeField] float maxAngle;
    [SerializeField] float angle;

    void Update()
    {
        AimAtMouse();
    }

    public void AimAtMouse()
    {
        Vector3 dir = Camera.main.ScreenToWorldPoint(Input.mousePosition)
                - transform.position;

        // flatten z axis
        dir.z = 0;
    
        Vector3 neutralDir = transform.up;
        float angle = Vector3.SignedAngle(neutralDir, dir, Vector3.forward);
    
        minAngle = -20f;
        maxAngle = 20f;
        
        angle = Mathf.Clamp(angle, minAngle, maxAngle);
       
        // rotate neutral dir by the clamped angle
        dir = Quaternion.AngleAxis(angle, Vector3.forward) * neutralDir;
    
        // set the rotation so that local up points in dir direction 
        // and local forward in global forward
        hardpoint.transform.rotation = Quaternion.LookRotation(Vector3.forward, dir);
    }
}


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...