WebGL Demo: https://oleg-avdeev.itch.io/traffic-light-controller Пароль: traffic-light
Написать контроллер, какого угодно вида, управляющий светофором. Светофор, это дорожный регулировщик с лампочками, работающий на любых дорогах, например, железных или автомобильных и, для регулировки движения, использующий только световую сигнализацию (без подвижных, например, частей). Можно считать, что контроллер работает с ограничениями: например, поддерживает максимальное число сигналов, равное пяти.
Прежде чем перейти к определению проблем и методов решений необходимо уточнить задачу, для этого надо понять, кем, для чего и в каких обстоятельствах этот светофор будет использован.
- Декоративный светофор — подойдёт как компонент для игры с городским пейзажем, но без необходимости перемещаться по дорогам и исследовать город. Такой светофор может полностью содержать в себе логику переключения сигналов и быть крайне простым в настройке;
- Светофор без логики — подойдёт для игры, где светофором управляет сторонний контроллер, сообщая какой сигнал должен загореться. Такой светофор может быть использован в гоночной игре на старте, чтобы синхронизировать его с обратным отсчётом;
- Программируемый светофор — на основе того, как работают простые светфоры в реальном мире — у светофора есть цикл сигналов, который настраивается при установке. В реальном мире есть множество нюансов и способов добавить обратную связь, но для игры, вроде Mafia или GTA такое решение может быть достаточным.
Я остановился на варианте 3, как на наиболее интересном для реализации. Предполагаю, что светофор будет использован в игре с открытым миром и перемещением по дорогам. Светофор размещается левел-дизайнером на карте игры, и должен быть удобен в настройке
- Абстрагировать контроллер от конкретных типов сигналов и конфигурации светофора;
- Возможность просто добавить или удалить новые типы сигналов;
- Корректная работа при включении/отключении компонента, восстановление состояния;
- Возможность использовать разные 3д и 2д ассеты для светофора.
Для того, чтобы контроллер мог поддерживать любой сигнал и любую конфигурацию, класс контроллера содержит список компонентов "лампочек" светофора, для каждой из которых настроен сигнал, который её включает. Очередь самих сигналов хранится в отдельной сущности Cycle, на которую есть ссылка у контроллера. При истечении длительности последнего сигнала, контроллер запрашивает следующий сигнал, и передаёт его каждой лампочке.
Таким образом нет привязки к конкретным типам сигналов — их список может быть изменён, дополнен или неиспользуемый сигнал может быть удалён. Выставление самих сигналов происходит в компоненте Cycle для каждого светофора. Пользуясь встроенными функциями редактора юнити, у дизайнера есть возможность выбрать сигнал из выпадающего списка, или скопировать настройки цикла и применить их для другого светофора.
Помимо типов сигналов, Cycle хранит длительность каждого из них. Эти два значения объединяются в структуру Step. На основании длительности полного цикла и каждого этапа контроллер может однозначно определить своё состояние в любой момент времени, что позволяет включать и выключать объект по необходимости, например, чтобы уменьшить количество объектов на сцене для быстроты отрисовки.
Список "лампочек" TrafficSignal настраивается для каждого контроллера. В этом проекте каждая лампочка — это один и тот же префаб, но TrafficSignal может быть добавлен как компонент на любую модель, главным условием является использование материала с шейдером Unlit/Signal для меша лампочки.
Для оптимизации Unlit/Signal поддерживает GPU Instancing — все объекты с одинаковым мешем и этим материалом будут отрисованы за один draw call. Если возможности использовать только один меш нет, решение может быть заменено на использование MaterialPropertyBlock. В примере три цветные лампочки настроены так, чтобы использовать GPU Instancing, лампочки с текстурами стрелки и велосипеда используют отдельные материалы, однако их тоже можно оптимизировать, объединив текстуры в атлас.
- Возможность использования любого ассета как компонета светофора;
- Контроллер поддерживает любую конфигурацию и любые сигналы;
- При необходимости, структура Step может содержать массив сигналов, чтобы каждый этап включал несколько сигналов светофоров;
- При необходимости, класс Cycle может быть перегружен, чтобы поддерживать более сложную логику переключения сигналов. Например, возвращать только жёлтый сигнал в ночное игровое время;
- Реализация использует минимальное количество материалов — цвет сигнала настраивается в компоненте TrafficSignal, и передаётся в шейдер при помощи PropertyBlock.
Для тестирования контроллера используется UI, расположенный в правой части экрана. С его помощью можно изменить или создать новую программу для светофора, задав все сигналы и их длительности:
- Кнопка "Add Step" — Добавляет новый этап цикла светофора
- Компонеты Step
- Выпадающий список — выбрать тип сигнала из enum Signal
- Поле ввода — указать длительность сигнала
- Кнопка "Delete" — удалить данный этап из цикла
- Кнопка "Commit Steps" — применяет новый список сигналов и перезагружает контроллер светофора.