Является прямым продолжением этой статьи. Без её прочтения может быть тяжело)
Итак, мы (гейм дизайнер) определились с базовым мувсетом и попросили программиста накодить его в базовом варианте. Как теперь сделать так, чтобы бег и прыжки ощущались приятными, и игрок был готов тыкать в кнопку дэша сотни раз и ловил от этого чистейшее удовольствие?
Основатель студии, сделавшей Celeste, говорил, что студия была собрана из людей, которые всю карьеру до того делали сайд скроллеры. И что концепция Celeste родилась из уверенности в своих силах сделать офигенный прыжок. А Celeste на 99% состоит из разных прыжков.
Допустим, такие опытные товарищи могли бы сразу реализовать крутой мувсет прям в коде. Но это инди, в таких студиях очень распространены мультиклассовые сотрудники, например гибрид гейм дизайнера и программиста. В большинстве студий побольше дела обстоят совсем не так.
Приведём очень реалистичный пример. Вы гейм дизайнер, который не только впервые реализует мувсет для сайд скроллера, но и код воспринимает как древнюю шумерскую клинопись. Что и как вам надо объяснить программисту, чтобы мувсет заработал корректно?
Итерации
Так как геймдизайнер — вы, то вам и решать хороши ваши бег, прыжок и т. д. или требуют доработки. Выясняется это очень понятным способом — разного рода плейтестами.
Вы много играете в свою игру, чтобы оценить качество управления. Параллельно вы играете в чужие игры, мувсеты которых вы уважаете и на которые хотели бы равняться в каких-то аспектах. Таким образом вы собираете солянку из чужих и (возможно) ваших собственных идей.
Чтобы сохранять трезвую голову, надо давать потрогать свой мувсет и третьим лицам — как коллегам «в теме», так и геймерам с улицы, плохо знакомым с жанром.
Плейтестить надо итеративно: поиграли → нашли проблемы → внесли изменения. Потом опять поиграли → нашли новые проблемы, и далее по кругу.
...думаю, вам уже понятно, что в подходе выше не достаёт важной детали.
Так как вы отвечаете за мувсет, то именно вы должны корректировать его в процессе плейтестов. Но как организовать себе возможность менять код во время итераций плейтестов, если вы в коде ни в зуб ногой?
Публичные переменные
Начать надо с настройки окружения. Рассмотрим на примере движка Unity.
Любая переменная, объявленная как public, будет видна прям в свойствах объекта в редакторе движка.
Пример: переменная int livesNumber обознает количество жизней у персонажа в сайд скроллере. Мы — гейм дизайнер, и {у нас лапки} мы не знаем, где эту переменную искать в коде, и как вообще она называется.
Мы просим программиста объявить её как public int livesNumber, и теперь эта переменная видна нам прям в свойствах нашего персонажа с полем для ввода, куда мы можем написать что вздумается.
Теперь мы можем плейтестить игру с любым количеством жизней, которое посчитаем нужным, и менять это значение в любой момент.
Вытаскивать переменные можно так же в виде слайдеров, чекбоксов и, возможно, чего-то ещё.
Мы не знаем, на основе каких формул авторы Celeste собирали свой мувсет. Тем более, что они позиционируют себя как большие профессионалы в вопросе, и там могут быть какие-то скрытые нюансы. Но давайте попробуем взором стороннего наблюдателя декомпозировать их готовые механики.
Декомпозиция дизайна (и самая суть этой дилогии статей)
Итак, какие именно переменные должны создать и вынести в свойства программисты, чтобы мы могли успешно итерировать наш мувсет?
|| ~ Бег ~ ||
В Celeste с бегом всё относительно просто. Его можно отрегулировать 3мя переменными. Это:
- Предельное значение скорости при беге. В Celeste единственная скорость и есть предельная. В зависимости от движка и используемых формул это может быть максимальная сила, применяемая к персонажу при нажатии влево-вправо.
- Положительное ускорение при нажатии влево-вправо. Или прилагаемая сила. Определяет, насколько быстро персонаж разгонится до максимальной скорости. В Celeste это весьма быстро.
- Отрицательное ускорение при отпускании влево-вправо. Определяет время с момента отпускания клавиши до полной остановки. Тут вариантов больше, чем с предыдущими пунктами. Если перемещение реализовано через приложение силы к персонажу, торможение будет работать и без отдельной переменной — он будет просто скользить по инерции. Но для большего контроля переменную иметь полезно.
Но это уже итоговая концепция, попавшая в игру. Что бы нам ещё могло пригодиться при тестировании бега?
Допустим, добавление ещё одного «колена» в процесс разгона. То есть персонаж быстро разгоняется до вменяемой скорости и, если долго бежит на ней, постепенно разгоняется до второго потолка скорости. В таком случае пришлось бы добавить ещё одну предельную скорость и ещё одно ускорение до второго потолка.
Ещё можно было бы добавить чекбоксы на выпиливание любых ускорений. Таким образом наш персонаж бы сразу трогался с предельной скоростью и при отпускании клавиши бы сразу останавливался. Так можно посравнивать свою модель бега с самым олдовым его вариантом, популярным во времена Spectrum и NES.
|| ~ Глобальная физика ~ ||
Всё указывает на то, что в Celeste используется физика. Поэтому будем рассматривать только вариант с приложением силы к персонажу, а остальные отметём.
Мы уже описали бег и готовимся описать прыжок. И уже понятно, что не хватает какой-то общей базы.
Если мы используем внутриигровую физику, нам нужно её глобально отрегулировать.
Для этого нам понадобятся переменные для:
- Массы персонажа. Чем персонаж легче — тем суровее воздействует на него приложенные силы. И при этом меньше воздействует сила трения.
- Гравитации. Это, думаю, всем понятно на интуитивном уровне.
Так же для разных поверхностей может задаваться разная сила трения. Для этого может понадобиться комплект переменных по числу видов поверхностей.
|| ~ Прыжок ~ ||
С прыжком возможны многочисленные вариации, поэтому тут особенно высок шанс ошибиться в анализе. Заранее простим себя за это🙂
В отличие от экшенов от 3го лица, где движение может считываться со стика или мышки по очень большому количеству направлений (бежим прямо, но при этом чуть-чуть налево); в Celeste инпут считывается по 8 осям. Это вверх-вниз-вправо-влево и оси под 45°.
Причём считывание по всем 8 осям идёт только в воздухе, и нужно это для совершения дэшей. Это может быть не очевидно, но на земле любые комбинации с направлением вниз (вниз, вниз+вправо, вниз+влево) не ведут к приложению силы и перемещению. С их помощью осуществляется приседание, которое с точки зрения логики живёт отдельно от перемещения.
Поэтому для прыжка с земли нас интересуют только направления вверх, вправо и вверх+вправо. Левые направления будут работать аналогично. И да, для прыжка вертикально вверх саму клавишу W нажимать не обязательно.
В теории авторы могли бы сделать прям 3 разных прыжка для каждого из трёх направлений. Но в Celeste этот момент сделан прямолинейно; во всех трёх случаях к персонажу прикладывается одинаковая сила вверх.
При этом в прыжке есть определённая вариативность, так как высота прыжка зависит от длительности удержания кнопки.
Итого мы имеем набор переменных:
- Вертикальная сила, прикладываемая к персонажу при нажатии прыжка. Тут понятно.
- Добавочное время приложение силы после отпускания клавиши. Пример: если клавиша прыжка удерживалась 100 миллисекунд — то подъёмная сила будет действовать на персонажа (100 + X) мс. Где X выводится отдельной переменной.
- Максимальная длительность удержания кнопки прыжка. По истечении этого времени дальнейшее удержание кнопки будет игнорироваться. Таким образом мы задаём максимальную высоту прыжка.
- Время зажатия, требующееся для совершения прыжка выше минимального. Можно заметить, что минимальный прыжок в Celeste - штука очень консистентная. В смысле его очень легко получить. Для достижения этой консистентности может иметься некоторый зазор по времени удержания кнопки. В который всё равно вызывается самый короткий вариант прыжка.
- Противодействующая сила + переменная для определения времени её воздействия. Наверное можно обойтись без неё и дать персонажу затормозить самостоятельно об гравитацию. С другой стороны, мы можем хотеть, чтобы прыжок ощущался быстрым, а потом вдруг резко переходил в падение. В таком случае мы можем дать большую подъёмную силу в начале, а потом в какой-то момент дать противодействующую силу. Когда персонаж начнёт падать, мы можем отключить противодействующую силу или оставить её как есть.
- Коэффициент эффективности движения вправо-влево в воздухе. Тут возможен целый веер вариантов. В некоторых играх если перс прыгнул вправо — нажатие влево после прыжка не даёт вообще ничего. В отдельных персонаж в воздухе может носиться вправо-влево как умалишенный (Super Meat Boy). В большинстве — что-то среднее. Причём система может быть комплексной — при прыжке вправо игрок пролетает большее расстояние, чем он успел бы за это время пробежать, но на попытку в воздухе завернуть влево реагирует со скрипом. В Celeste как будто этот параметр оставили на стандартных 100% или вообще не создавали.
|| ~ Дэш в воздухе ~ ||
Дэш в Celeste работает довольно необычно; не припомню прямых аналогов из других игр. Как будто здесь происходит следующее: в течение очень короткого времени к персонажу прикладывается сила по одной из 8ми осей. Впечатление, что мы выстреливаем из пушки самим собой.
Расстояние, преодолеваемое при дэше по любой оси воспринимается как одинаковое. Что невозможно реализовать по-тупому из-за действия гравитации. Поэтому скорее всего были добавлены корректировки в зависимости от направления (например, при дэше вниз прикладывается меньшая сила, так как она суммируется с гравитацией).
Ещё один важный момент — пока дэш не закончился, мы никак не можем влиять на его направление. Повернуть в обратную сторону нельзя. Я думаю, что у нас на какое-то время просто забирают управление.
- Набор величин прикладываемых сил по разным осям. Объяснил выше.
- Набор времён, на которые у нас забирают управление в зависимости от оси.
С основными концепциями мы разобрались выше, осталось добить 2 базовых движения из мувсета.
|| ~ Зацеп за стену и ползание по ней ~ ||
Тут всё ± просто:
- Коэффициент наследования вертикальной скорости при зацепе. Например мы стремительно летим вниз и при падении зацепились за стену. Если мы при этом обнуляем вертикальную скорость — то как будто сразу намертво приклеиваемся к стене. Если нет — то будем уже после зацепа какое-то время скользить вниз пока не остановимся. В Celeste мы как раз моментально приклеиваемся.
- Скорости ползания по стене. Могут быть разные для движения вверх и вниз. В Celeste так и есть.
- Время, после которого персонаж отцепится от стены и начнёт падать. Тут понятно.
- Коэффициент наследования вертикальной скорости при отвале от стены. В Celeste если мы отваливаемся при скольжении вниз — то стремительно летим в пропасть. Если бы скорость не наследовалась, было бы ощущение, что мы скользили вниз, наткнулись на уступ, резко затормозили и уже после этого упали (медленнее).
И последнее!
|| ~ Прыжок от стены ~ ||
БОльшую часть свойств мы наследуем от обычного прыжка. Кроме двух:
- Отдельная вертикальная сила для прыжка от стены. В отличие от обычного прыжка, подъёмная сила будет более скромная.
- Коэффициент наследования вертикальной скорости при прыжке от стены. В Celeste это 0%, она не наследуется. Если мы прыгаем при скольжении вниз — подлетаем ровно на столько же, как при зацепе на месте или подъёме наверх. Если бы наследование было, то прыжки от стены ощущались бы совсем иначе.
Ну вот и всё!
Думаю, и вам, и мне должно хватить этих знаний чтобы собрать вменяемое управление в сайд скроллере с поддержкой программиста. Было сложно, местами душно, но, надеюсь, интересно и полезно.
Конечно же не забываем, что крутые ощущения от мувсета делаются не только с помощью механики. Анимации, звуки и работа камерой тоже очень важны.
Если вы до сюда дочитали — вот вам приз за отвагу:
Я надеюсь и дальше время от времени постить здесь подобный предметные материалы по гейм дизайну. Так что, надеюсь, до встречи😁
Лучшие комментарии