#8 Godot: 3D Platformer от BornCG. Привязка камеры к игроку
Приступим. Сегодня в меню:
- добавление камеры, следующей за игровым персонажем;
- сглаживание движения камеры с помощью функции lerp().
Если мы посмотрим на наш текущий проект, то заметим (это сложно не заметить), что камера статична и не меняет своего положения при перемещениях объекта персонажа игрока.
Такое поведение камеры нас не устраивает, поэтому приступим.
Для того, чтобы исправить поведение камеры, нам нужно... удалить текущую камеру из сцены Level1. Дело в том, что мы добавим камеру в сцену Steve, содержащую игрового персонажа, что позволит нам изящно решить вопрос перемещения камеры за игроком, а также пригодится на случай использования игрового персонажа на других уровнях (читай - сценах) нашей игры. Поэтому отдельная камера на уровне нам не нужна - мы будем использовать камеру, привязанную к персонажу.
Итак, во вкладке level_1 в панели Сцена кликаем правой кнопкой мыши на узел Camera3D и выбираем Удалить (Delete).
Переходим во вкладку steve и в панели Сцена добавляем к корневому узел Steve дочерний узел Camera3D.
В целом мы уже сейчас можем просто поменять положение камеры на более выгодное...
...поставить для узла Camera3D в панели Инспектор галочку напротив свойства Current...
...и получить вот такой результат
В целом задача решена, но при таком подходе камера не меняет своего положения вообще - а хочется иметь в том числе режим со свободной камерой, чтобы свободно вращать её и вертеть. Поэтому мы пойдём другим путём.
После создания узла Camera3D создаём ещё один дочерний узел Node3D, и переименовываем его как Camera_Controller.
К узлу Camera_Controller добавляем дочерний узел Node3D, который переименовываем как Camera_Target.
Узел Camera_Target перемещаем вдоль положительного направления оси Z и приподнимаем. Затем в верхней части рабочего пространства нажимаем на кнопку Использовать локальное пространство (Т)...
И слегка наклоняем узел в сторону игрового персонажа (без включения опции Использовать локальное пространство узел Node3D не отражает изменения положения вращения).
Затем в панели Сцена перетаскиваем узел Camera3D в узел Camera_Target.
Теперь узел Camera3D является дочерним для узла Camera_Target.
Сейчас камера находится в центре координатной сетки.
Для того, чтобы переместить её туда же, где расположен узел Camera_Target, в панели Инспектор раскрываем группу свойств Transform и сбрасываем значения параметров Position и Rotation до нулевых.
После сброса камера перемещается точно к своему родительскому узлу Camera_Target.
Если мы запустим проект сейчас, то увидим, что у нас получилось всё то же самое, что могло получиться и раньше.
Однако камера всё ещё привязана к игровому персонажу, поэтому мы идём дальше.
В панели Сцена выделяем узел Camera_Controller и в панели Инспектор ставим галочку напротив параметра Top Level.
После этого мы увидим, что камера снова не привязана к игровому персонажу - потому что параметр Top Level как раз отвечает за то, чтобы узел не наследовал изменения координат родительского узла.
Теперь переходим во вкладку с кодом (можно сделать с помощью соответствующей иконки рядом с корневым узлом Steve).
Нам нужно сделать так, чтобы узел Camera_Controller изменял своё положение так же, как и наш игровой персонаж, причём постоянно в процессе игры. Для этого в функции _physics_process мы напишем такие строки кода:
Символ $ позволяет нам обратиться к дочернему узлу, в данном случае - к узлу Camera_Controller. Остальное же - дело техники: мы просто присваиваем значения параметров позиции игрового персонажа параметрам позиции дочернего узла Camera_Controller. Вот что получается в итоге:
Однако есть проблема: статтеры при изменении направления движения игрового персонажа - задержка хоть и небольшая, но присутствует постоянно и хорошо заметна. Дело в том, что мы сначала перемещаем камеру с помощью строчки нашего кода, а затем уже меняем положение игрового персонажа с помощью вызова метода move_and_slide(). Поэтому, если мы переместим перемещение (каламбур) камеры после вызова данного метода,
то получим нормальный результат.
Теперь поработаем над плавностью камеры. Плавность обеспечим применением функции lerp(start, end, factor), которая принимает три аргумента:
- start - начальное значение, в нашем случае - текущее положение камеры, то есть $Camera_Controller.position
- end - конечное значение, в нашем случае - положение игрового персонажа, то есть position
- factor - число между 0 и 1, которое определяет степень интерполяции, в нашем случае - определяет скорость изменения положения камеры за один фрейм. Для примера установим значение в 1%, то есть 0.01
Посмотрим на результат
Очень уж медленно) попробуем 5%, то есть 0.05
Чего-то не хватает... поставим 0.15 и получим отличный результат: замедление камеры есть, но небольшое и оно не мешает динамичной игре. Обратите внимание на прикольный эффект отдаления камеры при загрузке уровня.
На сегодня, пожалуй, и всё. Пора пить чай и думать о будущем