Protos, дневник #2: детектив о пустом чузере, камера из глаз и вопрос залу
День второй. В прошлой серии мантл научился класть руки на кромку, а вольт молча возвращал пустоту. Сегодня: как я три дня искал убийцу вольтов и нашёл троих, зачем камере жить внутри головы, и большой вопрос к тем, кто делал полнотелый FP.
[СКРИН: вайтбокс-небоскрёбы в лесу - о них в конце]
Детектив о пустом чузере
Симптом: чузер траверсал-монтажей на запрос вольта отвечал пустотой. Всегда. При этом мантлы работали как часы, а по колонкам таблицы запрос проходил идеально.
Прорыв случился, когда я открыл для себя живую отладку чузеров: во время PIE открываешь таблицу, выбираешь Debug-объект - и она в реальном времени подсвечивает, какая строка выбрана и на какой колонке гаснут кандидаты. Красная ячейка = вот твой убийца. После недели гаданий по логам это ощущается как включить свет в тёмной комнате.
Убийц оказалось трое, все - я сам:
1. Автокомплит-предатель. Собирал условие «тип действия == Vault», а автодополнение подсунуло вместо константы Vault функцию IsVaulting() из моего же компонента. Блюпринт молча привёл enum и bool к байтам и сравнивал «тип == 1» с «нахожусь ли я в старом вольт-режиме == 0». Для вольта это всегда ложь. Все булевы поля структуры умирали, чузер не находил ни одной строки.
2. Оборванный Index. У Select-узла глубины препятствия отвалился провод Index - и он всегда возвращал ветку по умолчанию: глубину 150. Чузер честно решал «препятствие толстое, это мантл» - и вольты играли мантл-анимации. Один провод, и вся семья перемахов выключена.
3. Select-пустышка. Пин Speed питался от Select с двумя пустыми входами. Скорость всегда ноль - чузер всегда брал stand-варианты анимаций, даже на спринте 700. Отсюда неделя «почему он лезет как пенсионер, я же бегу».
Мораль, выстраданная: после любой правки графа - прогон всех действий с чтением лога. Провода в блюпринтах отваливаются локтем, молча, и валят систему не в месте обрыва, а через три таблицы. И вторая: в текстовом дампе блюпринта (Ctrl+C по узлам вставляется как текст!) спрятаться невозможно - все три обрыва в итоге нашлись именно так.
Что теперь работает
Вся линейка траверсала, с честными данными о мире:
- Hurdle - перемах с пробежкой, когда за препятствием есть пол (проверяю трейсом за препятствие);
- Vault - перемах в обрыв, когда пола нет (прыжки между крышами!);
- Catch - перехват кромки в полёте. Тонкость: катч включается только когда персонаж уже падает (Velocity.Z < 0). Сначала сделал «в воздухе = катч» - и прыжок у бортика на уровне груди давал анимацию «повис на скале»: руки на полметра выше кромки, подтягивание в пустоту. Падаешь - хватаешься, летишь вверх - перемахиваешь;
- Climb - залаз на 2.5 метра, выбрался по высоте сам, я даже не просил.
[ВИДЕО: hurdle/vault/catch/climb/slide]
Ложка дёгтя, жирная. У GASP-монтажей в начало зашита фаза подхода: пара-тройка шагов разбега до хвата. Анимации снимались с дистанции, а мой детектор срабатывает и вплотную к стене - и тогда персонаж честно отыгрывает эти шаги в воздух или прямо в препятствие, после чего варп рывком выдёргивает его к кромке. На одиночном мантле глаз ещё прощает, но я построил полосу препятствий - и там, где залазы идут очередью, это выглядит откровенно уродски. Быстрого лечения нет: буду пробовать расширять окно Motion Warping на фазу подхода в копиях монтажей и резать стартовые кадры позовым матчингом или переписывать систему обнаружений. Если вы это уже проходили - расскажите, что сработало у вас.
Слайд оброс физикой: с горки разгоняется (проекция гравитации на плоскость склона), в горку глохнет, вход со склона доступен с шага (не надо разбегаться - горка сама разгонит), кулдаун пол секунды против спама. А бег по склонам теперь чуть медленнее в обе стороны - и спуск слайдом стал выгоднее спуска бегом. Механики начали подпирать друг друга - ради этого всё и затевалось.
Камера из глаз
Камера переехала с капсулы на кость головы: позиция следует за головой со сглаживанием и «поводком» (дальше 120 см не убегает), поворот - строго от мыши. В мантле камера теперь ныряет и карабкается вместе с телом, в слайде стелется у пола. Ощущение физического тела появилось мгновенно.
Три грабли по дороге:
- Голову скрывать не надо. Классический трюк «спрятать кость головы» убивает и её тень. А если камера сидит внутри головы у глазниц - полигоны изнутри просто не рендерятся, владелец головы не видит, мир и тени видят. Ноль кода;
- Камера улетела в космос. Функция базовой высоты читала позицию камеры, к которой я же в конце кадра добавлял смещение глаз. Каждый кадр +15 см. Урок на всю жизнь: не читай свой выход как свой вход;
- Присед телепортировал камеру: движок при приседе мгновенно роняет центр капсулы. Лечится компенсацией дельты полувысоты в тот же кадр.
Провал недели и вопрос залу
А вот поворот тела за камерой я провалил. Дано: полнотелый FP, персонаж на CMC, анимации GASP в страйф-режиме. Стоя тело не доворачивается за мышью вообще (можно обойти камерой и посмотреть себе в лицо), turn-in-place не заводится. Флик на 180 в беге показывает спину.
Попробовал честный ручной доворот: отвязал капсулу от контроллера, крутил её сам по порогу рассинхрона. Тело поворачивалось - но камера-на-голове поехала дугами вслед за вращающимся телом, и стало хуже, чем было. Откатил.
Вопрос тем, кто делал full-body FP: как вы решаете доворот тела за камерой? Особенно интересно в связке с Motion Matching: чем кормить систему, чтобы стоячий поворот давал переступание ногами, а не скольжение или вечное накопление рассинхрона? Расскажите про свои схемы - соберу решения в следующую запись.
Новый дом
Мигрировал в проект окружение Electric Dreams (44 гига, редактор по дороге дважды падал с OOM - если полезете, поднимите файл подкачки заранее) и переехал жить в их лесной уровень. Вайтбокс-небоскрёбы уже стоят между деревьями - деревья пока без коллизии, чисто примерка силуэта.
Дальше: коллизии окружения, расчистка леса под здания через PCG-исключения, дождь, и второй заход на поворот тела - уже с вашими советами, я надеюсь.
Первая запись дневника: [ссылка на пост #1]