Rotate around a pivot to a specified degree and stop, with key press

UnityServicesMade with UnityLearnCommunityAsset StoreGet Unity

ForumsAnswersFeedbackIssue TrackerBlogEvangelistsUser Groups
Find posts and topics…
Ask a question
Spaces

Ask a Question
The form below has errors. Correct the fields in red and try again.
avatar image
Your Question:
rotating an object around a pivot inside and stopping at a set degree

I’ve been struggling with this one all morning. I have a game I’m designing where the entire level can rotate on a set pivot. I am rotating the level because, not the camera, because gravity needs to remain unchanged. My script, when Q or E is hit, rotates the entire level. (Currently in the X/Y plane, rotating around the z)

I was able to get it working without a pivot (it would rotate around 0,0,0) In the interest of being able to have multiple rotation points as levels get bigger, i was adjusting my script. I am having trouble getting it to stop - I have tried a bunch of different ways: my current version is setting a vector at an angle equal to the desired rotation and then using vector3.dot to see if they line up as the script rotates it.

The rotation is also in a coroutine.

If you could please help me figure out how to get this while loop to recognize that the vectors have aligned, I woudl be very grateful

     [SerializeField] public GameObject level; // levels will change.
    [SerializeField] private float rotationDegree = 90f; // how far you want the level to rotate. May need to be made public in order to change it for different levels.
    [SerializeField] private float rotateSpeed = 15f; // speed of the rotation
    
private bool levelRotating = false,

Quaternion toAngle, startAngle;
private float startDegree;

private Transform levelTrans;
    private Transform pivot;

    private void Awake()
    {
        levelTrans = level.transform; // shorthand for the transform of the level vrs the GO

        startAngle = Quaternion.identity; // Make sure the level startAngle is set to No Rotation to start.

        foreach(Transform child in levelTrans) 
        {
            // searches for each child in the Level for the pivot point on layer 9 (pivot layer) and then sets it for use later. Should only be one pivot per camera move.

            // Note: Camera Move script (to change levels/scenes) will need to re find pivot!!
            if(child.gameObject.layer == 9)
            {
                pivot = child;
                break;
            }
        }
        
    }


   private void LateUpdate()
    {
        if (!levelRotating)
        {

            startDegree = levelTrans.eulerAngles.z;

            if (Input.GetAxisRaw("Rotate") < 0)
            {

                toAngle = Quaternion.AngleAxis(startDegree + rotationDegree, levelTrans.forward); // set the destination angle as an offset from the start angle

                this.transform.SetParent(levelTrans); // adds the player object to the level, so it will rotate with the level and not get tossed out
                rotatingClockwise = true; // set the direction flag
                levelRotating = true; 
                StartCoroutine(SpinLevel(rotateSpeed, Vector3.forward, pivot));
                
            }
            else if (Input.GetAxisRaw("Rotate") > 0)
            {
                toAngle = Quaternion.AngleAxis(startDegree + rotationDegree, -levelTrans.forward); 
                this.transform.SetParent(levelTrans);
                rotatingCounterClock = true;
                levelRotating = true; 
                StartCoroutine(SpinLevel(rotateSpeed, -Vector3.forward, pivot));
                
            }
        } // else do nothing if the level is moving. No change in current location, no change in flags, no change in toAngle
    }


 private IEnumerator SpinLevel(float overTime, Vector3 rotDirection, Transform pivot)
    {


        Vector3 pivotPoint = pivot.position;

        Vector3 destination = FindEndRotation(rotationDegree);
        Vector3 start = startAngle.eulerAngles;

       

        float dotRotateCheck = 0.0f;


        // if they are different, rotate the level a small amount, and set the level rotating to True

        while (!Mathf.Approximately(dotRotateCheck,0.0f))
        {
                
            levelRotating = true;

            levelTrans.RotateAround(pivotPoint, rotDirection, overTime * Time.deltaTime);

            dotRotateCheck = Vector3.Dot(levelTrans.transform.right, destination);



            yield return null; 
        }


            levelRotating = false;

            this.transform.parent = null;
            
        
    }


    private Vector3 FindEndRotation(float degree)
    {
        Vector3 end = new Vector3(0,0,0);

        float radians = degree * Mathf.Deg2Rad;

        end.x = Mathf.Cos(radians);
        end.y = Mathf.Sin(radians);

        
        return end;
    }

I’ve been struggling with this one all morning. I have a game I’m designing where the entire level can rotate on a set pivot. I am rotating the level because, not the camera, because gravity needs to remain unchanged. My script, when Q or E is hit, rotates the entire level. (Currently in the X/Y plane, rotating around the z)

I was able to get it working without a pivot (it would rotate around 0,0,0) In the interest of being able to have multiple rotation points as levels get bigger, i was adjusting my script. I am having trouble getting it to stop - I have tried a bunch of different ways: my current version is setting a vector at an angle equal to the desired rotation and then using vector3.dot to see if they line up as the script rotates it.

The rotation is also in a coroutine.

If you could please help me figure out how to get this while loop to recognize that the vectors have aligned, I woudl be very grateful

  [SerializeField] public GameObject level; // levels will change.
 [SerializeField] private float rotationDegree = 90f; // how far you want the level to rotate. May need to be made public in order to change it for different levels.
 [SerializeField] private float rotateSpeed = 15f; // speed of the rotation

private bool levelRotating = false,

Quaternion toAngle, startAngle;
private float startDegree;

private Transform levelTrans;
private Transform pivot;

 private void Awake()
 {
     levelTrans = level.transform; // shorthand for the transform of the level vrs the GO

     startAngle = Quaternion.identity; // Make sure the level startAngle is set to No Rotation to start.

     foreach(Transform child in levelTrans) 
     {
         // searches for each child in the Level for the pivot point on layer 9 (pivot layer) and then sets it for use later. Should only be one pivot per camera move.

         // Note: Camera Move script (to change levels/scenes) will need to re find pivot!!
         if(child.gameObject.layer == 9)
         {
             pivot = child;
             break;
         }
     }
     
 }


private void LateUpdate()
 {
     if (!levelRotating)
     {

         startDegree = levelTrans.eulerAngles.z;

         if (Input.GetAxisRaw("Rotate") < 0)
         {

             toAngle = Quaternion.AngleAxis(startDegree + rotationDegree, levelTrans.forward); // set the destination angle as an offset from the start angle

             this.transform.SetParent(levelTrans); // adds the player object to the level, so it will rotate with the level and not get tossed out
             rotatingClockwise = true; // set the direction flag
             levelRotating = true; 
             StartCoroutine(SpinLevel(rotateSpeed, Vector3.forward, pivot));
             
         }
         else if (Input.GetAxisRaw("Rotate") > 0)
         {
             toAngle = Quaternion.AngleAxis(startDegree + rotationDegree, -levelTrans.forward); 
             this.transform.SetParent(levelTrans);
             rotatingCounterClock = true;
             levelRotating = true; 
             StartCoroutine(SpinLevel(rotateSpeed, -Vector3.forward, pivot));
             
         }
     } // else do nothing if the level is moving. No change in current location, no change in flags, no change in toAngle
 }

private IEnumerator SpinLevel(float overTime, Vector3 rotDirection, Transform pivot)
{

     Vector3 pivotPoint = pivot.position;

     Vector3 destination = FindEndRotation(rotationDegree);
     Vector3 start = startAngle.eulerAngles;

    

     float dotRotateCheck = 0.0f;


     // if they are different, rotate the level a small amount, and set the level rotating to True

     while (!Mathf.Approximately(dotRotateCheck,0.0f))
     {
             
         levelRotating = true;

         levelTrans.RotateAround(pivotPoint, rotDirection, overTime * Time.deltaTime);

         dotRotateCheck = Vector3.Dot(levelTrans.transform.right, destination);



         yield return null; 
     }


         levelRotating = false;

         this.transform.parent = null;
         
     
 }


 private Vector3 FindEndRotation(float degree)
 {
     Vector3 end = new Vector3(0,0,0);

     float radians = degree * Mathf.Deg2Rad;

     end.x = Mathf.Cos(radians);
     end.y = Mathf.Sin(radians);

     
     return end;
 }

Thanks for any help you can provide

( ai also have tried using local forward z compared to rotation degrees, and vector3.angle to find the current angle in the loop until it reaches 0. I suspect that the issue is Float and Epsilon, but…

In the end, I feel silly as there was a much easier way to do it. The level design already calls for a centerpoint that the camera is focused on - and that is of course a game object.

I went back to my old rotate code, and moved the centerpoint to the master of the level instead of an empty game object. Rotating this of course rotates the entire level around a pivot, with ease.