Моделирование дорожного трафика и библиотека FollowMe

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

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

Логотип для своего проекта я ещё не придумал, но только посмотрите, как притягательны эти низкополигональные модельки

В той игре, которую я планирую разработать, дорожный трафик занимает чуть ли не центральную часть. По крайней мере, это будет один из самых важных аспектов во всём дизайне игрового мира. К тому же система с таким количеством сущностей (100 000 транспортных средств для моей задумки – не предел) сама по себе является достаточно сложным программным проектом, реализация которого может неплохо поднять уровень навыков да и вообще быть показателем того, насколько мои идеи реализуемы.

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

Follow Me library traffic jam
Не успели выехать на улицы, как тут же встали в виртуальные пробки. Реализм!

Надо сказать, что реализуемая мной идея далеко не нова – самые ранние публикации на тему компьютерного моделирования трафика, которые мне довелось изучить, датировались началом 80-х годов. С тех пор появилось множество наработок в этом направлении, но все их можно разделить на три большие подгруппы: макро, микро и гибридные. В макро, как следует из названия, мы опускаем индивидуальные детали каждого транспортного средства и пытаемся сформировать некий общий поток, как если бы наши магистрали были трубами, а потоки машин потоками воды. Я не шучу, многие макромодели используют в качестве основы законы гидродинамики. В противоположность им ставятся микромодели, где моделируется поведение отдельных сущностей в зависимости от дорожной ситуации, особенностей транспортного средства и характера водителя. Здесь основу составляют following-модели (модели следования, то есть большую часть времени мы ориентируемся на следующее впереди нас ТС). Здесь сразу напрашивается очевидный плюс этих систем: более точное моделирование с учётом индивидуальных особенностей. К сожалению, это требует и бОльших расчётов – для крупных сетей такие модели не всегда подходят (особенно для моделирования в реальном времени). Поэтому существуют гибридные модели, объединяющие два этих подхода. Ведь, по сути, большую часть времени машины движутся в общем потоке, который мало отличается от потока воды, а на перекрёстках мы просто переходим к индивидуальным моделям. Из минусов – сложность разработки таких систем. По крайней мере, с моим текущим уровнем математики мне пока что не удалось создать в голове чёткого понимания их работы.

Follow Me library with debug info
Отображение технической информации позволяет отследить детали, важные для создания и функционирования сетей

Как видно из названия моей библиотеки, я выбрал в качестве основы модель следования. В самом простом понимании эта модель рассчитывает ускорение транспортного средства в конкретный момент времени t. И всё. То есть мы берём наши сущности, рассчитываем для каждой ускорение в зависимости от окружающих условий. А, узнав ускорение, вычисляем скорость и положение в некий последующий момент времени t+Δt. И «перемещаем» глобальное время на эту позицию. Чтобы повторить всё то же самое снова.

И всё было бы просто, если бы весь мир стоял на одной единственной очень длинной дороге шириной в две полосы. Но ведь есть ещё перекрёстки, светофоры, дорожные знаки, многополосное движение, парковки, непредсказуемые пешеходы, велосипедисты и неопознанные летающие объекты. Они-то и вносят всю смуту в нашу стройную систему. И простая following-модель превращается в массивного динозавра, который должен учесть множество дополнительных факторов, прежде чем наше авто перепрыгнет в своё счастливое Δt-будущее.

Им ещё многому предстоит научиться. Но хотя бы не сталкиваются, уже хорошо!

На текущий момент я уже более-менее разобрался со скоростным режимом полос, приоритетами, перекрёстками, светофорами и стоп-линиями. А также добавил возможность формировать составные ТС (ведь трамваи и грузовики могут состоять из нескольких частей). На повестке дня – параллельные перестроения. Крепкий орешек, который затрагивает практически все аспекты моделирования. Многие части уже написанного кода, в которые оно обещало хорошо вписаться, на деле оказались неподготовленными, и подвергаются переработке. Причиной тому некоторые преждевременные оптимизации (никогда не начинайте оптимизацию прежде, чем у вас будет готов рабочий прототип – успеется!). А также наивная уверенность в том, что простые прикидки в уме позволят в будущем подружить существующий код с крупной партией новых возможностей. Но, в целом, всё не так уж печально. Ведь мои подопечные хоть и с неохотой, но всё же начинают перестраиваться в новые полосы, расталкивая конкурентов и устраивая опасные ситуации.

Сейчас рано говорить о дате релиза библиотеки, но она обязательно будет иметь модуль интеграции с движком Unity, доступный на Asset Store. Чтобы получилось многофункциональное решение для внедрения в любой игровой мир масштабной транспортной сети. Кому-то это позволит оживить статичное окружение, добавить очарования или даже написать свою собственную стратегию. Но ещё больше я надеюсь на то, что мой проект поможет в дизайне реальных транспортных систем и решении проблем городского трафика. Ведь, пусть он и реализован в игровой форме, весь его фундамент заложен на научной основе. Как и во многих других проектах индустрии. Так что никогда не стоит сбрасывать игры со счетов в вопросах реального мира.

Mazeraptor

Вы любили в детстве разгадывать лабиринты? Искать выход из сложных переплетений, напечатанных в журналах с головоломками? Может быть, вы помните легенду о нити Ариадны или игру с пространством в фильме «Начало»? У всех этих лабиринтов был один минус. После того, как путь найден, уже не составляло труда пройти по нему снова.

Поэтому разработчики уже давно озаботились вопросом того, чтобы создавать лабиринты «на лету» и использовать их в своих проектах. Только представьте, что перед вами каждый раз – совершенно новый мир, в котором проверенная схема уже не действует и нужно искать новый путь.

Для этих целей я написал собственную программную библиотеку Mazeraptor. По-русски это слово звучало бы как-то навроде «Лабиринторатопс». Знаю, выглядит ужасно, а произнесение вслух может разбудить каких-нибудь древних богов, поэтому оставлю его, как есть, в своём изначальном варианте.

Что же нужно для создания лабиринта? Нужна некая структура, которая будет описывать положение его «комнат» относительно друг друга. Это может быть просто прямоугольная сетка с клетками, как в тетради, где каждая клетка исполняет роль такой комнаты. А может быть и множество колец друг в друге, разделённых на ячейки. Здесь всё ограничено только вашей фантазией. Главное, чтобы вы смогли объяснить логику своей структуры на понятном языке.

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

Логотип приложения, созданный в самом приложении

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

Понимаю, в целом всё выгядит одинаково запутанно. Поэтому я добавил цветовую индикацию того, в каком порядке обрабатываются ячейки. От тёмных к светлым. Видите разницу? На картинке справа прослеживается характерная черта Prim – множество коротких тупиковых ответвлений. Можете вернуться к первым двум картинкам и взглянуть на ход работы алгоритма обратного прохода (его характерная особенность – длинные закрученные ходы).

Не составляет также труда для моей программы найти путь из ячейки А в ячейку Б. Причём начальную и конечную точку вы можете указать абсолютно любую. А для поиска использовать различные алгоритмы, в том числе и A Star. Надо сказать, что в среде компьютерных игр это, пожалуй, один из самых распространённых способов поиска пути. Играете ли вы в стратегии или шутеры, будьте уверены, где-то там под корпусом вашего ПК или консоли маленькие единицы и нули скачут под его управлением. Уже не удивлю вас, сказав, что придумано и множество других алгоритмов, решающих ту же задачу. Всем заинтересованным могу намекнуть, что смотреть стоит в сторону теории графов, о которой я вам как-нибудь обязательно расскажу.

Если же вы в целом интересуетесь темой создания лабиринтов, обратите внимание на книгу Jamis Buck «Mazes for Programmers», которая невероятно помогла мне в работе. На этом, пожалуй, достаточно слов. Оставляю ссылку на архив со своим генератором здесь. А также ссылку на github для тех, кому нужен функционал библиотеки. Играйтесь, ищите, создавайте и не забывайте делиться со мной своими впечатлениями.