Как создать динамическое освещение для 2D-игры

Подробный туториал для Unity.

Инди-разработчик из студии Half Human Games Перси Лежандр опубликовал на Gamasutra текст, в котором рассказал о процессе создания динамической системы освещения для своей игры Dwerve. Он подробно описал каждый шаг, а мы выбрали главное.

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

Основной инструмент для реализации освещения — ассет Smart Lighting 2D. Лежандр подробно расписал все необходимые действия для использования этого ассета в игровых проектах.

Как создать динамическое освещение для 2D-игры

Создайте новый проект Unity с помощью шаблона 2D-игры и импортируйте туда Smart Lighting 2D. Создайте новую сцену и добавьте Tilemap, щёлкнув правой кнопкой мыши по окну Hierarchy и выбрав 2D Object — Tilemap. Далее вам понадобится тайлсет для создания подземелья — вы можете собрать его сами или взять сторонний (на itch.io есть множество бесплатных наборов тайлов).

В этом примере автор использовал Pita's Dungeon Tileset, на основе которого разработчики собирали прототип Dwerve
Повторите настройки импорта спрайтов 
Повторите настройки импорта спрайтов 

Затем откройте редактор спрайтов и установите размер сетки 16х16 ячеек. Многие спрайты разделены на несколько фрагментов — вам нужно объединить их в один. Убедитесь, что длина и ширина кратны 16. На рисунке ниже красным контуром показаны сгенерированные спрайты, а синим — то, как они должны выглядеть.

Красным обведён сгенерированный спрайт, разделённый на два фрагмента. Этот вариант не подходит. Спрайт, обведённый синим, — правильный пример
Красным обведён сгенерированный спрайт, разделённый на два фрагмента. Этот вариант не подходит. Спрайт, обведённый синим, — правильный пример
В настройках спрайта выберите Pivot — «Custom», Pivot Unit Mode — «Pixels», Custom Pivot — «8, 8». Это гарантирует, что спрайт будет правильно выровнен по сетке 
В настройках спрайта выберите Pivot — «Custom», Pivot Unit Mode — «Pixels», Custom Pivot — «8, 8». Это гарантирует, что спрайт будет правильно выровнен по сетке 

Далее вам нужно сгенерировать тайлы из окна Tile Palette. Откройте окно на верхней панели инструментов, выбрав пункт Window — 2D — Tile. Затем создайте новый Tile Palette под названием Dungeon Palette и сохраните его в новой папке Assets — Palettes.

Как создать динамическое освещение для 2D-игры

Чтобы автоматически создать тайлы из спрайтов, просто перетащите их из Assets в окно Tile Palette. Когда появится окно Select Folder, создайте новую папку Assets — Tiles и сгенерируйте тайлы в эту папку.

Как создать динамическое освещение для 2D-игры

Теперь окно Tile Palette должно выглядеть следующим образом:

Как создать динамическое освещение для 2D-игры

Продублируйте свой Tilemap в окне Hierarchy. Переименуйте оригинал в Ground Tilemap, а копию — в Obstacle Tilemap. У Obstacle Tilemap установите параметр Order in Layer равным 10, чтобы этот тайлмап рендерился поверх Ground Tilemap.

Теперь нужно разукрасить тайлмап. Убедитесь, что пол и землю вы разукрашиваете на Ground Tilemap, а стены, колонны и пропсы на Obstacle Tilemap. Факелы нужно будет добавить позже.

На изображении ниже в правом нижнем углу стена рендерится поверх мебели. Такую проблему можно исправить в настройках проекта. Откройте окно Project Settings на верхней панели инструментов, выбрав Edit — Project Settings — Graphics. В разделе Camera Settings установите Transparency Sort Mode на Custom Axis, а Transparent Sort Axis на (0, 1, 0). Это должно исправить проблему.

Неправильный вариант
Неправильный вариант
Исправленный вариант
Исправленный вариант

Затем нужно добавить Tilemap Collider 2D к Obstacle Tilemap и поставить галочку на Used by Composite. После этого добавьте Composite Collider 2D, с которым автоматически идёт компонент Rigidbody 2D — у него нужно изменить Body Type на «Static». Выберите Obstacle Tilemap — ваш коллайдер должен выглядеть примерно так:

Как создать динамическое освещение для 2D-игры

Вы можете заметить проблему с этим коллайдером. Он должен находиться только у основания объектов, а не охватывать спрайты полностью. Откройте окно Sprite Editor в Texture Import Settings и отредактируйте фигуры спрайтов, выбрав Sprite Editor — Custom Physics Shape.

Сделайте фигуры похожими на этот пример
Сделайте фигуры похожими на этот пример

Выберите Obstacle Tilemap в Hierarchy. Если коллайдеры не обновились автоматически, отключите и снова включите компонент Tilemap Collider 2D. Теперь коллайдеры должны выглядеть так.

Как создать динамическое освещение для 2D-игры

Далее нужно добавить тайлы факелов. Выберите объект Grid и создайте новый тайлмап — щёлкните правой кнопкой мыши и выберите 2D Object — Tilemap. Переименуйте этот тайлмап в Torch Tilemap и установите показатель Order in Layer на 20.

Факелы должны двигаться: Unity 2D Extras включает AnimatedTile.cs, поэтому тайлы можно легко анимировать. Можно просто скачать этот скрипт и поместить его в Assets — Scripts. В окне проекта нажмите правой кнопкой мыши и выберите Create — 2D — Tiles — Animated Tile. Это позволит вам анимировать спрайт. Переименуйте его в Pillar Torch Tile и выберите его.

В Inspector нажмите на значок замка, чтобы заблокировать его
В Inspector нажмите на значок замка, чтобы заблокировать его

Перетащите спрайты факела в контейнер. Установите минимальную и максимальную скорость на 10. Разблокируйте Inspector. Повторите эти шаги, чтобы создать тайлы настенного факела. Теперь перетащите тайлы факела в окно Tile Palette.

Используйте новые тайлы факелов, а не старые сгенерированные
Используйте новые тайлы факелов, а не старые сгенерированные

Теперь нарисуйте пару факелов на Torch Tilemap. Левый факел в синем круге предназначен для колонн, а правый — для стен. Когда вы закончите, войдите в Play Mode, чтобы увидеть анимированные факелы.

Теперь можно приступить к созданию освещения. Создайте Lighting Manager 2D: щёлкните правой кнопкой мыши на Hierarchy и выберите 2D Light — Light Manager. Таким же образом добавьте Light Source и переименуйте объект в Torch Light. Перетащите его в Assets — Prefabs, чтобы создать префаб. Теперь дублируйте свет факела и перетащите его на каждый факел. Поместите его на землю прямо перед колонной или стеной, чтобы сам источник света не находился внутри какого-либо препятствия.

Как создать динамическое освещение для 2D-игры

Войдите в Play Mode, чтобы проверить освещение.

Локация должна выглядеть примерно так
Локация должна выглядеть примерно так

Пока препятствия не блокируют свет. Чтобы исправить это, добавьте компонент Lighting Tilemap Collider 2D к объекту Obstacle Tilemap.

Теперь препятствия блокируют свет
Теперь препятствия блокируют свет

Получилось не совсем то, что нужно: тени формируются самими тайлами, а не физической формой препятствий. Чтобы исправить это, нужно поставить Collision Type на «Sprite Custom Physics Shape».

Результат должен выглядеть примерно так
Результат должен выглядеть примерно так

Тени получились слишком тёмными. Чтобы исправить это, нужно сделать их более прозрачными. Откройте окно Lighting 2D — Preferences и установите Shadow Darkness на 0,85. Также можно сделать оттенок более тёплым. Откройте Torch Light префаб и выберите светлый коричнево-рыжий цвет (автор использовал #FFAF64 ). Поставьте параметр Size на 3.

Как создать динамическое освещение для 2D-игры

Далее факелам можно добавить свечение и частицы. Откройте префаб Torch Light и сделайте пустой объект корневым, а затем переместите компонент Lighting Source 2D в дочерний объект Light Source. Добавьте ещё два объекта Light Glow и Ember Particles.

Как создать динамическое освещение для 2D-игры

Источник света расположен на земле, а свечение и частицы должны быть над факелом. Установить положение Light Glow и Ember Particles на (0, 0,5, 0). Затем добавьте компонент SpriteRenderer к игровому объекту Light Glow и выберите светло-жёлтый цвет (например, CD7319 ). Также установите Order in Layer на 20, чтобы он отображался поверх любых препятствий.

Затем добавьте такую текстуру
Затем добавьте такую текстуру

Создайте новый материал под названием Additive Particle Material в Assets — Materials и установите для шейдера значение Legacy Shader — Particles — Additive. Поставьте Material, чтобы использовать его в качестве материала. Чтобы он начал мерцать, скачайте SpriteAlphaFlicker.cs и переместите его в Assets — Scripts. Затем добавьте его к объекту Light Glow.

Как создать динамическое освещение для 2D-игры

Чтобы сделать частицы, добавьте Particle System к объекту Ember Particles. Автор использовал следующие настройки:

Как создать динамическое освещение для 2D-игры
Как создать динамическое освещение для 2D-игры
Как создать динамическое освещение для 2D-игры
Результат должен выглядеть примерно так
Результат должен выглядеть примерно так

Чтобы затемнить края экрана, можно добавить виньетку. Откройте окно Package Manager — Post Processing — Install. Создайте новый слой Post Processing. Затем добавьте компонент Post Process Layer к объекту Main Camera. Далее поставьте Layer на «Post Processing».

Создайте объект Post Process Volume и также поставьте Layer на «Post Processing». Добавьте к нему компонент Post Process Volume и установите галочку на «Is Global». Создайте новый профиль. Нажмите кнопку Add effect — Unity — Vignette.

Вот настройки, которые использовал автор
Вот настройки, которые использовал автор
Также он увеличил яркость и контрастность
Также он увеличил яркость и контрастность
Финальный результат

Чтобы проверить динамическое освещение, можно добавить скрипт FollowMouse.cs и добавить его в Assets — Scripts. Продублируйте один из факелов, переименуйте его в Mouse Torch и добавьте компонент Follow Mouse. Отключите свечение и частицы.

Пример системы динамического освещения
189189
14 комментариев

О, это же одна из статей, у которых закладок больше чем рейтинга. Спасибо за перевод.

14

Комментарий недоступен

2

Комментарий недоступен

3

Отлично, вы показали дефолтный пример. А есть что-то, с чем пытались работать лично вы?
Я почему-то уверен, что это можно сделать и без сторонних ассетов, или найти бесплатный, который также позволит всё настроить. Вас никто не заставляет использовать то или иное решение.

Godot хорош, я сам на нём сейчас делаю проект, однако, есть тут свои проблемы, с которыми сейчас приходится бороться.
Вот пример. В то время, когда у Unity есть Cinemachine с кучей настроек из коробки, мне для игры необходимо писать свою систему слежения за игроком с опережением, и чтобы это всё работало плавно. И вот нюанс. Камера дергается даже при равномерном перемещении игрока, и дело тут даже не в опережении или чем-то таком.
Выяснил, что можно камеру заставить обновлять свою позицию в Fixed Process (игрок - физический объект, и также перемещается через Fixed), и вроде бы дерганье исчезло. Но внезапно по какой-то причине встроенное сглаживание перестало работать, как только сцена грузится из сохранённого файла, все перемещения становятся резкими.
К слову, в итоге, от встроенного метода сохранения сцены в файл пришлось отказаться в пользу самописных сохранений, ибо это вызывало у всех созданных файлов _ready метод, который, по сути, должен срабатывать только когда сцена загружена и объект готов к работе. И в целом, логично, что после загрузки сцены из файла все объекты опять вызывают _ready, ибо это по-новой загруженная из файла сцена. Но всё-таки в итоге после загрузки всё ломалось, объекты, находившиеся в середине чего-то останавливались, анимации также не возобновлялись, и всё это заставляет писать костыли.


Я прекрасно понимаю, что часть из проблем вызвана, собственно, моим кодом, и я не говорю, что Godot забагован или что-то вроде этого. Просто когда есть встроенные средства, которые вроде бы работают, но требуют костылей, это не особо круто. В любом случае, движок активно развивается и при этом остаётся свободным и открытым, и это как раз очень круто. Жду 4 версию, но при этом планирую следующий проект написать на Unity, чтобы в итоге иметь полное понимание картины.

3

Это больше похоже на 3д освещение, которое в юнити тоже есть из коробки.

2