4

This script is called when the user release the mouse button:

float rot_duration = 3f;
float rot_speed = 1.8f;
Quaternion final_rot;

void Start()
{
    cubeMesh = GameObject.FindWithTag("CubeMesh");

    Vector3 initial_rot = transform.rotation.eulerAngles;
    final_rot = Quaternion.Euler(new Vector3(initial_rot.x, initial_rot.y, 180));
}

public void Update()
{
    if (Input.GetMouseButtonUp(0)) 
    {
        StartCoroutine (DelayRotate (0.1F));
    }
}

IEnumerator DelayRotate(float waitTime)
{
        yield return new WaitForSeconds (waitTime);
        float rot_elapsedTime = 0.0F;
        while (rot_elapsedTime < rot_duration) {
        cubeMesh.transform.rotation = Quaternion.Slerp (transform.rotation, final_rot, rot_elapsedTime);
            rot_elapsedTime += Time.deltaTime * rot_speed;
            yield return null;
        }
}

This script makes a GameObject rotate, 0.1 seconds after mouse button release. The problem is that it "flips" the GameObject quickly then starts rotating.

I believe it is flipping due to final_rot2 = Quaternion.Euler(new Vector3(initial_rot.x, initial_rot.y, 180)); (because of 180 value) What should I do instead?

5
  • @Prix The while needs to be there or else it won't rotate. Commented Mar 20, 2016 at 11:42
  • never use quaternions for any reason - ever. use the Rotate call. transform.Rotate(Time.deltaTime, 0, 0); many examples right here docs.unity3d.com/ScriptReference/Transform.Rotate.html Commented Mar 20, 2016 at 13:45
  • What is final_rot initialized to? Commented Mar 20, 2016 at 15:03
  • @Programmer question edited. Commented Mar 20, 2016 at 15:11
  • I found the mistake in your code. Take a look at my answer. Commented Mar 20, 2016 at 16:10

2 Answers 2

1

I looked at code carefully and I was able to spot two mistakes.

1. The one mistake that is causing the problem is:

cubeMesh.transform.rotation = Quaternion.Slerp (transform.rotation, final_rot, rot_elapsedTime);

The guy above me said you should replace transform.rotation with cubeMesh.transform.rotation. That is close but wont work. What you are suppose to is to get the current position of the GameObject outside the while loop and store it somewhere, then you can use it later on inside the while loop. For example,

Quaternion currentLocation = cubeMesh.transform.rotation;
while(...){
  cubeMesh.transform.rotation = Quaternion.Slerp (currentLocation, final_rot, rot_elapsedTime);
...Other codes
}

2. Another mistake I found is that it looks like you are trying to rotate the object within time because you have a variable called rot_duration.

If this is true then you failed when you did Quaternion.Slerp (transform.rotation, final_rot, rot_elapsedTime);.

If you want the object to rotate within rot_duration amount of time, change rot_elapsedTime to rot_elapsedTime / rot_duration. Also remove rot_speed as that will NOT work if you want to rotate over time.

If this is NOT what you are trying to do then the first mistake I found should fix your problem.

Your final Code should look like something below:

float rot_duration = 10f;
float rot_speed = 3f;
Quaternion final_rot;
GameObject cubeMesh;

void Start()
{
    cubeMesh = GameObject.FindWithTag("CubeMesh");

    Vector3 initial_rot = transform.rotation.eulerAngles;
    final_rot = Quaternion.Euler(new Vector3(initial_rot.x, initial_rot.y, 180));
}

public void Update()
{
    if (Input.GetMouseButtonUp(0))
    {
        StartCoroutine(Delay(1));
    }
}

IEnumerator Delay(float waitTime)
{
    yield return new WaitForSeconds(waitTime);
    float rot_elapsedTime = 0.0F;

    //Get the current rotation 
    Quaternion currentLocation = cubeMesh.transform.rotation;

    while (rot_elapsedTime < rot_duration)
    {
        rot_elapsedTime += Time.deltaTime;
        cubeMesh.transform.rotation = Quaternion.Slerp(currentLocation, final_rot, rot_elapsedTime / rot_duration);
        yield return null;
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

The problem here is that this doesn't update for each frame. I see that you add Time.deltaTime, but it doesn't update per frame, it only uses the value for the current frame several times, since you do everything in one update.

This code might work:

float rot_duration = 10f;
float rot_speed = 3f;
float rot_elapsedTime = 3f;
Quaternion final_rot;

public void Update()
{
    if (Input.GetMouseButtonUp(0)) 
    {
        StartCoroutine (Delay (1));
    }
    if (rot_elapsedTime < rot_duration) {
        cubeMesh.transform.rotation = Quaternion.Slerp (transform.rotation, final_rot, rot_elapsedTime);
        rot_elapsedTime += Time.deltaTime * rot_speed;
}

IEnumerator Delay(float waitTime)
{
   yield return new WaitForSeconds (waitTime);
   rot_elapsedTime = 0.0F;
}

But as being said, transform.Rotate is probably better.

Edit: Updated after OP's edit with new code, adding a 1 sec delay.

2 Comments

Sorry, I didn't catch the 1 sec delay at first, but still I think your problem is that you have a while loop, which means that you are doing the whole rotation at once, without the frame updating. I have edited my answer to your new code.
His while loop is not a problem, it yields return null, which will do the same as WaitForEndOfFrame()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.