Search code examples
c#unity-game-enginerotationeuler-angles

Can you set max angles for RotateAround in Unity?


This doesn't accomplish what I want really. It basically just rotates around an empty until it hits a max. When I use this code, it moves fine. The "maximum" angle changes based on which way you decide to move first. Is there a way to set a maximum rotate around angle?

 using UnityEngine;
using System.Collections;

public class CameraMovement : MonoBehaviour {
    Transform rotAround;
    public float maxRotation = 0;
    // Use this for initialization
    void Start () {
        rotAround = GameObject.Find ("CamRotation").GetComponent <Transform> ();
    }

    // Update is called once per frame
    void Update () {
        if (Input.GetKey (KeyCode.D) && maxRotation < 52.0f) {
            transform.RotateAround (rotAround.position, Vector3.down, 100 * Time.deltaTime);
            maxRotation += 1;
        }
        if (Input.GetKey (KeyCode.A) && maxRotation > -52.0f) {
            transform.RotateAround (rotAround.position, Vector3.up, 100 * Time.deltaTime);
            maxRotation -= 1;
        }
    }
}

Solution

  • You are adding 1 to maxRotation each frame. You need to add Time.deltaTime instead otherwise your maxRotation will be reached at different times depending on your framerate. Just changing this should make your GameObject stop at the same angle no matter what way they turn.

    That is the quick and simple way to do it. The other is to do some maths. finding the arctan (using Mathf.Atan2) of the difference of the rotateAround transform.position and the camera's start transform.position and then subtracting that from the camera's current transform.position minus the rotateAround position would give you the current angle (example below). You could then use this value to check if rotation should continue. See this answer for more info on how Atan2 works.

    Note that Mathf.Atan2 returns the angle (in radians) between the vector passed to it and the X-axis (you probably don't want this). I think to find the angle between three vectors (which I think you do want) you will have to take the difference of their respective arctans (I've not checked this and it's pseudo-code for brevity). Like so:

    float angle = 
    Atan2(cameraStartPos.y - rotatePointPos.y, cameraStartPos.x - rotatePointPos.x) -
    Atan2(cameraCurrentPos.y - rotatePointPos.y, cameraStartPos.x - rotatePointPos.x);
    

    Even better than that, have unity do all that for you! use Vector3.Angle:

    float angle = Vector3.Angle(rotateAround.position - cameraStart.position,  
                                rotateAround.position - cameraEnd.position));
    

    Your final code could look something like:

    public class CameraMovement : MonoBehaviour {
    
        Transform rotAround;
        private Vector3 startPosition;
        public float maxRotation = 0; // set this to the maximum angle in degrees
    
        void Start () 
        {
            rotAround = GameObject.Find ("CamRotation").GetComponent <Transform> ();
            startPosition = transform.position;
        }
    
    
        void Update () 
        {
    
            float currentAngle = Vector3.Angle(rotAround.position - startPosition,
                                               rotAround.position - transform.position));
    
            if (Input.GetKey (KeyCode.D) && maxRotation < currentAngle) 
            {
                transform.RotateAround (rotAround.position, Vector3.down, 100 * Time.deltaTime);
            }
    
            if (Input.GetKey (KeyCode.A) && maxRotation < currentAngle) 
            {
                transform.RotateAround (rotAround.position, Vector3.up, 100 * Time.deltaTime);
            }
        }
    }
    

    Note that the angle returned from Vector3.Angle will 'flip' when it reaches 180 so you can set your max angle to any value under 180 and it will stop at the same point on both sides.