В предыдущем рассказе я описал базовые шаги по настройке проекта. Прочитайте его, если еще не сделали этого.
В этот раз речь пойдет о немного более сложных вещах, таких, как управление состоянием, компоненты высшего порядка и Gamepad API.
Шаг 6. Движение
Как вообще-то передвигать персонажа (который есть набор отдельных 3D-объектов) в пространстве? Я уже рассказывал ранее в 4 шаге о том, об объединении объектов в группу. Еще раз: вы можете перемещать группу с линейной скоростью; в сумме с подходящей анимацией это будет выглядеть как ходьба или бег, в зависимости от вашей задумки.
То есть если стоит задача передвигать NPC в каком-то направлении, скажем, на север, то нужно всего лишь:
Повернуть его в этом направлении
Мало-по-малу передвигать
Самый удобный, по-моему, способ - это использовать композицию. Для этого я создам файл /hoc/Movable.jsx
со следующим поведением:
![](https://habrastorage.org/getpro/habr/upload_files/e9b/b3f/313/e9bb3f3136e9be6122fa8824b5f72720.png)
Этот компонент берет всех потомков и перемещает их в направлении вектора 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 выглядит так:
![](https://habrastorage.org/getpro/habr/upload_files/909/119/09c/90911909cbda1838544f1bc7302685d8.png)
А Fireball - так:
![](https://habrastorage.org/getpro/habr/upload_files/ff9/156/3e3/ff91563e34836715b67c7c0c1fd00acd.png)
И еще зацените компонент Zombie особенно вот эти места:
![](https://habrastorage.org/getpro/habr/upload_files/b89/88b/85a/b8988b85a478d1a76292d44d7fcbd2dc.png)
![](https://habrastorage.org/getpro/habr/upload_files/61e/3c2/4ca/61e3c24ca1207ed92805a504f6eeb309.png)
Теперь зомби преследуют вас, куда бы вы ни пошли.
Полный код этого примера доступен тут, за одним исключением: в codesandbox какие-то проблемы с парсингом .fbx, так что все модели там заменены на цветные кубики.
Спасибо за внимание! В следующий раз я разберу вопрос столкновений и UI.
Дополнение
Есть вероятность, что ваш геймпад не заработает в демке. Проблема в маппинге. У меня самый простой геймпад со стандартным маппингом, а за нестандартным обращайтесь к документации библиотеки Gamepads.
![](https://habrastorage.org/getpro/habr/upload_files/f7d/093/541/f7d093541412fca82d3abdd88edc1f81.png)