King, Witch and Dragon. Отчёт 1
Пару дней работал над процедурной анимацией паучьих лап для способности "карабканье по стенам и потолку".
Описание фичи
В моей игре персонаж обладает способностью "прилипать" и карабкаться по стенам и потолку. При этом стены могут быть не обязательно строго вертикальные, а потолок не обязательно строго горизонтальным.
Визуально способность представлена наличием у персонажа паучьих лап, которые вырастают из спины, когда персонаж "приземляется на стену" и пропадают когда персонаж делает прыжок от стены или выходит на более-менее горизонтальную поверхность.
Итого, повежение паучих лап можно тезисно описать так:
- Используют IK для постановки в нужное место
- Появляются при "приземлении" стену
- Пропадают при прыжке от стены или при выходе на горизонтальную поверхность
- Должны уметь шагать по стенам и потолку разного наклона
- Должны уметь огибать внешние и внутренние углы
- Не должны сильно рябить и визуально "шуметь" и просто смотреться странно
Поехали! (с)
Посмотрев на список требований, я составил список параметров, который должна иметь каждая лапа. Эти параметры я вынес в Scriptable Object, чуть дальше объясню зачем я это сделал. В скрипте на локе указывается референс на этот Scriptable Object и все параметры берутся с него.
В свойствах задаётся минимальное и максимальное допустимое расстояние IK-таргета (конца лапы) от персонажа. Если таргет выходит за этот диапазон, лапа делает шаг. Также задаётся положение таргета по умолчанию, если лапа не может найти "землю". Задаются свойства для поиска точки на поверхности, а также время на совершение шага, плюс кривые для интерполяции или твинига шага (ускорение, замедление и т.д.) и высота шага.
Определяем момент когда нужно сделать шаг
Для начала я создал одну лапу и начал настраивать её на плоской поверхности. Вот так выглядит логика нахождения IK-таргета в заданном диапазоне. Так как лапы и поверхность могут распологаться под любым углом, нельзя брать расстояние по оси, по этому диапазоны обозначены кругами вокруг основания лапы. При пересечении одного из красных кругов совершается шаг:
Упрощённый код для этого выглядит так (на самом деле всё немного сложнее, но тем не мене):
Находим новую точку на поверхности
Для этого мы также используем окружность, потому что, также как и в прошлом параграфе, мы не знаем заранее под каким углом будет находиться поверхность, на которую лапа попытается встать. Вот только стандартный CircleCast или SphereCast тут не помогут, т.к. нам нужна именно точка на окружности. Для этого я использовал последовательный LineCast по касательной к окружности заданного радиуса, а если быть совсем точным, то это LineCast по секторам с поворотом на заданный угол:
Функция для поиска точки на поверхности с использованием этого метода выглядит так:
Ну и в нагрузку код для перемещения таргета из предыдущего полгожения в новое:
Синхронизация лап
С одной лапой всё выглядело и работало круто, до тех пор, пока я не прицепил персонажу 4 лапы, по 2 с каждой стороны...
Пока движение шло по ровной поверхности всё выглядело прилично, но при изменении наклона и при огибании углов положение лап отностельно друг друга сбивалось и момент шага относительно других лап уходил в рассинхрон. Иногда получались курьёзные ситуации, когда сначала шаг делали 2 лапы слева, потом 2 лапы справа, получался эдакий паучий галоп. Или того хуже, все 4 лапы одновременно решали, что именно сейчас отличный момент сделать шаг и отрывались от стены... Персонаж, конечно, никуда не падал, но выглядело очень странно. Пришлось искать пути как синхронизировать лапы между собой.
Сначала, я попробовал в каждый момент времени двигать только одну лапу и ставить других в очередь, пока первая не закончит шаг. Часть проблем это решило, но некоторые всё равно остались, например неправильный порядок и "галоп".
В итоге я пришёл к тому, что разбил лапы на 2 группы, в каждой группы была 1 левая и 1 правая лапа. Если одна из лап в группе "хочет" сделать шаг, то вторая лапа в этой же группе тоже принудительно делает шаг. Получаем 2 лапы с разных сторон персонажа делают одновременное движение. При этом, второй группе запрещается шагать, пока первая группа не закончит. Получаем синхронное шагание "2-через-2".
После этого я создал 4 Scriptable Object'a с параметрами лап и в каждом из них немного поменал значения, так что каждая лапа движется немного по разному (разное время на совершение шага, разная высота над поверхностью, разные минимальные и максимальные расстояния). Это мало заметно в движении, но при остановке видно, что лапы стоят не симметрично.
Конечный результат:
ДИСКЛЕЙМЕР: поза персонажа - заглушка. Я сделаю специальную анимацию для этого состояния, но сразу скажу, что персонаж так и будет всегда в вертикальном положении. Это выглядит немного странно и не то, что сходу ожидаешь, но зато это позволит в будущем сделать атаки в 4 направлениях (влево, право, вверх, вниз) пока персонаж ползёт по стенам и потолку. Мне кажется, что такая геймплейная свобода важнее, чем персонаж "красиво" прилегающий к стене.
Что дальше?
На этом с паучьими лапами пока что всё. Следующая на очереди змея с её процедурной анимацией хвоста при рывке.
Спасибо за внимание!