В этой статье вы узнаете как поворачивать объекты в Defold. В программирования нет понятия градусов. Для поворотов в двухмерных играх используют радианы. Однако, Defold — это полностью трёхмерный движок. Даже когда вы создаёте 2д игру, то используется трёхмерное пространство. В трёхмерных играх, в основном, используются кватернионы и расширенная версия углов Эйлера. Рассмотрим сначала углы Эйлера, радианы, кватернионы по отдельности, а потом способы поворота объектов и их преобразования.
Углы Эйлера
Начнём с наиболее простой для понимания темы — углы Эйлера. Углы Эйлера описывают последовательные вращения объекта вокруг трех осей координат (x, y, z). По сути это те же самые градусы, но в трёхмерном пространстве с указанием оси. Например, указанная система координат (0, 0, 90) поворачивает объект по оси Z на 90 градусов. В действительности, то, что мы используем в игровых движках на сегодняшний день, это расширенная версия Эйлеровых углов. Сам Леонард Эйлер описывал вращение объекта по двум осям с использованием трех переменных. Часто такой метод поворота описывают визуализацией юлы
Расширенная же версия углов Эйлера описывает поворот вокруг трех осей с использованием трех переменных.
Повороты эйлеровых углов задаются конкретной последовательностью трех чисел. То есть присваивание поворота конкретному объекту по каждой оси должно протекать в определенном порядке. Если мы хотим изменить поворот какого-либо объекта сразу по трем осям, то присвоение нужного поворота не пройдет за одну операцию. Из-за этого часто возникает известная проблема под названием gimbal lock — потеря одной степени свободы. При использовании эйлеров могут возникать ситуации, когда две оси будут совпадать, отчего мы потеряем поворот по одной из осей. Например, при повороте объекта на 90 градусов вокруг оси x, вращая далее объект по осям y и z мы заметим, что они идентично поворачивают объект, к чему и приводит особенность Эйлеровых углов.
Однако здесь есть один крайне важный ньюанс: так или иначе Defold всё равно преобразовывает углы Эйлера в кватернионы. Сделано это для того, чтобы как раз-таки избегать проблемы шарнирного замка. Иначе говоря, мы можем задавать повороты углами Эйлера, однако “под капотом” Defold преобразует все в кватернионы во избежание проблемы.
Для базовых задач достаточно использовать углы Эйлера. Например, их используют для функции плавного поворота через go.animate()
function init(self)
-- поворот по часовой стрелке на один полный оборот за две секунды
go.animate(".", "euler.z", go.PLAYBACK_LOOP_FORWARD, -360, go.EASING_LINEAR, 2)
end
Однако помимо проблем с углами Эйлера, они также требуют больше вычислительных мощностей и ресурсов, чем кватернионы. Поэтому для поворотов в трёхмерных пространствах часто используют кватернионы, хоть и они более сложные в понимании.
Радианы
Прежде чем начать работать с кватернионами, надо понять радианы.
Как вы знаете, окружность делится на 360 частей, которые называются градусами.
Однако, это условная единица. Можно было разделить окружность и на 720 частей. Поэтому придумали радиан — угол, образованный дугой, численно равной радиусу окружности.
В чем отличие от градуса? А в том, что угол образован реальной дугой окружности, а не мнимым делением на 360 кусков общей окружности.
Радианы и градусы легко переводятся друг в друга. Есть простое соотношение:
В Defold есть функция math.rad(), которая превращает градусы в радианы
print(math.rad(180)) -- 3.1415926535898
Радианы используются для вычисления кватернионов.
Кватернионы
Кватернионы — четырёхмерный вектор, описывающий поворот вокруг оси на заданный угол. В Defold он выражается так: vmath.quat(x, y, z, w). Первые 3 компонента — это три оси координат в трёхмерном пространстве или же мнимые части, а четвёртый компонент w — компонент, описывающий поворот или же вещественная часть. Кватернионы рассчитываются по этой формуле:
x = RotationAxis.x * sin(RotationAngle / 2)
y = RotationAxis.y * sin(RotationAngle / 2)
z = RotationAxis.z * sin(RotationAngle / 2)
w = cos(RotationAngle / 2)
где RotationAxis — ось вращения (вектор направления), а RotationAngle — угол вращения. Не пытайтесь воссоздать функцию вычисления кватернионов в Defold, там, на удивление, нет векторного направления. Но есть функции, которые как раз рассчитывают кватернионы по нужной оси: vmath.quat_rotation_x(), vmath.quat_rotation_y(), vmath.quat_rotation_z(). Они принимают радианы и возвращают рассчитанные кватернионы.
Интересно, почему нет векторного направления, но есть кватернионы? Defold, я требую полную свободу действий с векторами!
Пример:
go.set_rotation(vmath.quat_rotation_z(3.14)) -- поворот на 180 градусов
Поворот по оси z используют в 2д играх
Способы вращения объектов в Defold
Примеры поворотов с использованием эйлеров:
go.set(".", "euler.z", 90)
--задаёт свойство объекта "поворот по оси z" на значение 90
Под капотом эйлеры всё равно преобразуются в кватернионы, даже если мы не используем функцию vmath.euler_to_quat(x, y, z).
go.set_rotation(vmath.euler_to_quat(0, 0, 90))
--сначала эйлеры преобразовываются в кватернионы,
--а потом объект поворачивается на указанные кватернионы
Снизу пример, в котором никто ни во что не превращаются. Указаны чистые кватернионы.
go.set_rotation(vmath.quat(0, 0, math.sqrt(0.5), math.sqrt(0.5)))
-- поворот на все те же 90 градусов по оси Z
Пример ниже преобразовывает радианы с указанной осью в кватернионы
go.set_rotation(vmath.quat_rotation_z(1.5707963267949))
-- поворот на 90 градусов по оси Z
Также мы можем радианы получить из градусов:
go.set_rotation(vmath.quat_rotation_z(math.rad(90)))
И вот, бонусом держите пример, в котором объект поворачивается в сторону курсора мыши:
function init(self)
msg.post(".", "acquire_input_focus")
end
function on_input(self, action_id, action)
if not action_id then
local cursor_pos = vmath.vector3(action.x, action.y, 0)
local pos = go.get_position()
local angle = math.atan2(pos.x-cursor_pos.x, cursor_pos.y-pos.y)
go.set_rotation(vmath.quat_rotation_z(angle))
end
end
Спрайт должен смотреть вверх, иначе он будет поворачиваться не куда надо
Сообщение тем, кто прочитал статью от начала до конца
Если Вы прочитали статью от начала до конца и всё поняли, то поздравляю! Вы теперь знаете немного высшей математики
Говорят, чтобы понять высшую математику, надо сойти с ума. Но я так не думаю, кстати, вы теперь умеете делать такие штуки: