Как 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.
Энтузиаст восстановил закрытую CD Projekt RED три года назад игру The Witcher: Monster Slayer
Слух: контроллер Xbox Elite Series 3 оснастят стиками на датчиках Холла
Prime 1 Studio открыла предзаказ на статую Гриффита из манги «Берсерк» высотой 93 сантиметра
Авторы симулятора BeamNG.drive намекнули на скорый выход игры на PS5
Названа стоимость русской версии настольной трилогии «Северного моря»
FLING UP TOGETHER получила новый трейлер — демо кооперативного платформера доступно в Steam
Inart откроет предзаказ на фигурку Вайпер из Valorant 7 октября
Младший победил старших: как Claude Sonnet 5.5 одолел Opus 5.5 и Fable 5.1 в пошаговой стратегии