Tesserfact, обновление 01_02

О процессе улучшения прототипа походовой 3d тактики на Godot, до новой версии.

Tesserfact, обновление 01_02

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

версия 01_02, процесс

Страница проекта (браузерная версия, билды для windows/linux):

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

Игровые модели

<i>Первый новый персонаж, Миранда, после всех предварительных перерисовок и правок</i><br />
Первый новый персонаж, Миранда, после всех предварительных перерисовок и правок

Модельки проходят примерно такой цикл разработки - сначала в Blender создаётся половинка персонажа, с зеркальным модификатором. Когда базовая форма более менее закончена - проводим по модели швы, отмечая грани, где будет разрез в текстуре. Выделяем все полигоны модели и жмём unwrap, чтобы получить развёртки. Далее размещаем развёртки оптимальным образом, увеличив какие-то важных части (лицо) и уменьшив малозначительные (внутренняя сторона рук, стопа). Не помешает сразу же проверить нормали.

Tesserfact, обновление 01_02

Теперь ставим силу света сцены на 1, размещаем свет, вешаем на персонажа diffuse материал (какого-нибудь цвета) и создаём в нём новую текстуру, не прикрепляя её к узлам шейдера. Отключаем из рендера все объекты кроме ламп и персонажа, нажимаем опцию запекания (bake), включив там просто diffuse или добавив что-то ещё, вроде AO (но под это и шейдер стоит усложнить). Получается первичная текстура, которую нужно сохранить и затем подключить её к diffuse, отрубив лампы. Сцену можно осветлить (поставив, например, 2) чтобы в режиме рендера получившаяся моделька выглядела поярче.

Tesserfact, обновление 01_02

Уже можно красить по модели в самом Блендере, добавляя деталей - как по сетке, так и по текстуре. Главное прокрашивать отдельно на текстуре области, немного за пределами островков развёртки - если красить только по модели, то цвет обрезается по границе и уже в игре или на рендере цвет участка текстуры будет смешиваться с непрокрашенной областью за пределами этого участка и порождать нежелательные линии на текстуре.

Далее, делаем копию персонажа и применяем модификатор зеркала, чтобы модель стала сплошной. Лучше убедится, что все вертексы в точках соприкосновения слились и спаять их вместе или воспользоваться функцией удаления дублей. На этом этапе можно добавить модели асимметрии и специфических элементов - браслет на одной руке, прядь волос с левой стороны, сумка на правом боку и так далее. Асимметричные элементы надо развернуть отдельно и расположить на той же текстуре.

Теперь создаём скелет (можно клонировать заранее заготовленный базовый) и привязываем его к модели. Для этого нужно сначала выделить модель (лучше перед этим сохранить её копию), лишь затем уже кости с зажатым Ctrl, затем зайти в меню Object и найти опцию Parent, где выбрать Bone, а затем with automatic weights.

Если подвигать различные кости в режиме pose, то становится видно, насколько хорошо кости привязались к модели. Если совсем плохо, то лучше расположить их по иному или изменить модель более правильным образом. Если есть лишь отдельные искажения, то правим их переключившись на модель и выбрав режим рисования весов - кликая по списку костей соотнесённых с моделью, видим область их влияния и добавляем или снижаем его.

<i>Тёмно-синий цвет - области на которые выделенная кость 011 не влияет. Красный, жёлтый, зелёный, светло-синий - места на которые она влияет с разной силой.</i><br />
Тёмно-синий цвет - области на которые выделенная кость 011 не влияет. Красный, жёлтый, зелёный, светло-синий - места на которые она влияет с разной силой.

Когда скелет нормально привязан стоит сохранить сцену в отдельный проект, оставив в ней только модель и кости. Теперь можно делать анимации. Конкретно для этих персонажей я задавал по 60 кадров на одну анимацию и сохранял разные анимации разными файлами. Количество кадров выбрано произвольное и просто как некий единый стандарт, для удобства анимирования. В любом случае в игровом движке можно будет ускорять/замедлять полученную анимацию отдельно. Ещё один момент - для получившейся зацикленной анимации скорее всего стоит выделить её всю и перевести в линейный режим, чтобы анимационная петля лучше стыковалась (но тут зависит от вида зацикленного действия, для той же ходьбы это не так принципиально, для равномерного вращения вокруг оси - важно).

<i>Переключаем тип интерполяции в линейный, чтобы не было затуханий по краям (дефолтный вариант).</i><br />
Переключаем тип интерполяции в линейный, чтобы не было затуханий по краям (дефолтный вариант).

Для переноса в Godot подойдёт формат collada (.dae). Для того, чтобы сделать это, нужно убедиться, что в сцене присутствуют только модель и кости (без прочего мусора), а также удалить материал с модели (так как в движке будем накладывать его отдельно). И затем экспортировать в виде .dae файла.

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

<i>В о вкладке Import, в пункте Storage для файла .dae по умолчанию стоит Built-in. Нужно менять это на Files (.anim) и жать кнопку Reimport. Кстати, там есть ещё один пункт с названием Storage, где находятся другие опции - не стоит путать.</i><br />
В о вкладке Import, в пункте Storage для файла .dae по умолчанию стоит Built-in. Нужно менять это на Files (.anim) и жать кнопку Reimport. Кстати, там есть ещё один пункт с названием Storage, где находятся другие опции - не стоит путать.

Затем я беру файл с анимацией походки персонажа, как его главный файл. Сохраняю отдельной сценой (.tscn), и сохраняю её default анимацию тоже отдельным .anim файлом.

Если потом нужно добавить новые анимации этому персонажу, то закидываем файл с новой анимацией (для того же скелета) в движок, делаем реимпорт с включением .anim, открываем и сохраняем её default анимацию с новым именем, после чего закрываем открытый .dae без сохранения (теперь его можно удалить, в отличие от того, основного, .dae, от которого сохранена .tscn). Затем открываем главную сцену персонажа, и в её анимациях через пункт load загружаем тот новый сохранённый .anim. Теперь через код можно будет менять - какую анимацию персонаж должен проигрывать.

Персонаж, с несколькими загруженными анимациями. Default-анимация при этом всегда будет пересоздаваться в этой сцене сама, по новой, даже если её переименовать или удалить - к ней лучше не обращаться.<br />
Персонаж, с несколькими загруженными анимациями. Default-анимация при этом всегда будет пересоздаваться в этой сцене сама, по новой, даже если её переименовать или удалить - к ней лучше не обращаться.

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

<i>С шейдингом</i><br />
С шейдингом
<i>Уже без шейдинга, как останется дальше</i><br />
Уже без шейдинга, как останется дальше

Кроме того в движке можно сделать некий простой аналог эффекта cellsading (обводка) для ещё более "нарисованного" вида, добавив основному материалу второй проход, где тёмный материал применяется на чуть более увеличенную сетку объекта и отрисовывается позади текстурированной модели. Так вобщем и оставил.

Ромео, следующий персонаж. 3D-адаптация героя из более раннего flash прототипа.<br />
Ромео, следующий персонаж. 3D-адаптация героя из более раннего flash прототипа.
Вот как он выглядел в 2д.<br />
Вот как он выглядел в 2д.
<i>Собственно, это был полноценный герой "Монстробоя" из мира Мглы. На фото часть его открытки с параметрами.</i><br />
Собственно, это был полноценный герой "Монстробоя" из мира Мглы. На фото часть его открытки с параметрами.

AI

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

Далее была спланирована простая схема базовая действий для AI, некий набор его шагов и приоритетов: старается продвинуться к уязвимому персонажу - если такой далеко, то старается ударить кого-то поблизости - затем передаёт ход. Уязвимая цель со временем может меняться, а если такой не обнаружено, то враг вместо этого недалеко смещается и пробует ударить вблизи.

Закодировано всё таким образом, что враг просто бросает область проверки на точку уязвимого персонажа и смещается ближе к ней, если область пересекается с клетками в его зоне движения. Если же враг атакует, то бросает область проверки уже на себя и если та задевает клетку в радиусе атаки, на которой есть живой противник, то враг совершает удар в ту сторону.

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

<i>Сверху слева виден лист, фиксирующий попавшие в пересечение объекты. Сверху на некоторых клетках чёрные, смотрящие вниз призмы - так отмечались клетки, попавшие в область.</i><br />
Сверху слева виден лист, фиксирующий попавшие в пересечение объекты. Сверху на некоторых клетках чёрные, смотрящие вниз призмы - так отмечались клетки, попавшие в область.

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

Цифры урона

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

<i>самодельный атлас с цифрами</i><br />
самодельный атлас с цифрами

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

Был ещё вариант выводить цифры в 2д, цепляя к позиции мыши, или показывать их на квад через вьюпорт, но это всё немного более сложные и шаткие схемы (пробовал их уже в иных проектах).

В итоге, теперь урон показан всплывающими цифрами и принцип нанесения урона немного изменился. Теперь здесь действуют принципы системы "Монстробой" - атака оружием имеет 4 позиции с разным количеством урона, и во время атаки бросается кубик, выбирая одну их них. То есть белые сейчас атакуют словно одним, чуть более слабым оружием, а чёрные оружием с уроном посильнее.

Прочие особенности

В настольно-ролевой системе "Монстробой" у меня действовало такое правило, что после атаки (магии или иного атакущего действия) персонаж терял возможность передвигаться. В принципе, я хочу сохранить это и здесь, но на данный момент после атак двигаться можно.

Зачем это было в настолке? Во-первых, для ускорения сражений (на что у меня там был направлен целый комплекс решений), меньшего их затягивания и большей плотности происходящего. В компьютерных играх это тоже актуально - часто бывает, что тот же противник двигается всегда при любом удобном моменте, и до и после действий, даже когда особо нет нужды и постоянно разбегается в стороны. Что утомляет, заставляет бегать за огрызающимися недобитками через пол-карты и так далее.

Во-вторых, психология. За столом очень легко забыть, кто ходил, кто не ходил, поэтому окончание движения после проведения приёма даёт некоторую пользу и играющие меньше путаются.

В-третьих, там была ещё и механика Очков Действия. Которые расходуются как на движение, так и на действия не совсем боевого характера - вроде использования предметов (хотя, наносящие урон предметы-гранаты метать тоже можно, пока они есть). Плюс неизрасходованные ОД можно запасать (если владеешь такой способностью) и тратить позднее, уже на отдельные боевые приёмы.

Так вот, Очки Действия позволяли часто совершить ещё как минимум одно, третье действие в ход, пожертвовав дальностью передвижения, но как до, так и после атак. Например, герой, имеющий 3 ОД на ход, мог сходить не на все 3, а на 1 клетку (потратив первый ОД), ударить противника и выпить лечебное зелье, потратив 2 оставшихся ОД.

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

Таким образом непотраченные ОД сохраняются после атак до конца хода, просто далее их уже нельзя тратить конкретно на обычное движение.

Куда-то в эту сторону и хочется двигаться.

99
10 комментариев

Бро, смотрел у тебя видосики, глянь может надо таких эффектиков? Понимаю, что кринжовенько смотрятся, но это в начале пути делал, храню проект как память. По работе мне не пригодятся, переделал уже, а так вдруг как заглушки сгодятся, чтобы не просто сферы падали сверху. Но не понял до конца, какая у тебя версия в работе, эти для 4.1.

1

Да нормально смотрятся. Сделать эффекты не такая уж проблема, просто это надо капитально в них закапываться, даже для ненавороченных, и получается, что эффекты есть, а логика и структуры не сделаны. Поэтому я стараюсь не отвлекаться от основы на мелочи, хотя и не всегда получается.
У меня версия 3.5 с gles2 для большинства проектов, так как это запустится практически везде, в отличие от 4-ки. Но если дело не в особых шейдерах и специфических опциях 4-ки, то это воспроизводимо в 3-ке тоже.
Вобще, ты бы просто написал статью о том, как устроены твои эффекты, чтобы было понятно как повторить или сделать что-то наподобие. Даже если там простой анимированный спрайтшит на каждую часть эффекта, то может упомянуть какие-то программы в котором их удобнее рисовать, например. То есть показать кухню.

1

Почему такой старой версией блендера пользуетесь?
Теперь можно делать анимации. Конкретно для этих персонажей я задавал по 60 кадров на одну анимацию и сохранял разные анимации разными файлами. Количество кадров выбрано произвольное и просто как некий единый стандарт, для удобства анимирования.В 60 FPS нет смысла анимировать, движки всё равно интерполируют под текущий фреймрейт. 30 кадров хватит за глаза.
для получившейся зацикленной анимации скорее всего стоит выделить её всю и перевести в линейный режим, чтобы анимационная петля лучше стыковалась (но тут зависит от вида зацикленного действия, для той же ходьбы это не так принципиально, для равномерного вращения вокруг оси - важно)Нет, нужно в graph editor'е нажать Shift + E -> Make Cyclic, затем скопировать нулевой кадр на место последнего. Тогда анимация будет бесшовной. Интерполяцию ставьте на bezier - auto clamped, потому что линейная, грубо говоря, превращает персонажа в робота.

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

а чего экспорт в формат такой странный? В доках Годо рекомендуют использовать GLTF, как наиболее совместимый и беспроблемный для годо.

В 4+ .gltf стал необходим для передачи костных анимаций. В 3+ нормально работал и .dae, что мне, допустим, удобнее (так как конкретно этот проект делается на Годо 3+).