Трудности с вращением ребенка вокруг родительских осей

Я знаю, что есть миллион вопросов о вращении, я пробовал и читал много вещей, но, похоже, не могу решить эту конкретную проблему.

Единственный способ, которым я могу придумать, чтобы объяснить это должным образом, - это с некоторыми плохо нарисованными диаграммами, так что вот!

У меня есть родительский объект и дочерний объект (здесь он представлен в виде кубика, где сумма противоположных граней составляет 7), оси на этой диаграмме - это родительские направления X, Y и Z.

Отправная точка:

Отправная точка

Я хочу, чтобы дочерний объект имел два метода, которые я назову RotateZ и RotateX. RotateZ и RotateX должны вращать дочерние кубики вокруг родительских осей Z и X с шагом 90 градусов.

ПовернутьX:

Начальная точкаRotateX

Повернуть Z:

Начальная точкаRotateZ

Код, который у меня сейчас есть, это

void RotateZ(int value) {
    transform.rotation *= Quaternion.AngleAxis(90f * value, pivot.transform.forward);
}

void RotateX(int value) {
    transform.rotation *= Quaternion.AngleAxis(90f * value, pivot.transform.right);
}

Я должен отметить, что пивот является родительским объектом

Похоже, это отлично работает, если дочерний элемент начинает с поворота (0, 0, 0), многократный вызов RotateZ или RotateX с начальной точкой (0, 0, 0) отлично работает. Эта проблема возникает, если, например, я звоню RotateX, а затем RotateZ.

После начального вызова RotateX он будет выглядеть так, давая дочернему элементу поворот на (90, 0, 0).

Начальная точка RotateX

Затем после RotateZ желаемый результат таков:

После RotateX введите здесь описание изображения

Но вместо этого я получаю следующее:

После RotateX После поворотаXZ

Я действительно в недоумении, что я делаю неправильно. У меня такое чувство, что я достиг предела того, что я могу делать с углами Эйлера, и мне нужно выучить кватернионы, чтобы предотвратить эту проблему. Какая функция вращения мне нужна, чтобы получить желаемый результат?


person GP89    schedule 10.06.2016    source источник
comment
У вас впечатляющая проблема. Никогда ни по какой причине не используйте кватернионы. Упоминание их в руководстве Unity сбивает с толку; они предназначены только для специального внутреннего использования, совершенно не относящегося к какому-либо обычному игровому программированию. В любом случае, все, что вам нужно, это RotateAround. Наслаждаться   -  person Fattie    schedule 10.06.2016
comment
Также обратите внимание, что вы можете просто захотеть установить .eulerAngles.   -  person Fattie    schedule 10.06.2016
comment
@JoeBlow Изначально я использовал углы Эйлера, и у меня была точно такая же проблема. Я знаю, что есть ограничения с углами Эйлера, когда они не будут выполнять работу, поэтому существуют кватернионы. Я подумал, что это может быть один из тех случаев, поэтому я попытался изменить реализацию. Я знаю, что они более запутаны и менее просты в использовании, но если вы столкнетесь с блокировкой карданного подвеса, у вас не будет выбора, кроме как использовать их, я не думаю, что ваше мнение о том, чтобы никогда их не использовать, правильное.   -  person GP89    schedule 11.06.2016
comment
Вы проверили RotateAround. это супер-полезно   -  person Fattie    schedule 11.06.2016
comment
@JoeBlow Выглядит хорошо, но я не уверен, что это сработает. Мне нужно повернуть его вокруг оси родителя, а не оси мировых координат   -  person GP89    schedule 11.06.2016
comment
это легко: я объясню в ответ.   -  person Fattie    schedule 11.06.2016
comment
Я также дам вам абсолютно критический совет.   -  person Fattie    schedule 11.06.2016


Ответы (1)


Похоже, вам нужен действительно потрясающий звонок

Повернуть вокруг

это одно из самых важных в Unity. Документ RotateAround

Не забывайте, что RotateAround вращается вокруг вектора — ЛЮБОГО вектора.

Огромный совет...

Повсеместный метод в разработке видеоигр: вы используете маркеры — то есть просто пустой игровой объект — которые вы прикрепляете к объектам или к которым вы прикрепляете свои объекты.

Очень часто вы временно прикрепляете объект к маркеру, чтобы переместить его, а затем снова снимаете с маркера.

Вот как это сделать в коде. Сделать маркер controlRotator...

  1. сделайте controlRotator дочерним элементом вашего объекта управления.

  2. сделайте его идеально прямым локально: т. е. просто точно такой же ориентации, как у родителя, объекта управления, т. е. локальное вращение = тождество

  3. затем ловко установите позицию WORLD для controlObject точно в позицию WORLD для smallCube...

  4. ваш smallCube, запишите его родителя. снимите smallCube с этого родителя.

  5. Далее временно сделайте smallCube дочерним элементом controlRotator

...и теперь можно...

  1. поверните элемент управления Rotator как вам угодно!

Вы просто вращаете controlRotator, а не маленький куб.

Обратите внимание, что теперь вы делаете именно то, о чем просили, вы вращаете smallCube используя ось объекта управления. Умно, верно?

  1. наконец, верните smallCube к родителю, который вы сохранили на шаге 4.

Это именно то, как вы это делаете. На практике это настолько распространено, что для этого вам понадобится расширение или функция.

Обратите внимание, что вполне нормально сделать так, чтобы GameObject управлял Rotator на лету по мере необходимости, и избавиться от него после поворота. (Это всего лишь математическая абстракция.)

Дальнейший совет...

Эта операция должна работать с объектом управления. Сделайте скрипт под названием

TwistSomethingOnMyAxis.cs

и поместите это НА CONTROLOBJECT.

Будет один звонок

 public void twistThisThing(Transform twistIt) {}

Что вы делаете, так это, когда вы хотите скрутить МАЛЕНЬКИЙ КУБ, вы фактически вызываете TwistSomethingOnMyAxis НА ОБЪЕКТЕ УПРАВЛЕНИЯ. Понимаете? Так нравится

TwistSomethingOnMyAxis:twistor = 
  controlObject.GetComponent<TwistSomethingOnMyAxis>();
twistor.twistThisThing( smallCube , .. 90 degrees on Y or whatever .. );

Надеюсь это имеет смысл! Наслаждаться!

person Fattie    schedule 11.06.2016
comment
Спасибо RotateAround сделал работу! Я прочитал ваш совет и думаю, что начинаю понимать шаги и то, как они будут работать. Я попробую! Похоже, я научился очень полезному трюку! Спасибо! Что касается дальнейшего совета, будет ли он работать лучше как статический метод в статическом вспомогательном классе, а не в компонентах, которые можно присоединить. - person GP89; 11.06.2016
comment
Кроме того, еще один хороший совет, мой инстинкт заключался бы в том, чтобы поместить этот тип логики в статический метод в статическом вспомогательном классе или расширить метод на тип, но в Unity мне действительно нужно больше думать о компонентах, чтобы это можно было сделать. привязывается к любому типу, и всему можно придать поведение Twist - person GP89; 11.06.2016
comment
Привет GP, рад, что это решило проблему. Вы знаете, определенно не используйте статику (как правило) в Unity, отложите это в сторону. Это просто не работает с системой ECS. Во-первых, если вы опытный программист, впервые работающий с Unity, расширения (категории) занимают центральное место в Unity Experience :) stackoverflow.com/a/35629303/294884 используйте расширения везде и всегда. - person Fattie; 11.06.2016
comment
Вы действительно попали в самую точку о компонентах, это очень проницательно. Вот эссе на эту тему: stackoverflow.com/a/37243035/294884 И пока мы здесь, вот хороший общий разглагольствовать! stackoverflow.com/a/37391504/294884 - person Fattie; 11.06.2016
comment
Да, единственный раз, когда я думаю, что статика была бы полезна или правильный выбор для модельных частей игры для классов, которые не являются MonoBehaviour и могут быть легко протестированы. Спасибо за чтение, я обязательно проверю их! Что такое ЭКС? Не думаю, что я видел этот термин раньше - person GP89; 11.06.2016
comment
Когда я начинал объектно-ориентированное программирование много лет назад, я часто использовал наследование, но с течением времени я использовал его все меньше и меньше в пользу компонентов. Затем, несколько лет назад перейдя на С# с интерфейсами, я обнаружил, что вообще никогда не использую наследование, даже до запуска единства пару месяцев назад. - person GP89; 11.06.2016
comment
Прочитайте эти ссылки, это действительно обнадеживает, я уже использую много расширений и компонентов и уже не наследование, так что похоже, что у меня не так уж плохо. Одна вещь, которую я поймал на том, что я не видел упоминаний, заключалась в том, что я делал все как GameObject, и когда я пришел писать модульные тесты (я должен написать их первым, я знаю! :P), я обнаружил, что вы можете на самом деле не модульный тест MonoBehaviours. С тех пор я начал писать как можно больше логики и как можно больше отделять простые объекты C#, которые я могу покрыть модульными тестами. - person GP89; 11.06.2016
comment
например, в этой игре у меня есть игровые объекты, которые имеют позиции и повороты и т. д., а также правила относительно того, куда они могут перемещаться и т. д. Я написал методы расширения, такие как Describe, которые возвращают дескриптор, определяющий все характеристики интересующего меня игрового объекта. Затем логика, определяющая, как и куда они могут двигаться, модель с состоянием, может быть передана этим дескрипторам. Таким образом, я могу создавать дескрипторы в тестах и ​​одну из этих простых моделей классов С#, передавать их и тестировать на ожидаемый результат/поведение. и в игре я могу просто вызвать Describe, чтобы получить данные для модели. - person GP89; 11.06.2016