Understanding the code

Hi so currently im trying to make a spinner for the block breaker game, I can make it rotate easily the issue is getting the direction to change after a certain time frame.

After I reset the direction for rotation the spinner will break like its pushing against itself but i cant understand why.

Code
using System.Collections.Generic;
using UnityEngine;

public class Rotation : MonoBehaviour
{

    [SerializeField] float rotationSpeed = 50f;
    [SerializeField] float rotatIonDirection;

    [SerializeField] bool startSpinning = false;
    [SerializeField] bool setRotation = false;

    private Vector3 rotate;

    // Start is called before the first frame update
    void Start()
    {
        
        
    }

    // Update is called once per frame
    void Update()
    {

        RotationMethod();
 
    }

    public void RotationMethod ()
    {
        if (!setRotation)
        {
            float rotatIonDirection = Random.Range(-1, 2);
            rotate = new Vector3(0f, rotatIonDirection, 0f);

            if (rotatIonDirection == 0)
            {
                rotatIonDirection = Random.Range(-1, 2);
            }

            else { startSpinning = true; }
        }
       
         
        
        if (startSpinning)
        {
            setRotation = true;
            transform.Rotate(rotate * rotationSpeed * Time.deltaTime);
            ResetDirection(5f);
            
        }
        
    }

    public IEnumerator ResetDirection (float delay)
    {
        yield return new WaitForSecondsRealtime(delay);
        startSpinning = false;
        setRotation = false;

   // Ive tried setting both rotate and rotation direction to 0 
   // here, it didnt help.
    }

} 
Video

https://www.youtube.com/watch?v=GiftqT3wf9Y&feature=youtu.be

Hi David,

That looks like the infamous gimbal lock. Use the RotateAround method to avoid this problem.

Thanks for the response Nina, I believe I am using the rotatearound method properly but the result is quire weird… to say the lest

transform.RotateAround(Vector3.zero, rotate , rotationSpeed * Time.deltaTime);

Another way I wrote it is

transform.RotateAround(rotate, 0.1f * rotationSpeed * Time.deltaTime);

but that produces the same “Gimbal Lock” as before.

What is rotate? The axis around which your object is supposed to rotate? If so, test Vector3.up.

Could you share your code with the changes again?

rotate is my vector3 for the Y axis, The only reason im using that instead of up is because I want the direction to change between -1 and 1.

using System.Collections.Generic;
using UnityEngine;

public class Rotation : MonoBehaviour
{

    [SerializeField] float rotationSpeed = 50f;
    [SerializeField] float rotatIonDirection;

    [SerializeField] bool startSpinning = false;
    [SerializeField] bool setRotation = false;

    private Vector3 rotate;

    // Start is called before the first frame update
    void Start()
    {
        
        
    }

    // Update is called once per frame
    void Update()
    {

        RotationMethod();
 
    }

    public void RotationMethod ()
    {
        if (!setRotation)
        {
            rotatIonDirection = Random.Range(-1, 2);
            rotate = new Vector3(0f, rotatIonDirection, 0f);

            if (rotatIonDirection == 0)
            {
                rotatIonDirection = Random.Range(-1, 2);
            }

            else { startSpinning = true; }
        }
       
         
        
        if (startSpinning)
        {
            setRotation = true;
         //   transform.Rotate(rotate * rotationSpeed * Time.deltaTime); // produces gimbal lock
         //   transform.RotateAround(Vector3.zero, rotate, rotationSpeed * Time.deltaTime); // causes the spinner to fly away
        //    transform.RotateAround(rotate, 0.1f * rotationSpeed * Time.deltaTime); // produces same gimbal lock
            StartCoroutine(ResetDirection(5f));

        }
        
    }

    public IEnumerator ResetDirection (float delay)
    {
        yield return new WaitForSecondsRealtime(delay);
        startSpinning = false;
        setRotation = false;
        rotatIonDirection = 0f;
        rotate = Vector3.zero;
        
    }

}

Edit: Not sure if it matters but unity says RotateAround is obsolete.

And what do you want to achieve by -1 and 1? If you want to change the rotation direction, you don’t have to change the axis. Instead, you could try to multiply the rotationSpeed by -1 and 1 respectively.

What does the message suggest as an alternative to RotateAround?

It suggests I use Rotate, also yes the -1 and 1 was just to change the rotation direction, Ill try using vector3.up and multiply the rotation speed by -1.

It appears to lock up this way as well.

    {
        if (!setRotation)
        {
            rotatIonDirection = Random.Range(-1, 2);
          //  rotate = new Vector3(0f, rotatIonDirection, 0f);

            if (rotatIonDirection == 0)
            {
                rotatIonDirection = Random.Range(-1, 2);
            }

            else
            {
                rotationSpeed = rotatIonDirection * rotationSpeed;
                startSpinning = true;
            }
        }
       
         
        
        if (startSpinning)
        {
            setRotation = true;
            transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime); 
           
            StartCoroutine(ResetDirection(5f));

        }
        
    }

Remove the code where you modify the direction and test the code again. If it locks, it’s a general problem. If it does not lock, it is a problem with the way how you (re)set the direction.

Yes the issue seems to be coming from when i reset the direction, I noticed in the inspector if I just click on setrotation to false when it resets itself it doesnt lock.

So maybe i dont fully understand how a coroutine works, cause I believe that is the issue.

So the issue was that once the coroutine started it never stopped (which I find strange since I was setting startSpinning to false inside the coroutine which means it shouldn’t have been able to run), since it is technically in the update function it was being called every second causing the lock.

Anyway I manged to find a fix.

Code
    {

        yield return new WaitForSecondsRealtime(delay);

        if (resetRotation)
        {
            startSpinning = false;
            setRotation = false;
            resetRotation = false;
        }

        else { StopAllCoroutines(); } 

    }

} 

The only thing im questioning currently is why I had to use StopAllCoroutines, when I tried using StopCoroutine(ResetDirection(0f)); it didn’t work. Anyway it’s fixed for now, my game now has a spinner that changes direction at random huzzah.

Edit: This is my third time using a coroutine so I didn’t really know about stop coroutine, the other two I made worked perfectly fine without it, but to be fair this is the first one that was in the Update function.

Actually I think I answered my own question in the post stopallcoroutines is needed most likely because more than 1 has been executed before it got the chance to run, that’s why stopcoroutine “didn’t work” because it only stopped one of multiple.

That’s what I think anyway.

ResetDirection(0f) itself is not a coroutine, it’s an ordinary method. When you call StartCoroutine, the StartCoroutine method returns an object of type Coroutine. When you pass on this Coroutine object to StopCoroutine, the coroutine you passed on gets stopped by the method.

If you find this hard to grasp, imagine the following scenario:

StartCoroutine(ResetDirection(0f));
StartCoroutine(ResetDirection(0f));
StartCoroutine(ResetDirection(0f));

You start the coroutine three times. StopAllCoroutines() will stop all of them but how is StopCoroutine supposed to distinguish between the three running coroutines if you just pass on the method?

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.