Пятница, 19 Апреля 2024, 03:46

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Форум игроделов » Движки для разработки игр и сложные системы разработки » Unity » точный плавный поворот
точный плавный поворот
polousДата: Пятница, 05 Сентября 2014, 14:29 | Сообщение # 1
частый гость
Сейчас нет на сайте
Ребята, эта тема поднималась здесь и не только уже 100500 раз. И тем не менее, нужно повернуть объект строго на 90 градусов относительно оси Y.
И если говорить о строгом повороте на 90 градусов, то прекрасно работает
Код

transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y - 90f, transform.rotation.eulerAngles.z);

но такой вариант мгновенно крутит объект. Мне же нужен плавный поворот и его также можно реализовать кучей способов, но тогда все решение зависит от скорости поворота (Time.deltaTime * speed) и условия выхода из вращения. Привожу пример реализации.
Код

    // кнопка поворота объекта влево (сидит в OnGUI ())
    if (GUI.Button (new Rect (10, Screen.height - 120, 80, 30), "Left")) {
     startAnglex = transform.rotation.eulerAngles.x;
     startAngley = transform.rotation.eulerAngles.y;
     startAnglez = transform.rotation.eulerAngles.z;
     AngleOfRotate = -90f;
     goRotatePlr = true;
    }

    // Плавный поворот на 90 градусов (сидит в Update ())
    if(goRotatePlr) {
     float angle = Quaternion.Angle(transform.rotation, Quaternion.Euler(startAnglex, startAngley + AngleOfRotate, startAnglez));
     if ((int)angle == 0) {
      goRotatePlr = false;
     }
     else {
      //transform.RotateAround(transform.position, Vector3.down, Time.deltaTime * rotateSpeed);
      //transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.down), Time.deltaTime * rotateSpeed);
      transform.Rotate(Vector3.down * Time.deltaTime * rotateSpeed);
     }
    }


Все бы хорошо, но точность поворота (а именно соблюдение условия остановки поворота) нарушается, когда возрастает скорость поворота. Если использовать скорость 50, то все ок и (int)angle == 0 не нарушается, но скорость 50 для моей задачи очень мала, мне нужно 300 и выше, и в этой ситуации условие выхода из вращения нарушается практически всегда, т.е. объект вращается так долго, пока однажды не выполнится это условие. Чтобы все работало корректно, мне нужно изменять условие, например на такое angle <= 5. Но таким углом я уже не могу пренебречь, т.к. тем же способом я хочу вращать ортогональную камеру и погрешность в 5 градусов при каждом повороте однажды приведет к значительному уклону камеры и неверному ее позиционированию. Итак, как же все-таки сделать точный (как в примере с Quaternion.Euler) поворот объекта вокруг своей оси, но при этом плавный, как последнем примере, и чтобы еще точность поворота не превышала 1 градуса (лучше меньше)?


Сообщение отредактировал polous - Пятница, 05 Сентября 2014, 14:38
Snake174Дата: Пятница, 05 Сентября 2014, 15:01 | Сообщение # 2
участник
Сейчас нет на сайте
Привет. Не знаю, как там на Юнити, но могу дать функцию плавного поворота на lua (Love2D):

Код

-- Функция плавного поворота на угол angle со скоростью speed
rotateTo = function( self, angle, speed )
   if self.ang < 0 then
     self.ang = self.ang + 360
   end

   if angle < 0 then
     angle = angle + 360
   end

   local a = self.ang - angle

   if a > 180 then
     a = a - 360
   elseif a < -180 then
     a = a + 360
   end

   local s = love.timer.getDelta() * speed

   if a >= -s - 0.5 and a <= s + 0.5 then
     self.ang = angle
   elseif a > s + 0.5 then
     self.ang = self.ang - s
   elseif a < -s - 0.5 then
     self.ang = self.ang + s
   end
end

self.ang - текущий угол поворота


Думаю код понятен и ты сможешь его переделать.


Не следует обманывать инспектора
Pipmak Assistant
Love2D Exporter
Love2D-Helpers
Old Consoles Games
polousДата: Пятница, 05 Сентября 2014, 21:41 | Сообщение # 3
частый гость
Сейчас нет на сайте
Спасибо, Snake174. Но все-таки хотелось бы получить подсказку в виде кода для юнити по той причине, что принцип то я итак понял и реализовал (примеры в первом посте), но у меня не получается сделать поворот точнее одного градуса. Хотелось бы иметь поворот 90 градусов +- , например, 0.01. Как мне так точно повернуться и при этом не мгновенно?

Добавлено (05.09.2014, 21:41)
---------------------------------------------
Ну же, мастера юнити, неужели вопрос настолько банален, что все молчат? если это так, то ткните хотя б в место, где искать, а то, как вы мб заметили, я в первом посте закомментировал еще 2 варианта вращения и они все работают аналогично....

MR_BorgДата: Пятница, 05 Сентября 2014, 22:09 | Сообщение # 4
участник
Сейчас нет на сайте
А что это непойдет?

RotateTodwards


Изучаю C++ попутно пишу игру.
polousДата: Пятница, 05 Сентября 2014, 22:41 | Сообщение # 5
частый гость
Сейчас нет на сайте
Вероятно, и так можно сделать, но этот вариант не особо отличается от тех, что я написал выше - везде нужно указывать направление поворота. Из-за чего я "проскакиваю" заданное условие при нужной мне скорости поворота. Т.е. получаю то 93,123 градуса, то 88,123 и тп, т.е. не получается подобраться к 90 градусам. Я сейчас решил иначе сделать. Чтоб конечной целью были всё те же 90 градусов, но подбираться к ним, замедляя шаг, вот тогда и условие хорошо срабатывает с любой точностью:

if(goRotatePlr) {
float angle = Quaternion.Angle(selectedPlayer.transform.rotation, Quaternion.Euler(startAnglex, startAngley + AngleOfRotate, startAnglez));
print (angle);
if (angle < 0.01) {
goRotatePlr = false;
}
else {
Quaternion target = Quaternion.Euler (0, startAngley + AngleOfRotate, 0);
selectedPlayer.transform.rotation = Quaternion.Lerp (selectedPlayer.transform.rotation, target, Time.deltaTime * 15f);
}
}
LertmindДата: Суббота, 06 Сентября 2014, 00:51 | Сообщение # 6
заслуженный участник
Сейчас нет на сайте
Ты просто неправильно делаешь проверку на достижение желаемого угла. Твой последний с Quaternion.Lerp будет двигаться с разной скорость.
Мой вариант с transform.Rotate, где скорость поворота одинаковая всегда:
Код
public class RotateMe : MonoBehaviour
{

     public float rotationSpeed = 0f; // Скорость поворота
     public float targetAngle = 0f; // Угол на который надо повернуться

     IEnumerator RotateMeNow()
     {
         float currentAngle = 0f;
         while (true)
         {
             float step = rotationSpeed * Time.deltaTime;
             if (currentAngle + step > targetAngle)
             {
                 // Докручиваем до нашего угла
                 step = targetAngle - currentAngle;
                 transform.Rotate(Vector3.up, step);
                 break;
             }
             currentAngle += step;
             transform.Rotate(Vector3.up, step);
             yield return null;
         }
     }

     void Update()
     {
         if (Input.GetMouseButtonDown(0))
         {
             StartCoroutine(RotateMeNow());
         }
     }
}

Добавлено (06.09.2014, 00:51)
---------------------------------------------
Если ты не научился работать с корутинами:

Код
public class RotateMe : MonoBehaviour
{
     public float rotationSpeed = 0f; // Скорость поворота
     public float targetAngle = 0f; // Угол на который надо повернуться

     bool goRotatePlr = false;
     float currentAngle = 0f;

     void Start()
     {
         goRotatePlr = true;
     }

     void Update()
     {
         if (goRotatePlr)
         {
             float step = rotationSpeed * Time.deltaTime;
             if (currentAngle + step > targetAngle)
             {
                 // Докручиваем до нашего угла
                 step = targetAngle - currentAngle;
                 transform.Rotate(Vector3.up, step);
                 goRotatePlr = false;
                 currentAngle = 0f;
             }
             else
             {
                 currentAngle += step;
                 transform.Rotate(Vector3.up, step);
             }
         }
     }
}
allodsДата: Суббота, 06 Сентября 2014, 01:12 | Сообщение # 7
почти ветеран
Сейчас нет на сайте
Mathf.LerpAngle или чето того
Код
public class Example : MonoBehaviour {
     public float minAngle = 0.0F;
     public float maxAngle = 90.0F;
     void Update() {
         float angle = Mathf.LerpAngle(minAngle, maxAngle, Time.time);
         transform.eulerAngles = new Vector3(0, angle, 0);
     }
}
polousДата: Суббота, 06 Сентября 2014, 02:22 | Сообщение # 8
частый гость
Сейчас нет на сайте
Спасибо, братцы, за помощь! Этот вопрос решил чуть раньше ваших комментариев с подсказки MR_Borg об использовании RotateTodwards:

Quaternion target = Quaternion.Euler (startAngle_x, startAngle_y + AngleOfRotate, startAngle_z);
transform.rotation = Quaternion.RotateTowards (transform.rotation, target, Time.deltaTime * speed);

где startAngle_x - угол x объекта до вращения (transform.rotation.eulerAngles.x) и т.д.

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

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


Сообщение отредактировал polous - Суббота, 06 Сентября 2014, 02:24
LertmindДата: Суббота, 06 Сентября 2014, 02:24 | Сообщение # 9
заслуженный участник
Сейчас нет на сайте
allods, ты - "молодец", но человеку не помочь этой функцией, если он не знает как правильно должно работать. Ему и надо было показать как надо делать, что я сделал выше.
С твоим LerpAngle, надо ещё проделывать такое (не считая ещё таких важных нюансов, как изменение startAngle и targetAngle для повторного поворота):
Код
public float rotationSpeed = 0f; // Скорость поворота
public float targetAngle = 90f; // Угол на который надо повернуться
public float startAngle = 0f;
float journeyTime = 0f;// Времени в движении
float currentTime = 0f;

void Start()
{
    journeyTime = targetAngle / rotationSpeed;
}

void Update()
{
    currentTime += Time.deltaTime;
    float fracComplete = currentTime / journeyTime;
    float angle = Mathf.LerpAngle(startAngle, targetAngle, fracComplete);
    transform.eulerAngles = new Vector3(0, angle, 0);
}

По мне здесь больше геморроя.

Правка: minAngle переназвал в startAngle, так понятней.


Сообщение отредактировал Lertmind - Пятница, 12 Сентября 2014, 02:27
allodsДата: Суббота, 06 Сентября 2014, 11:24 | Сообщение # 10
почти ветеран
Сейчас нет на сайте
Lertmind,

float angle = Mathf.LerpAngle(angle , targetAngle, Time.deltaTime);
transform.eulerAngles = new Vector3(0, angle, 0);

Этого достаточно
LertmindДата: Пятница, 12 Сентября 2014, 01:58 | Сообщение # 11
заслуженный участник
Сейчас нет на сайте
Цитата allods ()
Lertmind,

float angle = Mathf.LerpAngle(angle , targetAngle, Time.deltaTime);
transform.eulerAngles = new Vector3(0, angle, 0);

Этого достаточно

Ничего подобного, твой код работает неправильно, здесь не будет равномерно движения (интерполяция между разными углами) , а в моём коде будет.

У polous правильный код с равномерным движением:
Перед началом поворота -
Код
Quaternion target = Quaternion.Euler (startAngle_x, startAngle_y + AngleOfRotate, startAngle_z);

На каждой итерации -
Код
transform.rotation = Quaternion.RotateTowards (transform.rotation, target, Time.deltaTime * speed); // Здесь deltaTime * speed - это СМЕЩЕНИЕ


Сообщение отредактировал Lertmind - Пятница, 12 Сентября 2014, 01:58
allodsДата: Пятница, 12 Сентября 2014, 10:58 | Сообщение # 12
почти ветеран
Сейчас нет на сайте
Он сказал плавный а не равномерный , вот поэтому я сказал LerpAngle. А так конечно вы правы мисье, у вас правильный код.
dj--alexДата: Воскресенье, 07 Мая 2017, 15:24 | Сообщение # 13
частый гость
Сейчас нет на сайте
Про Love2D в инете вообще ничего не находится кроме этого поста.

Snake174 подскажите как на 90 градусов мгновенно обьект повернуть?
пока выхожу из положения созданием 4 текстур с разными поворотами.
и просто меняю текстуру по необходимости.
но я же не могу для всей графики так делать


Lua + Love
seamanДата: Понедельник, 08 Мая 2017, 00:35 | Сообщение # 14
старожил
Сейчас нет на сайте
Цитата
Про Love2D в инете вообще ничего не находится кроме этого поста.

Да здрасьте!
И на хабре и даже в контакте уроки есть.
Love не знаю, но исходя из кода Snake174 self.ang = self.ang + 90
Форум игроделов » Движки для разработки игр и сложные системы разработки » Unity » точный плавный поворот
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг