EN
Heiser Saint
Heiser Saint
22 subscriber

Heavy Memories - работаем с темнотой.

Года три назад я впервые делал динамическое освещение в одном из конкурсных проектов. После конкурса я упоролся в шейдеры - уж больно хотелось достичь определённых эффектов.
В частности - так чтобы в темноте показывались опасности (хаззарды, противники). Так игрок будет ПРИМЕРНО знать что его ждёт в неизвестности и быть чуточку подготовленным, что улучшает игровой экспириенс, то есть UX.
Я решил, что если я в Heavy Memories прикручиваю динамическое освещение, то нужно сделать что-то подобное. Есть несколько вещей, которые АРХИВАЖНО чтоб были подсвечены: разбитые шасси с бонусами, сами бонусы, противники. С противниками всё не так однозначно. Если их сходу подсвечивать, то нет той самой интриги темноты. Поэтому для некоторых объектов я решил сделать триггер подсветки в радиусе. И для бочек пока что. Причём подсветка может возникнуть при попадании. Это прям супер круто. Выстрелил наугад, попал в противника и можешь его отслеживать и стрелять точно в его сторону в темноту. Только после того как я этот функционал сделал, я понял что его очень сильно не хватало в оригинальной Heavy Memories.
Так же этот функционал решает часть UX проблем. Например, с бочками, которые часто можно взорвать, разрушив что-то для продвижения дальше. Только раньше это было неочевидно, а теперь когда в темноте видишь цель, а рядом огоньки - паззл более менее складывается и уже примерно знаешь что делать.
Как это реализовано? Программисты, добро пожаловать! Игроки тоже могут остаться, но далее много технической части.
Сама по себе система освещения реализована довольно просто. Есть готовый набор скриптов, сердцем которого является рассчёт световых лучей. Чтоб подключить: инициализация с настройками, прописать вызов функций в апдейт и в отрисовку. Далее нужно назначить кастеры, через который не будет проходить свет. И источники света. Тут нужно чётко продумать всё, т.к. Сложность алгоритма рассчётов - это произведение количества кастеров, на количество светильников. Да, считается каждый с каждым. Когда стены представляют собой большие блоки и сплошные (как в первом проекте на видео) - проблем особо нет. Но в танчиках реально стен много, т.к. они разрушаются кусочками 16*16 пикселей. Поэтому в целях оптимизации я использую только один светильник - свет от игрока. Иначе на уровнях больше одного экрана тормозит даже несмотря на то, что я залез в код и оптимизировал это всё.
Технически как итог всего этого дела я получаю сурфейс(кусок видеопамяти с текстурой) с освещённостью. Чёрный - нет света, белый - есть. Его можно отрисовать в нужном режиме смешивания, чтобы получить картинку с освещением.
Но есть проблема. Кастеры сами не освещаются, т.к. не пропускают свет. Значит их нужно освещать руками. Но как? Самое простое - дорисовать на текстуру со светом там где стены - белые прямоугольники. 
Подумав, отрисовать их в нужном радиусе от игрока. Ещё подумав - рисовать их с прозрачностью в зависимости от расстояния до игрока.
Нуууу, чёт не очень. В сочетании с динамическим освещением выглядит как халтура. Хочется более плавные границы света, а не эти квадраты. Но для начала нужно решить другую проблему - игрок видит те стены, которые за другой стеной и в темноте. Будет лучше, если игрок будет видеть только те, стеные, которые попадают в рэйкаст. Я сделал базовую проверку чтоб между центром стены и игроком не было других стен. 
Получается эффект, что как только игрок подъезжает ближе к стене, рэйкаст от соседей начинает проходить через эту стену и игрок видит меньше. В целом, это даже прикольно, но уж шибко некультяписто выглядит.
Надо сделать чтоб игрок мог смотреть немного в толщу стены, т.е. Затухающий рэйкаст. Сделать несложно - считаем освещённость стены в зависимости от того, сколько между игроком и стеной других стен. Чтобы не выглядело как баг, эту альфу меняем не сразу, а интерполируем со временем.
Получше, но теперь бесят квадратики. Чтобы сделать более плавные переходы, нужно посчитать расстояния до углов стены с учётом освещённости самой стены. Затруднение - я не могу всё это считать для каждой стены индивидуально, т.к. смежные стены имеют разную освещённость, и какую брать?
Ладно, я сделаю 2Д массив, со всеми углами, и для каждого угла посчитаю свою освещённость, которая равна среднему всех освещёностей стен, частью которых этот угол является. То есть 4 стен. Если там нет стен, считаем освещённость нулевой.
При таком подходе есть риск, что освещённость стен, которые напрямую видит игрок будет провалена. Как итог - кривой рассчёт освещения, который я даже принял за баг отрисовки 2Д примитивов.
Поэтому нужно предварительно пометить пустое место в радиусе источника света как освещённое. Я даже степень освещённости не считал. Если между клеткой и источником света нет стены - значит там светло.
Теперь остаётся отрисовать градиенты для каждой стены по заданным значениям освещённостей в углах. В итоге получаем доработанный сурфейс, на котором не только динамическое освещение, но и освещение стен. Вышло вполне удобоваримо.
А дальше статичные источники света, которые просто освещают вокруг и не зависят ни от чего. Их просто рисуем поверх с режимом смешивания add всё в тот же сурфейс.
Это полное освещение. Теперь нужно нарисовать значки противников и бочек в неосвещённых участках. Тут всё просто - это инверсия освещённости. То есть нужно отрисовать значки в тех местах, где нет освещённости на сурфейсе с освещением. Завожу ещё один сурфейс, на котором рисую все нужные UI элементы. И теперь мне нужно отрисовать этот сурфейс с альфой, которая - инверсия сурфейса с освещением.
В Game Maker Studio нету(почти!) готового функционала отрисовки чего бы то ни было с альфа каналом. Так что я сделал это через шейдер, в который дополнительно подаётся текстура с альфой. Инверсию, я зашиваю прям в этот шейдер. Вот он, если кому будет интересно:
На 15-ой строчке я сделал порог для отображения значков, т.е. значки будут отображаться только в абсолютной темноте. Иначе они с альфой накладываются на объекты и получается каша. Позже я понизил это значение до 0.8, т.е. когда объект плохо различим в темноте.
Получаем весьма приличный результат. Можно двигаться дальше, в сторону улучшения геймплея и левелдизайна.
Ах да, если вдруг кто из читателей использует Game Maker Studio 2 и хочет прикрутить подобную систему освещения, в качестве бонуса выкладываются локальный пакет:
light-system.yymps47.35 KbDownload
Это даже бонус в бонусе, т.к. кроме освещения там же скрипты для менеджера сурфейсов.

Subscription levels

No subscription levels
Go up