В предыдущем рассказе я описал базовые шаги по настройке проекта. Прочитайте его, если еще не сделали этого.

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

Шаг 6. Движение

Как вообще-то передвигать персонажа (который есть набор отдельных 3D-объектов) в пространстве? Я уже рассказывал ранее в 4 шаге о том, об объединении объектов в группу. Еще раз: вы можете перемещать группу с линейной скоростью; в сумме с подходящей анимацией это будет выглядеть как ходьба или бег, в зависимости от вашей задумки.

То есть если стоит задача передвигать NPC в каком-то направлении, скажем, на север, то нужно всего лишь:

  1. Повернуть его в этом направлении

  2. Мало-по-малу передвигать

Самый удобный, по-моему, способ - это использовать композицию. Для этого я создам файл /hoc/Movable.jsx со следующим поведением:

Этот компонент берет всех потомков и перемещает их в направлении вектора heading в каждом новом кадре. Свойство Velocity отвечает за то, как далеко он это делает. Обратите внимание на onMove: о нем мы поговорим чуть позже.

Кстати, добавился еще хелпер /helpers/getRotation.js который делает некоторую магию школы кватернионов, чтобы собственно поворачивать группу.

Теперь, если обернуть персонажа в компонент <Movable /> то он будет двигаться. Зацените демо:

Шаг 7. Поддержка геймпада

Раньше, вплоть до начала карантина, у меня не было геймпада. Я купил его просто попробовать. И оказалось, что это довольно удобный способ управления (никогда бы не подумал, но Diablo II: Resurrected с геймпадом - это что-то с чем-то). А в chrome поддержка геймпадов была еще давным-давно. Так что же мешает поэкспериментировать?

Gamepad API - довольно простая штука; можно даже брать код из примеров. Но чтобы заморачиваться еще меньше, я буду использовать библиотеку Gamepads. Используя контекст в реакте можно просто описать весь связующий код в одном месте и получать информацию о нажатиях кнопок, направлении и силе нажатия на стики прямо в компоненте Movable. Вот тут можно посмотреть реализацию: /GamepadControls.jsx — колбеки для геймпада и клавиш WASD на клавиатуре (ссылка); /Player.jsx — небольшая обертка над моделью игрока, которая и будет реагировать на ваши действия (ссылка).

Теперь я заменю всех NPC в index.js этим:

<GamepadControls>
  <Player />
</GamepadControls>

И все!

Используйте геймпад, если он у вас, конечно, есть, или клавиатуру.

Следующий важный вопрос: "Как соединить всех зомби, игрока и файрболы? Как враги узнают, где находится игрок?". И ответ - вы его знаете - глобальное состояние.

Шаг 8. Управление состоянием

Бесспорно, никакой фронтед-проект в 2021 не обходится без слоя управления состоянием. Игры не исключение. Вы, конечно, можете брать вашу любимую библиотеку, пусть то Redux, MobX, effector или что-то еще. В этом вообще никакой разницы. Я выбрал Zustand.

Все сущности можно представить коллекциями. Добавляем сущность (зомби или файрбол) в нужную коллекцию, рендерим, потом в нужный момент (файрбол врезается в зомби, или улетает слишком далеко) просто удаляем. Думаю, все не раз это проделывали, только сущности были другими, к примеру, товары в интернет-магазине.

Добавились следующие хранилища в папке /store:

Надеюсь, названия методов говорят сами за себя. Player хранит позицию (она должна быть доступна всем) и жизни игрока; zombies - id каждого врага, их местоположение и hp. Наконец, fireballs используется для управления количеством и направлениями всех файрболов в сцене.

Теперь компонент Player выглядит так:

А Fireball - так:

И еще зацените компонент Zombie особенно вот эти места:

Теперь зомби преследуют вас, куда бы вы ни пошли.

Полный код этого примера доступен тут, за одним исключением: в codesandbox какие-то проблемы с парсингом .fbx, так что все модели там заменены на цветные кубики.

Спасибо за внимание! В следующий раз я разберу вопрос столкновений и UI.

Дополнение

Есть вероятность, что ваш геймпад не заработает в демке. Проблема в маппинге. У меня самый простой геймпад со стандартным маппингом, а за нестандартным обращайтесь к документации библиотеки Gamepads.

Комментарии (0)