Архитектура игры «Хроники Королевств»: C4 и критические пути
Схемы C4 до уровня компонентов и четыре критических пути через sequence: начало партии, кадр, приказ и сохранение.
«Хроники Королевств» — стратегия в духе Age of Empires II, которая запускается как обычный сайт: без сервера и сборки, около 80 модулей на JavaScript и холст на всю страницу. Игра переписана из Python-версии построчно, поэтому правила и числа совпадают с оригиналом. Ниже схемы C4 до уровня компонентов и четыре пути, на которых всё держится.
C4: контекст и контейнеры
Уровень 1. Система и её окружение
Игре нужны только файлы и браузер. Конвейер и Python-версия работают вне игры: первый готовит картинки, вторая служит эталоном для тестов.
Уровень 2. Контейнеры
Загрузчик тянет ассеты и показывает полосу прогресса, затем подключает игру. Игра говорит с браузером только через среду, которая повторяет API pygame.
C4 уровня 3: компоненты
Главный контейнер, «Игра», делится на три части: симуляция (правила), соперник (ИИ) и интерфейс. Симуляция не знает о графике, поэтому гоняется в тестах без экрана. Среда выполнения разобрана отдельно.
Симуляция
Мир хранит игроков, юниты, здания, снаряды, туман и ищет пути; один шаг мира двигает всё это.
Юниты, здания, технологии и 14 цивилизаций лежат в таблицах content/*: новая единица добавляется строкой данных.
Параметры матча (ресурсы, эпохи, перемирие, победа) собирает match.js.
Карты: шесть рецептов в mapgen.js плюс рельеф с высотами, обрывами и мелями.
Соперник (ИИ)
Каждый соперник думает раз в полсекунды и отдаёт те же команды, что и игрок.
Профиль задаёт, сколько селян держать в каждой эпохе, когда переходить дальше и когда нападать; уровней шесть, от лёгкого до предельного.
Война идёт по кругу: сбор, поход, бой, отход; решение берётся по сравнению сил.
Флот подключается только на картах с водой.
Интерфейс
Экран игры — один большой класс, к которому подмешаны панели, управление, меню, лобби и экраны вокруг матча.
Цикл простой: события, обновление мира, отрисовка, звук; меню, загрузка и итоги — это состояния того же цикла.
Звук слушает события мира (удар, смерть, постройка) и сам решает, что проиграть.
Картинка берёт готовые спрайты; если их нет, рисуется запасная процедурная графика.
Среда выполнения
Игровой код остался в стиле Python; среда притворяется Python, pygame и numpy поверх браузера.
py.js повторяет числа, сортировку и random бит в бит, поэтому сохранённая партия и тесты дают те же результаты, что в Python.
storage.js ведёт себя как обычные файлы: читает и пишет сразу, а в IndexedDB сбрасывает в фоне.
assets.js грузит по манифесту группами; листы юнитов приходят по одному, когда нужны.
Четыре критических пути
1. Начало партии
Мир строится за один шаг, а картинка ждёт, пока придут спрайты стартовых юнитов (не дольше короткого лимита).
2. Один кадр
Время кадра режется на шаги не длиннее 0.034 с; ИИ решает раз в полсекунды, остальные кадры только ждёт.
3. Приказ и его выполнение
Игрок и ИИ используют одни и те же команды юнита; очередь по Shift и патрули живут в модуле приказов.
4. Сохранение и загрузка
В файл попадает весь граф объектов целиком; статические таблицы записываются адресами и берутся из текущей версии игры.
Правила, на которых всё держится
Мир один знает правду. Экран только читает его и шлёт приказы.
Игрок и ИИ равны. Оба командуют юнитами через одни и те же cmd_*.
Данные отдельно от кода. Юниты, здания, технологии и цивилизации живут в таблицах.
Симуляция без графики. Тесты гоняют целые матчи ИИ против ИИ без экрана и сверяют их с CPython.
Нужное синхронно загружено заранее. Загрузчик кладёт ассеты в память до старта игры; листы юнитов подгружаются по одному.
Слабые места
Где
Что не так
Большие файлы
world.js — 3,2 тысячи строк, ui.js — 2,2 тысячи, hud.js — 2 тысячи: границ внутри них мало.
Подмешанные части
Экран игры собран из шести подмешанных частей, которые общаются через общие поля.
Связи по имени
Модули находят друг друга через реестр modules.* во время работы: в коде связи не видны.
Шаг зависит от кадра
Длина шага берётся из реального времени. Для общей партии по сети понадобится фиксированный шаг.
Вес
Первая загрузка около 60 МБ, все листы юнитов — ещё около 90 МБ; в памяти они раздуваются до гигабайтов.
Нет сервера
Сохранения живут только в одном браузере, сетевой игры нет.