0

I'm trying to make a simple game in Unity for GearVR. In the game I have a scene where the user can navigate through a list of items. An item can be selected if the user clicks while looking at one. For the navigation part, the user should be able to use both head movement and swipe to rotate the items (shifting by one/minus one at every right/left swipe).

Now the problem: I can make all of this work with the code below (set as component to the parent of the items), but the rotation keeps increasing the more I use swipes. I can't seem to figure out why ... still working on it.
Any kind of help is appreciated XD

private void ManageSwipe(VRInput.SwipeDirection sw)
{
    from = transform.rotation;
    if (sw == VRInput.SwipeDirection.LEFT)
    {
        to = Quaternion.Euler(new Vector3(0, from.eulerAngles.y + 30, 0));           
    }
    if (sw == VRInput.SwipeDirection.RIGHT)
    {
        to = Quaternion.Euler(new Vector3(0, from.eulerAngles.y - 30, 0));
    }
    StartCoroutine(Rotate());
}

IEnumerator Rotate(bool v)
{
    while (true)
    {
        transform.rotation = Quaternion.Slerp(from, to, Time.deltaTime);           
        yield return null;
    }
}

I'm using Unity 5.4.1f1 and jdk 1.8.0.

PS. Don't be to hard on me, since this is my first question here.
By the way ... hello everyone XD

Fattie
  • 27,874
  • 70
  • 431
  • 719
remmargorp
  • 434
  • 1
  • 6
  • 14
  • 1
    This code is so wrong that I don't even know where to start. Even though you found a solution, it is still wrong. I don't think that your `Rotate` function will ever exist because it has `while(true)` loop. On top of this, this function is being called each time there is a swipe. At some point the whole thing will be slow. Also, if you ever pass 0 to the `Rotate` function, your whole app will freeze. To fix that put `yield return null;` inside the while loop not inside the if statement in the while loop... – Programmer Nov 25 '16 at 16:29
  • Thank you for the fix. I think you're right about that point. With that said I as many others post here after many tries and errors. I found A solution, not THE solution. And I'd appreciate you to explain, if you're willing, how and where it is wrong. – remmargorp Nov 25 '16 at 16:55
  • Fixed the yield return null; out of the if() statement. Fixed Rotate(int v) to Rotate(bool v). If I remove the while true the objects rotate only for a frame, not to the destination of Lerp. Can you help me? – remmargorp Nov 25 '16 at 17:05
  • I am currently writing an answer for this. Hopefully, that would solve your problem. – Programmer Nov 25 '16 at 17:05
  • What type is `from` and `to` variables? `Vector3`, `Transform` or `Quaternion`? – Programmer Nov 25 '16 at 17:13
  • They are both quaternions as I used them in: Quaternion.Slerp(from, to, Time.deltaTime); – remmargorp Nov 25 '16 at 17:14
  • Ok. I see you fixed the possible infinite loop problem. What is the `bool v` used for? – Programmer Nov 25 '16 at 17:16
  • Not really used it, if I change the code as above. – remmargorp Nov 25 '16 at 17:17
  • You can check my answer. That's not tested but I believe it should solve most of your problem. – Programmer Nov 25 '16 at 17:45

2 Answers2

2

You fixed most of the problems I discussed in the comment section. One things left is still the while loop. Right now, there is no way to exit that while loop and this will result to multiple instance of the Rotate function running at the-same time.

but the rotation keeps increasing the more I use swipes

Solution is to store reference to one coroutine function then stop it before starting a new one.

Something like this.

IEnumerator lastCoroutine;
lastCoroutine = Rotate();
...
StopCoroutine(lastCoroutine);
StartCoroutine(lastCoroutine);

Instead of while (true), you should have a timer that exists the while loop. At this time, the Rotate function is continuously running. You should make it stop after moving from the rotation to the destination rotation.

Something like this should work:

while (counter < duration)
{
    counter += Time.deltaTime;
    transform.rotation = Quaternion.Lerp(from, to, counter / duration);
    yield return null;
}

Here is what your whole code should look like:

IEnumerator lastCoroutine;

void Start()
{
    lastCoroutine = Rotate();
}

private void ManageSwipe(VRInput.SwipeDirection sw)
{

    //from = transform.rotation;
    if (sw == VRInput.SwipeDirection.LEFT)
    {
        to = Quaternion.Euler(new Vector3(0, from.eulerAngles.y + 30, 0));
    }
    if (sw == VRInput.SwipeDirection.RIGHT)
    {
        to = Quaternion.Euler(new Vector3(0, from.eulerAngles.y - 30, 0));
    }
    //Stop old coroutine
    StopCoroutine(lastCoroutine);
    //Now start new Coroutine
    StartCoroutine(lastCoroutine);
}

IEnumerator Rotate()
{
    const float duration = 2f; //Seconds it should take to finish rotating
    float counter = 0;

    while (counter < duration)
    {
        counter += Time.deltaTime;
        transform.rotation = Quaternion.Lerp(from, to, counter / duration);
        yield return null;
    }
}

You can increase or decrease the duration variable.

Programmer
  • 121,791
  • 22
  • 236
  • 328
1

Try to use Lerp from the current Rotation not the last one:

transform.rotation = Quaternion.Slerp(transform.rotation, to, Time.deltaTime);
Ludovic Feltz
  • 11,416
  • 4
  • 47
  • 63
  • I have tried that, but that way the rotation doesn't stop at all, since 'to' is a quaternion defined as a rotation of 'transform'. to = Quaternion.Euler(new Vector3(0, transform.eulerAngles.y + 30, 0)); – remmargorp Nov 25 '16 at 16:11
  • Solved! Thank you for your answer. – remmargorp Nov 25 '16 at 16:17