Туториал – Вращение объекта с помощью мыши в UE4
Юрий “yurembo” Язев
независимый игродел
Во многих играх
(особенно в MMORPG) в
главном меню есть экран «Создания персонажа», где игрок создает (настраивает)
своего персонажа. Обычно (особенно в симуляторах техники) персонаж вращается по
оси Y. Вдобавок, зажав
над персонажем курсор, игрок может поворачивать персонажа в любую сторону.
Сегодня я
расскажу о том, как сделать вращающийся в трехмерной сцене объект. Хотя в
рассматриваемом примере объект вращается по оси Y, на основе полученных сведений вы
легко можете организовать вращение по X или Z.
Следующее
изображение показывает полную программу, служащую для вращения:
Постепенно
начнем вгрызаться в программу. В отличие от предыдущих версий движка, Unreal Engine 4 вместо привычного
скриптового языка содержит графический язык программирования, в котором
программные конструкции строятся путем размещения и настройки взаимодействия
блоков – функций. Я не буду здесь подробно рассматривать этот механизм
визуального программирования, ибо туториал посвящен другой теме.
Во-первых, нам
нужно событие щелчка мыши. Как вы знаете, в UE4 каждый объект имеет событие OnPressed. Однако мы программируем Level Blueprint. В нашем случае это
удобно, поскольку, таким образом, мы можем получить доступ к любому объекту
уровня с глобальной позиции. Тем не менее, в этом случае мы лишены события OnPressed мыши.
Но мы легко можем его добавить. Для этого откроем настройки проект (Edit -> Project Settings), и в открывшемся
окне щелчком по пункту Input (с левой стороны) откроем меню настройки управления
(справа). Далее, щелчком по кнопке с плюсом рядом с пунктом Action Mapping добавим новое событие.
Развернем образовавшийся список. Появится поле ввода для задания имени нового
события. Введем MouseClick.
Ниже текстового поля находится ниспадающий список, содержащий список
всевозможных событий от устройств ввода. Нам
необходимо развернуть список Mouse и выбрать в нем событие Left Mouse Button. В моем случае это выглядит так (следующее изображение):
Теперь мы можем
вернуться в Level Blueprint и создать это новое событие, выбрав его из контекстного
меню.
Как видно, этот
блок содержит 2 вывода: один реагирует на нажатие (Pressed), а второй – на отпускание (Released) левой кнопки мыши.
В данном случае нам нужен второй - Released. При таком развитие событий, где будет обрабатываться
нажатие (Pressed)? Это
событие должно происходить при нажатии на вращающемся объекте, а не на пустом
месте сцены. Поэтому, после импортирования 3D-модели в движок, нам необходимо создать для нее Blueprint-класс. Однако,
сперва надо просто создать Blueprint-класс
– наследник от Actor. После
его создания, двойным щелчком по объекту Blueprint откроем окно редактора объекта.
Перейдем на вкладку Components,
затем из Content Browser перетащим импортированную трехмерную модель в окно редактора
на панель Components. Теперь,
можно переименовать, как саму модель, так и Blueprint-класс. Также, в редакторе можно наложить на модель
любые материалы. Далее перейдем на вкладку Graph, где, собственно, происходит весь процесс кодирования.
Сначала нам надо добавить переменную булева типа. Назовем ее canRotate, так как она разрешает или запрещает вращать объект.
Эта переменная станет членом нашего нового класса. Далее, щелкните правой
кнопкой мыши по свободному пространству графа и из контекстного меню выберите Event Actor on Clicked. Данное событие
произойдет, когда пользователь нажмет кнопку мыши над нашим объектом. Теперь, перетащите
переменную canRotate с панели на пространство графа. В результате, появится
контекстное меню. Выберем из него пункт Set. Образуется новый блок, который позволяет установить
переменной нужное значение. Галочкой отметим переменную canRotate и соединим
этот блок с блоком события Event Actor on Clicked.
Обратите
внимание, чтобы сделать переменную открытой (т.е. доступной для других Blueprint –
классов) надо щелкнуть на закрытом глазе рядом с переменной на панели. В
результате, он откроется, что будет означать доступность переменной. Теперь, мы
снова можем вернуться в Level Blueprint.
Добавим 2 переменные: delta типа float и tank – ссылка на только что созданный класс 3d объекта.
На этом графе у
нас уже имеется один блок – событие InputAction MouseClick. Далее, от выхода Released перенесем
нить для создания блока set canRotate.
В этом блоке необходимо сбросить значение булевой переменной.
Взгляните, этот
блок имеет свойство Target для того, чтобы указать движку переменную-член какого
объекта мы хотим модифицировать. Помните, мы создали переменную, которая
указывает на трехмерный объект из другого класса? Она называется tank. Перетащим ее с панели
на граф. В появившемся меню выберем пункт Get. Свяжем Tank с Target.
Теперь, нам надо узнать координаты позиции курсора мыши. Чтобы их получить
сначала создадим Get Player Controller
блок, он возвращает текущее пользовательское устройство ввода. Из выходного
значения создадим блок Get Input Mouse Delta.
Эта функция возвращает разность между последней и текущей позициями мыши. Это,
как раз то, что нам нужно!
Если применить
это значение к вращению объекта, то он будет поворачиваться слишком медленно. В
таком случае нам нужно умножить это значение на -10. Отрицательное значение
используется для того, чтобы вращение объекта происходило в противоположную
сторону.
Сейчас, мы
можем создать объект-вращатель (Rotator).
Чтобы это сделать, нам надо воспользоваться функцией Make Rot, найдите его в контекстном
меню. Свяжите результат умножения с входящим значением Yaw данной
функции. После этого, свяжем выходной результат функции Make Rot с
входом A функции Combine Rotators.
Значением для второго входного параметра операции объединения (combine) должна быть текущая
позиция объекта в 3d сцене. Чтобы ее получить, создайте функцию Get Actor Rotation из контекстного
меню. Как и в прошлый раз, параметром target этой функции должен служить tank. Возвращаемое значение
функции Combine Rotators
является сформированный объект – вращатель, который может использоваться для
вращения трехмерного объекта в 3d сцене. Таким образом, из контекстного меню нам надо создать
новую функцию “Set Relative Rotation”.
Ей нужен параметр target,
которым, как вы знаете служит tank,
если перетащить нить от tank к данному блоку, Blueprint автоматически добавит необходимое
преобразование типов.
Сейчас, нам
необходимо немного вернуться назад. Как видно “Set Relative Rotation” не получает
управления. В таком случае, нам надо создать новое событие: Event Tick, оно срабатывает каждый
тик. После возникновения события, контроль передается на условное выражение, в
котором определяется значение переменной canRotate. Ели она равна true, тогда управление передается в функцию Set Relative Rotation. И, она поворачивает
наш объект. Мы рассмотрели один путь выполнения нашей программы, когда объект
поворачивается следом за курсором мыши.
Во втором пути
выполнения программы, объект поворачивается, благодаря своей инерции. Когда пользователь
отпускает кнопку мыши, скорость мыши (delta) сохраняется в переменной. И, объект поворачивается с этой
скоростью. Но когда программа сохраняет скорость мыши (delta)? После выполнения функции Set Relative Rotation управление
передается в условный оператор, где снова проверяется значение переменной canRotate, если оно равно
истине, тогда программа изменяет значение переменной delta, которую мы объявили ранее.
Если условие
после возникновения события Event tick
ложно, тогда программа выполняет другую функцию Set Relative Rotation, которая получает
другие параметры. В данном случае дельта берется из переменной delta. Другие операции такие же: Make Rot, Combine Rotators, Get Actor Rotation и,
в качестве, параметра target так же выступает tank.
Заметьте,
переменная delta имеет начальное значение, что позволяет вращаться объекту
сразу после запуска программы. Затем, пользователь может изменить скорость и
направление вращения объекта.
Теперь, мы
полностью рассмотрели программу вращения 3d объектов в 3d пространстве.
Если у вас
возникли какие-то вопросы, задавайте их в комментариях.