Проблема с поворотами объекта при многократном вращении
|
|
urbemAngeli | Дата: Воскресенье, 14 Августа 2016, 13:56 | Сообщение # 1 |
частый гость
Сейчас нет на сайте
| Всем привет!Пытаюсь осуществить вращение обьекта при нажатии кнопки по одной из оси(y или z). Камера всегда неподвижна, и суть поворота куба заключается в том, что не зависимо от его поворота относительно камеры, если нажать кнопки(стрелки) он должен поворачиваться строго на 90 град. в том направлении как на скрине. Здесь у меня возникло две проблемы: Проблема 1: Если куб допустим повернуть по оси z на +90° а затем по оси y на 180° , то при последующих поворотах вокруг z, кнопки вверх и вниз меняются местами, чего мне не нужно. Пришел к выводу что проблемой данного явления является когда узнаю текущие углы и добавляю или отнимаю 90 град, может происходить конфликт углов(допустим был угол -90 и нужно для правильного поворота -180, а у меня получается -90 + 90 = 0) и поэтому поворачивается не в ту сторону. Пробовал кубу добавлять родителя и у него брать углы, но тогда куб вращался как хотел. Проблема 2: Если повернуть куб вдоль оси z, то при последующих поворотах вверх или вниз, вращение происходит по оси x, хотя в transform куба во время вращения углы меняются по z. Помогите разобраться с данными проблемали, а то у самого мыслей уже 0 осталось как это можно решить. Сорри что все так запутано описано, ниже скину еще проект, может кому наглядно лучше посмотреть на все это дело.
Код public class HandlerRotation : MonoBehaviour { Quaternion target; bool nowRotate = false; //public Transform parent;
public int speed = 80; int nowFrame = 0;
void FixedUpdate() { if (Input.GetKeyDown(KeyCode.UpArrow)) { if (nowRotate == false) // Проверка для предотвращения поворота по второй оси { target = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, transform.rotation.eulerAngles.z + 90); nowRotate = true; } }
if (Input.GetKeyDown(KeyCode.DownArrow)) { if (nowRotate == false) { target = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, transform.rotation.eulerAngles.z - 90); nowRotate = true; } }
if (Input.GetKeyDown(KeyCode.LeftArrow)) { if (nowRotate == false) { target = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y + 90, transform.rotation.eulerAngles.z); nowRotate = true; } }
if (Input.GetKeyDown(KeyCode.RightArrow)) { if (nowRotate == false) { target = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y - 90, transform.rotation.eulerAngles.z); nowRotate = true; } }
if (nowRotate) { if (nowFrame < 57) // Проверка на окончание поворота { transform.rotation = Quaternion.RotateTowards(transform.rotation, target, Time.deltaTime * speed); nowFrame++; } else { nowRotate = false; nowFrame = 0; } } } Ссылка на проект
Сообщение отредактировал urbemAngeli - Воскресенье, 14 Августа 2016, 14:06 |
|
| |
Storm54 | Дата: Воскресенье, 14 Августа 2016, 17:10 | Сообщение # 2 |
постоянный участник
Сейчас нет на сайте
| Советую прочитать про Gimbal lock.
|
|
| |
Lertmind | Дата: Воскресенье, 14 Августа 2016, 18:16 | Сообщение # 3 |
заслуженный участник
Сейчас нет на сайте
| Вот код:
Код using UnityEngine; using System.Collections;
public class HandlerRotation : MonoBehaviour { public float Speed = 80;
bool nowRotate = false; float angle = 0; Vector3 vectorRotation;
void Update() { if (Input.GetKeyDown(KeyCode.UpArrow)) { if (!nowRotate) { nowRotate = true; vectorRotation = Vector3.forward; } }
if (Input.GetKeyDown(KeyCode.DownArrow)) { if (!nowRotate) { nowRotate = true; vectorRotation = Vector3.back; } }
if (Input.GetKeyDown(KeyCode.LeftArrow)) { if (!nowRotate) { nowRotate = true; vectorRotation = Vector3.up; } }
if (Input.GetKeyDown(KeyCode.RightArrow)) { if (!nowRotate) { nowRotate = true; vectorRotation = Vector3.down; } }
if (nowRotate) { if (angle < 90f) { angle += Time.deltaTime * Speed; transform.Rotate(vectorRotation * Time.deltaTime * Speed, Space.World); } else { angle = 0f; nowRotate = false;
transform.eulerAngles = new Vector3( Mathf.RoundToInt(transform.eulerAngles.x / 90f) * 90f, Mathf.RoundToInt(transform.eulerAngles.y / 90f) * 90f, Mathf.RoundToInt(transform.eulerAngles.z / 90f) * 90f); } } } }
Получилось не очень красиво из-за округления, можно по-другому, но сейчас я сразу не соображу. Если нужен FixedUpdate(), то не забывай менять Time.deltaTime на Time.fixedDeltaTime. А про Gimbal lock есть статья на хабре: https://habrahabr.ru/post/183116/.Добавлено (14 августа 2016, 18:16) --------------------------------------------- Есть ещё одна простая техника, когда создаёшь пустых родителей, каждого для вращения по одной из осей. В твоём случае - два, для удобства можно ещё одного в корне, который будет без вращения.
|
|
| |
urbemAngeli | Дата: Воскресенье, 14 Августа 2016, 23:15 | Сообщение # 4 |
частый гость
Сейчас нет на сайте
| Lertmind, только сейчас добрался до Unity, ваш скрипт работает просто супер, так как я и задумывал. Огромное спасибо:) Техника с родителями не совсем понятна, если первый родидель вращать по одной из оси, то для второго родителя(внутренний) остальные 2 оси будут отличными от мировых, и очень сложно будет реализовать вращение в требуемом направлении.
Сообщение отредактировал urbemAngeli - Воскресенье, 14 Августа 2016, 23:21 |
|
| |
Lertmind | Дата: Понедельник, 15 Августа 2016, 02:55 | Сообщение # 5 |
заслуженный участник
Сейчас нет на сайте
| urbemAngeli, можно изменять локальные углы Эйлера (Transform.localRotation). Есть книга Building a Game with Unity and Blender - Lee Zhi Eng - 2015, там на странице 156 это используется.
|
|
| |
urbemAngeli | Дата: Понедельник, 15 Августа 2016, 08:13 | Сообщение # 6 |
частый гость
Сейчас нет на сайте
| Lertmind, спасибо за наводку, буду разбиратся
|
|
| |