Как Pizza Tycoon имитировала дорожный трафик на процессоре с частотой 25 МГц

Предыстория
Я занимаюсь Pizza Legacy — open-source ремейком классической игры 1994 года Pizza Tycoon для DOS. Одной из ключевых особенностей был вид на город с активным трафиком: два-три десятка спрайтов машин, которые перемещались по дорогам, формировали заторы на светофорах и создавали иллюзию оживленного мегаполиса. Несмотря на мелкие огрехи симуляции, вроде «просачивания» машин друг сквозь друга, это выглядело крайне убедительно — и всё это работало на процессорах Intel 386 с тактовой частотой 25 МГц.
Разработка проекта стартовала в 2010 году. Я начал именно с этой системы, но на то, чтобы заставить машины двигаться «как надо», у меня ушло 14 лет. Множество попыток заканчивались крахом из-за чрезмерной усложненности архитектуры.
В 2017 году я внедрил систему, где каждый тайл отслеживал занятость, а автомобиль запрашивал «разрешение» на въезд, резервируя слот. Это превратилось в избыточную систему блокировок ради перемещения пары пикселей. Машины постоянно боролись за синхронизацию с тайлами.
Меня не покидал вопрос: если оригинал 90-х годов справлялся с этим на 25 МГц, почему мой код выходит таким перегруженным?
В итоге я решился на глубокое погружение в ассемблерный код оригинала. На помощь пришли LLM, которые отлично справились с анализом низкоуровневых инструкций. Разгадка оказалась проста: я подходил к задаче с багажом современных знаний — графами сцен, поиском путей и проверкой коллизий, предполагая, что мне нужны мощные вычислительные ресурсы.
Устройство городов
Взглянем на структуру игрового мира:

Города состоят из сетки 160 на 120 тайлов. Все элементы ландшафта берутся из файла landsym.vga:

0x54 соответствует конкретному сегменту крыши.Дорожная сеть
Главный инсайт: машинам не нужно знать пункт назначения. Направление движения «зашито» в сам тип тайла. Например, тайл дороги 0x16 жестко задает движение слева направо. Другие ID определяют движение в обратном направлении или по вертикали.
Город по факту представляет собой сеть дорог с односторонним движением. Машине достаточно определить, на каком тайле она находится, чтобы понять, куда двигаться дальше. На поворотах (например, CORNER_SW) логика проста: бросается жребий, и с вероятностью 50% автомобиль либо продолжает движение, либо поворачивает. Чтобы избежать неестественного поведения, введено ограничение: два поворота налево подряд запрещены.

Перемещение и логика тайлов
Машины перемещаются с шагом в один пиксель на кадр. В дополнение к координатам есть внутренний счетчик (от 16 до 0), отвечающий за логику перекрестков. Как только счетчик достигает нуля, машина определяет новый тайл и направление. Поскольку каждый тайл занимает 16 пикселей, «тяжелая» логика выполняется в 16 раз реже, чем базовое смещение по оси X или Y. Начальные значения счетчика рандомизируются при создании авто, чтобы избежать «пакетного» обновления всех спрайтов одновременно.
Оптимизация коллизий
Вместо сложного поиска путей используется примитивная проверка пар. Для каждой машины проверяется список остальных: если путь прегражден — машина ждет 10 циклов. Ключ к эффективности — «быстрый выход»: если машины движутся в разных направлениях на разных полосах (например, восток и запад), проверка прерывается моментально, еще до вычислений координат. Благодаря этому даже при наличии 25 машин ресурсоемкие вычисления почти не требуются.
Жизненный цикл машин
Игра сканирует дорожные тайлы и с определенной вероятностью «спавнит» транспорт. Машины, покинувшие границы экрана, перерождаются в новых точках (другого цвета, с другим направлением), что избавляет от необходимости глобального менеджмента объектов. Это простое циклическое обновление позволяет поддерживать жизнь на карте без нагрузки на CPU.
Итог
Я осознал, что пытался «переинженерить» задачу. Машинам не нужен интеллект — им нужна лишь локальная инструкция, диктуемая тайлом. Код, написанный мною по мотивам анализа оригинала, получился лаконичным и эффективным. Ознакомиться с реализацией можно в методе decide_desired_direction файла Car.cpp.
Разработчик создал игру про иголку в стогу сена без страницы в Steam, после чего ее захватили клоны
Вышла новая версия эмулятора PS2 PCSX2 2.8.0 с масштабными улучшениями
Хроники Orbis: от триумфального переосмысления Civilization IV до творческого тупика в пятой части
Sega закрыла студию из-за провала мобильной игры про Соника
Шедевр на века: истории культовых игр, оставшихся без продолжения
Создатели Dragon Quest разрабатывают 4X-стратегию Conquista с необычной системой жителей
Директор Final Fantasy 7 признался в восхищении The Witcher 3
В сети появилась масштабная утечка билдов Valve