Unity3D: понятия не имею, как использовать Quaternion.Slerp(); вращение становится быстрее

Я пытаюсь сделать простую игру в Unity для GearVR. В игре у меня есть сцена, где пользователь может перемещаться по списку элементов. Элемент может быть выбран, если пользователь щелкает, глядя на него. Что касается навигационной части, пользователь должен иметь возможность использовать как движение головы, так и смахивание для поворота элементов (сдвиг на единицу/минус один при каждом свайпе вправо/влево).

Теперь проблема: я могу заставить все это работать с кодом ниже (установленным как компонент родительского элемента), но вращение продолжает увеличиваться, чем больше я использую свайпы. Я не могу понять, почему ... все еще работаю над этим.
Любая помощь приветствуется 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;
    }
}

Я использую Unity 5.4.1f1 и jdk 1.8.0.

PS. Не будьте строги ко мне, так как это мой первый вопрос здесь.
Кстати... всем привет XD


person arjel    schedule 25.11.2016    source источник
comment
Этот код настолько неверен, что я даже не знаю, с чего начать. Даже если вы нашли решение, оно все равно неверно. Я не думаю, что ваша функция Rotate когда-либо будет существовать, потому что у нее есть цикл while(true). Кроме того, эта функция вызывается каждый раз при свайпе. В какой-то момент все это будет медленно. Кроме того, если вы когда-нибудь передадите 0 функции Rotate, все ваше приложение зависнет. Чтобы исправить это, поместите yield return null; внутри цикла while, а не внутри оператора if в цикле while...   -  person Programmer    schedule 25.11.2016
comment
Спасибо за исправление. Я думаю, что вы правы в этом вопросе. С учетом сказанного я, как и многие другие, пишу здесь после многих попыток и ошибок. Я нашел решение, а не решение. И я был бы признателен, если бы вы объяснили, если хотите, как и где это неправильно.   -  person arjel    schedule 25.11.2016
comment
Исправлено значение return null; из оператора if(). Исправлено Rotate(int v) для Rotate(bool v). Если я удалю значение while true, объекты будут вращаться только на один кадр, а не в пункт назначения Lerp. Вы можете помочь мне?   -  person arjel    schedule 25.11.2016
comment
В настоящее время я пишу ответ для этого. Надеюсь, это решит вашу проблему.   -  person Programmer    schedule 25.11.2016
comment
Какого типа переменные from и to? Vector3, Transform или Quaternion?   -  person Programmer    schedule 25.11.2016
comment
Оба они являются кватернионами, поскольку я использовал их в: Quaternion.Slerp(from, to, Time.deltaTime);   -  person arjel    schedule 25.11.2016
comment
Ok. Я вижу, вы исправили возможную проблему с бесконечным циклом. Для чего используется bool v?   -  person Programmer    schedule 25.11.2016
comment
На самом деле не использовал его, если я изменю код, как указано выше.   -  person arjel    schedule 25.11.2016
comment
Вы можете проверить мой ответ. Это не проверено, но я считаю, что это должно решить большую часть вашей проблемы.   -  person Programmer    schedule 25.11.2016


Ответы (2)


Вы исправили большинство проблем, которые я обсуждал в разделе комментариев. Осталось одно — цикл while. Прямо сейчас нет способа выйти из этого цикла, и это приведет к одновременному запуску нескольких экземпляров функции Rotate.

но вращение продолжает увеличиваться, чем больше я использую свайпы

Решение состоит в том, чтобы сохранить ссылку на одну функцию сопрограммы, а затем остановить ее перед запуском новой.

Что-то вроде этого.

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

Вместо while (true) у вас должен быть таймер, который существует в цикле while. В это время функция Rotate работает постоянно. Вы должны остановить его после перехода от вращения к целевому вращению.

Что-то вроде этого должно работать:

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

Вот как должен выглядеть весь ваш код:

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;
    }
}

Вы можете увеличить или уменьшить переменную duration.

person Programmer    schedule 25.11.2016
comment
Угадайте, как это выглядит, когда вы получаете некоторый опыт ... Спасибо за вашу помощь! - person arjel; 28.11.2016

Попробуйте использовать Lerp из текущей ротации, а не из последней:

transform.rotation = Quaternion.Slerp(transform.rotation, to, Time.deltaTime);
person Ludovic Feltz    schedule 25.11.2016
comment
Я пробовал это, но таким образом вращение вообще не останавливается, поскольку «до» - это кватернион, определяемый как вращение «преобразования». to = Quaternion.Euler (новый Vector3 (0, transform.eulerAngles.y + 30, 0)); - person arjel; 25.11.2016
comment
Решено! Спасибо за ваш ответ. - person arjel; 25.11.2016