Как стать автором
Обновить

История одной разработки: Передвижные барабаны в стиле классики Sokoban в инди платформере X-Drums 2.0

Уровень сложностиСредний
Время на прочтение11 мин
Количество просмотров810

В Steam завершился «Фестиваль передвижных ящиков», посвященный играм, где разными способами можно передвигать ящики. На английском фестиваль называется «Sokoban Fest» в честь первой игры, где появилась эта механика.

Игра-головоломка «Sokoban» (яп. 倉庫番, рус. кладовщик) вышла в Японии в 1982 году и вскоре стала абсолютным хитом. Разработал ее годом ранее Хироюки Имабаяси (яп. 今林宏行). Как пишет сам автор в своем приветствии на официальном сайте, ему захотелось создать игру, где персонаж может толкать груз и таким образом перемещать его в пространстве. Используя эту простую механику, он решил собрать головоломку, где этот самый груз, который необходимо перемещать, еще и мешает самому процессу.

PC-8801 倉庫番
PC-8801 倉庫番

«Sokoban» имела колоссальный успех. И механика привлекла тогда внимание многих геймдизайнеров, которые стали применять ее в новых играх и продолжают применять в современных играх разных жанров.

В своем проекте X-Drums 2.0 на Unreal Engine 5 мне захотелось добавить эту механику. И в этой статье я расскажу, что из этого получилось и какие еще игры повлияли на финальную реализацию.

Как делали в разных играх

На фестивале «Sokoban Fest» было представлено около 500 небольших игр, где механика передвижных ящиков была ключевой. Но как одна из множества, механика чаще встречается в платформерах, но нередко и в RPG, JRPG и action играх.

В моем игровом опыте передвижные ящики (они же кубы) встретились мне в играх NieR: Automata, NieR Replicant ver. 1.22, Final Fantasy VII Remake, STAR WARS Jedi: Survivor. Примеры из этих игр и предлагаю рассмотреть для формирования требований к механике в своем проекте.

NieR: Automata

NieR: Automata | A2 толкает куб
NieR: Automata | A2 толкает куб

В игре NieR: Automata передвижной куб встречается в нескольких локациях. Один из кубов находится в Пустыне, в тоннеле между Котлованом (англ. Pit Hollow), где происходит первая встреча с Адамом и Евой, и ее Пограничной зоной (англ. Border Area). Еще один закрывает проход между Городскими руинами (англ. City Ruins) и деревней Паскаля (англ. Pascal’s Village). Эти кубы предназначены для того, чтобы открыть проход между локациями во время выполнения заданий основного сюжета, поэтому встреча с ними неизбежна.

Еще два куба находятся в Лесном замке (англ. Forest Castle). Один блокирует проход в кузницу Масамуне (англ. Masamune Blacksmith), а второй расположен в подвале, где проходит встреча машин. Кубы в Лесном замке не связаны с сюжетом, и их можно даже не найти, если не исследовать территорию.

NieR: Automata | Проход в кузницу Масамуне
NieR: Automata | Проход в кузницу Масамуне

Главные герои игры андроиды 2B, 9S и A2 могут толкать куб вперед и тянуть его на себя, используя физическую силу. Для этого игроку необходимо удерживать триггер, чтобы ухватить объект (англ. Grab), а потом двигаться в одном из интересующих направлений вперед или назад. Какой именно триггер, указано в подсказке, всплывающей, когда герой находится рядом с гранью.

NieR: Automata | A2 тянет куб
NieR: Automata | A2 тянет куб
Видео передвижения куба

Кроме этих кубов, геймдизайнеры NieR: Automata предлагают игрокам передвигать и классические коробки на складах одного из обитателей Лагеря сопротивления (англ. Resistance Camp) в серии сайд квестов «Проблемы сортировки» (англ. Sorting Trouble). Как в той самой игре «Sokoban».

Всего в этой серии три квеста, которые необходимо выполнять последовательно. Два из них проходят на складе в Лагере сопротивления, а заключительный — в Городских руинах на одной из крыш здания. Квесты представляют из себя легкую головоломку, где игроку нужно толкать вперед деревянные ящики, чтобы освободить проход к целям. В отличие от взаимодействия с кубами, эти ящики нельзя тянуть на себя, как и в оригинальной игре «Sokoban».

NieR: Automata | Квест «Проблемы сортировки» 3
NieR: Automata | Квест «Проблемы сортировки» 3
Скрытый текст

Следующая за персонажем камера в этих квестах меняет обзор на топ-даун (англ. Top-down view), что является очередным примером оригинальных решений геймдизайнеров серии. Наряду с 2D камерой на некоторых локациях (англ. 2D Side View Camera) и другими приемами. Больше про такие решения можно прочитать здесь.

NieR Replicant ver. 1.22

Похожая головоломка есть и в игре NieR Replicant ver. 1.22, но она не является квестом, который выдается и требует выполнения. Это просто одна из небольших локаций. И доступ к ней открыт в любое время игры, а ящики всегда активны для взаимодействия. Находится она на Почте в Приморье (англ. Seafront).

Главному герою необходимо передвигать ящики, чтобы освободить проход в следующую комнату, где находится ценный лут. Схема взаимодействия с ящиками такая же, как в NieR: Automata, но здесь герой может двигать их в обоих направлениях, то есть и тянуть на себя. Ящики, которые можно сдвинуть, имеют более светлый оттенок и маркируются с помощью белого UI ромба. Он становится желтым, если захват объекта (англ. Grab) уже произошел.

NieR Replicant ver. 1.22 | Головоломка на почте
NieR Replicant ver. 1.22 | Головоломка на почте

Еще несколько головоломок, но уже с перемещением кубов и с привычным видом от третьего лица, предстоит решать игроку в комнатах в Пустынном храме (англ. The Barren Temple). Это локация из первой части игры, которая является частью основной сюжетной линии.

Главный герой в команде с напарниками Кайне и Вайсом должен помочь жителям города Фасада (англ. Facade) найти принца, пропавшего на территории храма. В поисках героям предстоит последовательно пройти 7 непростых комнат. Задача в каждой — добраться до красного куба в конце комнаты и уничтожить его. Но задачу усложняют блоки, стреляющие снарядами в стиле bullet-hell, а также запрет на использование одной или нескольких способностей, о которых сообщается на входе.

В качестве укрытия и преграды на линии огня геймдизайнеры, собственно, и предлагают использовать расположенные в комнатах передвижные кубы. Они есть в первой и четвертой комнате. Схема взаимодействия с ними такая же, как с кубами в NieR: Automata.

NieR Replicant ver. 1.22 | Одна из комнат в Пустынном храме
NieR Replicant ver. 1.22 | Одна из комнат в Пустынном храме

Головоломки в Пустынном храме заметно сложнее всех описанных ранее, потому что происходят в условиях, представляющих опасность для героя, когда его функционал существенно ограничен. Их прохождение обязательно для продвижения по сюжету, и после прохождения повторить их снова невозможно.

В целом в мире NieR Replicant ver. 1.22 передвижным кубам уделяется намного больше внимания, чем в NieR: Automata. Они есть во многих локациях и имеют разный визуал. Впервые такой куб встречается в самом начале игры в Затерянном храме (англ. Lost Shrine). Дальше их можно найти и на территории Свалки (англ. The Junk Heap). В зависимости от расположения предполагается разное их использование: в качестве платформы для прыжка или как укрытие.

NieR Replicant ver. 1.22 | В Затерянном храме
NieR Replicant ver. 1.22 | В Затерянном храме
Видео из комнат в Пустынном храме

Другие примеры

Еще один пример этой механики есть в Final Fantasy VII Remake. В одной из глав на пути главного героя Клауда появляется зеленый контейнер, который необходимо передвинуть, чтобы использовать его в качестве платформы для проникновения на новую территорию.

Final Fantasy VII Remake | Interact with Box
Final Fantasy VII Remake | Interact with Box

За всю игру встречается только один такой куб. И, как и в играх серии NieR, без его передвижения продвинуться дальше невозможно.

Видео с кубом в Final Fantasy VII Remake

Еще передвижные кубы есть в серии God of War (видео с ними по ссылке). И есть в STAR WARS: Jedi: Survivor. В первой их передвижение реализовано как в описанных ранее играх. А вот в Jedi: Survivor разработчики предлагают передвигать их с помощью телекинеза, которым обладает главный герой — джедай Кэл Кестис (англ. Cal Kestis).

В качестве «ящика» в игре выступает металлический контейнер в форме куба желтого цвета внушительных размеров. В радиусе возможного взаимодействия его корпус начинает светиться синим цветом. Контейнер можно как притягивать к себе, так и отталкивать, используя соответствующие триггеры. В сравнении с классической схемой перемещение таким образом не всегда предсказуемо, поэтому требуется не одна попытка, чтобы доставить его в нужное место.

STAR WARS: Jedi: Survivor | Movable Box
STAR WARS: Jedi: Survivor | Movable Box

Встречается такой контейнер впервые в самом начале игры на планете Корусант (англ. Coruscant). Несколько таких контейнеров находятся на планете Джеда (англ. Jedha). Их передвижение обязательно для продвижения дальше. Еще несколько контейнеров есть на Кобо (англ. Koboh). Они предназначены для проникновения на дополнительные территории с сундуками и являются частью необязательной головоломки.

Видео кубы в STAR WARS: Jedi: Survivor

Итак, подведем итог и сформируем основные требования к передвижному ящику в моей игре. В качестве примеров будем использовать игры серии NieR, God of War и Final Fantasy VII Remake с поправкой на 2D. Реализация Jedi: Survivor интересна, но не подходит, поскольку наш герой джедайской силой не обладает. Дальше напомню немного про свою игру.

Про X-Drums 2.0 и передвижной барабан

Игра называется X-Drums 2.0. Это мультиплеер 2D пиксель-арт платформер c поддержкой single-player режима, посвященный теме барабанов. Главным героем выступает барабанщик, управляя которым, необходимо собрать ноты и найти выход.

Действие игры разворачивается условно на складах музыкальных инструментов, где размещаются барабаны, тарелки, клавиши пианино и разные подвижные платформы, по которым можно ходить и прыгать. На пути героя встречаются влюбленные фанатки, отбирающие ноты. Купидоны, пускающие стрелы, и ослепляющие прожекторы.

Игра разрабатывается на Unreal Engine 5.3 на C++ с использованием Steam Online Subsystem для мультиплеера. Подробнее про разработку можно прочитать здесь.

В качестве передвижного ящика наиболее подходящим в моей игре мне показался большой барабан 64×64 пикселей.

X-Drums 2.0 | Передвижной барабан
X-Drums 2.0 | Передвижной барабан

Опираясь на приведенные примеры, сформируем следующие ключевые требования к барабану (ящику в моей интерпретации) и его поведению:

  1. Барабан должен перемещаться строго по горизонтали по направлению движения персонажа.

  2. Скорость движения барабана одинаковая, независимо от того, толкают его или тянут.

  3. Передвижение должно выглядеть с усилием, будто барабан обладает значительной массой.

  4. Когда герой находится рядом с гранью барабана, появляется всплывающая подсказка, какой триггер необходимо использовать, чтобы его передвигать.

  5. Для передвижения игроку необходимо удерживать триггер, чтобы ухватить барабан (англ. Grab), и двигаться в одном из интересующих направлений (вперед или назад), используя привычные триггеры движения.

  6. Барабан должен останавливаться при коллизиях со статичными или подвижными объектами (в том числе и с персонажем другого игрока).

  7. На барабан можно запрыгнуть. В момент приземления на него проигрывается такой же звук, как при прыжке на статичные барабаны.

  8. Барабан не блокируется одним игроком. Его могут пробовать передвигать одновременно несколько.

  9. При перемещении барабана используется свой набор анимации персонажа: тянуть-толкать.

  10. При перемещении барабана проигрываются звуковые эффекты.

Теперь перейдем к некоторым интересным и значимым деталям реализации.

Некоторые детали реализации

Классический способ реализации захвата объекта (англ. grab) и перемещения его в пространстве реализуется в Unreal Engine с помощью Physics Handle Component, который предполагает включение физики у перемещаемого объекта.

Наряду с этим компонентом существует Physics Constraint Component, который чаще применяется для связки твердых тел и передачи движения от главного к подчиненному. Например, для груза на веревке. Этот компонент также предполагает использовать физику объекта.

Для 2D пиксель-арт игры использовать физику, а особенно ее включение в радиусе взаимодействия и выключение вне, мне показалось overkill’ом и overhead’ом. Поэтому, реализовав несколько прототипов, демонстрирующих немало проблем этих способов, было решено отказаться от их использования.

Прототип с Physics Constraint Component
Использование Physics Constraint Component
Использование Physics Constraint Component

Еще один способ реализовать желаемое поведение в Unreal Engine — это использовать Attachment to Actor или Attachment to Component. Но у него есть свой большой недостаток. Так, объект после прикрепления (англ. attachment) теряет свои коллизии и поэтому может проходить сквозь стены и другие объекты. На форумах пишут, что победить это невозможно без включения физики, и объясняют тем, что в состоянии присоединения объектов таким способом коллизия сохраняется только у parent объекта. Это самый главный блокер способа, хотя были и другие.

Прототип с Attachment to Actor
Использование Attachment to Actor
Использование Attachment to Actor

Что же тогда остается?

Мне показалось возможным использовать Add Actor Local Offset барабану на каждый Tick, получая направление движения от Player Character — игрока, перемещающего барабан.

void AMovableDrum::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (HasAuthority() && MovingCharacter && bGrabbed && bIsOccupied)
	{
		FVector DeltaLocation = FVector::ZeroVector;

		float MaxSpeed = MovingCharacter->GrabMaxSpeed;
		
		DeltaLocation.X = MoveDirection * MaxSpeed * DeltaTime;

		FHitResult* HitResult = nullptr;

		AddActorLocalOffset(DeltaLocation, true, HitResult);

		if (HitResult && HitResult->bBlockingHit)
		{
			bGrabbed = false;
		}
	}
}

MovingCharacter определяется в момент overlap персонажем триггер компонента барабана (UBoxComponent Grab Volume). В этот же момент происходит подписка на делегаты OnGrabActionStartedDelegate и OnGrabActionEndedDelegate.

OnGrabActionStartedDelegate сообщает о начале захвата барабана — это удержание клавиши Alt, что переводит bGrabbed в статус true и передает направление движения MoveDirection, где (1) — это движение вперед, а (-1) — движение назад.

OnGrabActionEndedDelegate сообщает, что захват прекращен, и переводит bGrabbed в статус false.

Реализация анимации

Перемещение барабана предполагает специфические анимации персонажа: толкать барабан от себя (англ. push) и тянуть его на себя (англ. pull), как в примерах ранее.

Для этого в стейт машине в анимационном блюпринте (англ. AnimBP) добавлено два новых стейта: push и pull.

AnimBP
AnimBP

А чтобы не усложнять код, решено было не различать в C++ эти два новых состояния и использовать проверку в самом AnimBP. Так, если: скалярное произведение форвард вектора актора и его нормализованной скорости > 0, то это push, а если < 0, то это pull.

Правило перехода в Pull state
Правило перехода в Pull state
Правило перехода в Push state
Правило перехода в Push state

Новое поведение предполагает отключение обновления направления движения, благодаря которому происходит переворот Control Rotation в Controller в случае движения назад. Однако в некоторых случаях такой поворот все-таки происходит, и персонаж тянет барабан на себя спиной. К сожалению, разобраться с этим поведением у меня не получилось, и поэтому оно превратилось в фичу. А почему бы и нет?

Для звуковых эффектов движения барабана по поверхности в соответствующие анимации персонажа добавлены AnimNotifyState вместо привычного и готового AnimNotifySound, поскольку в первом есть ивенты BeginPlay и EndPlay, что позволяет ограничивать проигрывание периодом, а не проигрывать звук постоянно, так как анимация циклическая.

Итак, смотрим, что из этого получилось!

Видео в отличном качестве вместо гифки

Дополнительные фичи

Палитра игры включает в себя 8 ключевых цветов, поэтому передвижных барабанов планировалось также 8, различающихся на старте только по цвету. В будущем можно добавить в различия звуки и эффекты.

Поскольку все передвижные барабаны обладают одинаковыми свойствами и различаются только по цвету, то был создан Base Actor Blueprint с TMap Flipbook по Enum, который отвечает за цвет.

Как и с софитами (о них можно почитать здесь), на карте планируется размещать несколько барабанов, поэтому необходим механизм их разнообразия, отвечающий следующим условиям:

  • рядом не должны оказаться одинаковые по цвету барабаны,

  • на карте должны быть представлены барабаны всех цветов и

  • при каждом запуске цвета должны меняться.

Для этой задачи был использован такой же метод рандомизации через гейммод, что был использован для софитов. Поэтому каждый запуск уникальный.

Known Issues и Change Log

Несмотря на многократные тесты в мультиплеере с несколькими Steam игроками, последний релиз проявил неприятный баг, когда барабан редко, но начинал проходить сквозь стены. Баг добавлен в баг-трекер. Надеюсь его победить в будущих релизах.

С момента прошлой публикации в игре появилось множество изменений. Например, добавлен подсчет времени, в целесообразности которого я сомневалась в самом начале. А также:

  • Добавлена новая карта и непосредственно выбор карт.

  • Добавлена и доработана механика клавиш пианино, которые были в основной игре.

  • Добавлена механика множественных выходов.

  • Значительно обновлен арт.

  • Добавлена локализация на 5 языков и многое другое.

Скачать последнюю версию, включающую и передвижные барабаны, можно по ссылке.

Видео прохождение после релиза

Заключение

Игра-головоломка «Sokoban» продолжает вдохновлять геймдизайнеров на свои интерпретации как всей игры, так и отдельно механики перемещаемого в пространстве ящика. И «Sokoban Fest» — явное тому подтверждение.

Вдохновившись примерами, мне удалось реализовать свой вариант такого ящика в рамках моего ремейка X-Drums 2.0 на Unreal Engine 5. И в ходе реализации пришлось познакомиться со способами, которые предлагает движок, и определить наиболее подходящий для своей игры. А также решить немало задач по адаптации под мультиплеер и поддержке сетевого кода. О чем здесь сказано не много, поскольку больше хотелось сфокусировать на общем подходе.

Новая механика наряду с запуском платформ добавила игроку еще одну возможность влиять на игровой мир и прохождения других игроков. Она сбавила высокий темп игры и позволила разнообразить левел дизайн. На мой взгляд, она неплохо вписалась в общую концепцию. Но так ли это? Решать вам, игрокам!

Теги:
Хабы:
+3
Комментарии0

Публикации

Работа

QT разработчик
8 вакансий
Программист C++
100 вакансий

Ближайшие события