- Stage 1: Eliminate fish-eye distortion with precomputed tangential ray offset table and fractional DDA depth - Stage 2: Full asset management in EblanStudio (stb_image/stb_image_write, 128x128 BGRA texture packaging, WAV sound manager) - Stage 3: Multi-level room streaming, LevelTransition/CELL_PORTAL trigger system, 16-frame screen fade to black - Stage 4: 60Hz cutscene engine in pure x86 ASM (v4 binary track, waypoint camera motion, shortest-arc pan, CP1251 Russian subtitles, letterbox overlay, audio) - Stage 5: EblanStudio cutscene timeline (F6) and windowless Live ASM Viewport over shared-memory IPC directly rendered into DX11 - Tooling & Tests: comprehensive regression test suite (94 editor + 107 engine tests), IPC tests, and cutscene demo
24 KiB
ТЕХНИЧЕСКОЕ ЗАДАНИЕ ДЛЯ АРТЕМА: EBLAN ENGINE 3D & EBLANSTUDIO
Назначение документа: Детальный план разработки следующих ключевых подсистем игрового 2.5D движка на ассемблере (EBLAN ENGINE 3D) и сопутствующего C++ визуального редактора (EblanStudio).
Целевой стек: x86 MASM32 (движок), C++17 + Dear ImGui + DirectX 11 (редактор).
Проверка реализации этапов 1–3 — 21.10.2026
- Этап 1: тангенциальные углы лучей, единственная косинусная коррекция, DDA с 8 дробными битами до проекции. В регрессионной сцене прямая стена имеет одинаковую глубину во всех 320 столбцах.
- Этап 2: PNG/JPG/BMP, BGRA и хромакей, безопасное создание и обновление пакета, стандартные слоты при первом импорте, WAV и манифесты. Портал не использует слот фонаря.
- Этап 3: EBLN v3 с чтением v1/v2, полная проверка перед заменой комнаты, обработка ошибочного перехода, спавны, затемнение и защита от повторного срабатывания при появлении в портале. F5 работает с временной копией карт и ресурсов.
- Регрессионные проверки:
python tools/test_regressions.py. Ручная проверка интерфейса и длительный игровой прогон остаются отдельной проверкой качества. - Этапы 4 и 5 реализованы следующим изменением, см. статус ниже.
Реализация этапов 4–5 — 22.10.2026
- Этап 4: бинарный трек EBLN v4, чистый ASM, линейные пролёты по точкам, повороты по кратчайшей дуге, паузы, русские субтитры CP1251, letterbox 2.35:1, WAV, затемнения и переходы. Автозапуск при входе, C для повтора и Tab для пропуска; управление игроком блокируется на время сцены. Старые карты v1/v2/v3 читаются.
- Этап 5: F6 открывает таймлайн с дорожками, перетаскиванием ключей, списком команд, инспектором, установкой точек на карте, автозапуском, Undo/Redo и сохранением. Предпросмотр и перемотка показывают сцену глазами камеры во встроенном игровом виде, а на карте — траекторию. F5 запускает полную игру и связанные комнаты с проверкой WAV.
- Пример
examples/cutscene_demo/run_demo.batпоказывает пролёт, текст, звук и переход во вторую комнату; основные карты проекта он не меняет. - Регрессионный набор расширен проверками формата v4, проигрывателей ASM/C++, оверлея, переходов, редактора и покадрового совпадения состояния.
- Уточнения исходного ТЗ: сериализуемый
dataPtrзаменён наdataId, строки хранятся в отдельном пуле; движение задаётся длительностью. Использованы линейные waypoints, камера во время пролёта не сталкивается со стенами. WAV воспроизводится одним каналом PlaySoundA без внешних библиотек.
Завершение редактора и исправление F5 — 22.10.2026
- Встроен игровой вид, который получает кадры от настоящего ASM-рендерера. Доступны режимы «Рядом», «Игровой вид», «Карта», свободный осмотр и камера таймлайна. Изменения стен, цветов, спрайтов и текстур видны без сохранения.
- Исправлена блокировка F5/F6 при захвате клавиатуры интерфейсом ImGui. Ошибки запуска показываются отдельным диалогом. Начальная карта открывается относительно расположения редактора, независимо от рабочей папки.
- Автопроверки проверяют горячие клавиши с фокусом в интерфейсе, реальную передачу кадров из x86 ASM в x64 редактор и DX11, обновление геометрии, перемотку кат-сцены, точное совпадение пикселей с отдельным движком и освобождение процесса рендерера.
- Все пять этапов реализованы. Предпросмотр редактора останавливается на команде перехода между комнатами; полный сценарий переходов и игровой ввод доступны через F5. Это ограничение предпросмотра, а не отсутствие переходов в движке.
- Итоговая проверка: 94/94 сценария редактора и 107/107 сценариев ASM, совпадение всех 320 углов лучей, покадровое совпадение проигрывателей и точное совпадение пикселей встроенного вида с движком. Обе программы пересобраны. Исходные ресурсы проекта при проверках остались без изменений. Ручное управление окнами было остановлено пользователем через Esc; полный визуальный прогон интерфейса не завершён.
Разделы ниже сохраняют исходное ТЗ и описание прежних проблем как историю требований. Актуальные формат и поведение описаны в AGENTS.md и docs/ENGINE_ARCHITECTURE.md.
📋 Оглавление
- Задача 1: Устранение Fish-Eye эффекта и фикс рендера
- Задача 2: Полноценный импорт ассетов в EblanStudio
- Задача 3: Многоуровневые локации и стриминг подуровней
- Задача 4: Система кат-сцен и скриптовых последовательностей
- Чек-лист готовности и порядок реализации
Задача 1: Устранение Fish-Eye эффекта и фикс рендера [ВЫПОЛНЕНО / DONE]
1.1. Суть проблемы в текущем коде
В файле include/engine_raycaster.inc лучи выпускаются с равномерным шагом угла:
; Линейное распределение углов по ширине экрана:
rayAngle = playerAngle - FOV_HALF + (screenX * FOV_ANGLES / SCREEN_W)
- Геометрическое искажение: когда экран плоский, равные интервалы пикселей по оси
Xсоответствуют разным угловым приращениям (\tan \theta \ne \theta). Лучи, выпущенные с постоянным шагом угла, проецируются на изогнутую цилиндрическую поверхность. - Артефакт "рыбьего глаза": стены по краям экрана кажутся вздутыми, а при повороте камеры прямые стены начинают "плавать" и изгибаться волной.
- Ошибки DDA: в секции
apply_fisheye_fixрасстояние повторно умножается на косинус, что при некоторых углах дает артефакт двойного искажения.
1.2. Решение: Тангенциальная коррекция углов лучей
Сохраняя радиальную архитектуру лучей (512 дискретных углов), пересчитать угол каждого столбца x \in [0..319] через тангенс:
\theta_x = \text{playerAngle} + \arctan\left(\left(\frac{2x}{\text{SCREEN\_W}} - 1\right) \cdot \tan\left(\frac{\text{FOV}}{2}\right)\right)
Что нужно сделать:
- Таблица предвычисленных смещений лучей (
tableRayAngleOffset):- В
include/engine_math.incпри вызовеInitMathTablesсгенерировать через FPU таблицу из 320 значенийDWORD. - Для каждого столбца
x:float cameraX = (2.0f * x / 320.0f) - 1.0f; float radOffset = atanf(cameraX * tanf(FOV_RAD / 2.0f)); int angleOffset = (int)roundf(radOffset * 512.0f / (2.0f * M_PI)); tableRayAngleOffset[x] = angleOffset;
- В
- Использование в цикле лучей (
include/engine_raycaster.inc):- Заменить линейный расчет угла на быстрый табличный:
mov eax, screenX mov edx, [tableRayAngleOffset + eax*4] add edx, playerAngle and edx, ANGLE_MASK mov rayAngle, edx
- Заменить линейный расчет угла на быстрый табличный:
- Коррекция перпендикулярного расстояния:
- Перпендикулярная дистанция:
\text{perpWallDist} = \text{rawDist} \cdot \cos(\text{rayAngle} - \text{playerAngle}) - Убедиться, что
sideDistXиdeltaDistXне накапливают масштабирующий множитель 64 дважды при вычислении текстурных координат (texX).
- Перпендикулярная дистанция:
Задача 2: Полноценный импорт ассетов в EblanStudio [ВЫПОЛНЕНО / DONE]
2.1. Требования
У Артема и дизайнеров уровней должна быть возможность в пару кликов мыши в редакторе загружать свои изображения (PNG) и звуки (WAV) без ручного запуска сторонних питоновских скриптов.
2.2. Архитектура Asset Manager в C++ (editor/)
- Библиотека декодирования картинок:
- Подключить
stb_image.h(однофайловая C++ библиотека без внешних зависимостей) в папкуeditor/src/stb_image.h. - Загрузка любого PNG, JPG, BMP в 32-битный массив пикселей:
int w, h, channels; unsigned char* data = stbi_load(filename, &w, &h, &channels, 4); // RGBA32
- Подключить
- Диалоговые окна выбора файлов Win32:
- Использовать стандартный
GetOpenFileNameAдля выбора PNG/WAV файлов.
- Использовать стандартный
- Конвертация и упаковка текстур (Wall Textures & Sprites):
- Входное изображение ресемплится/обрезается до стандарта движка: 128x128 пикселей.
- Цветовые каналы конвертируются из RGBA в BGRA (
00RRGGBBh), где для прозрачных спрайтов альфа = 0 заменяется на ключевой цвет мадженты0x00FF00FF(COLOR_CHROMA_KEY). - Автоматическая перезапись и сохранение в
assets/textures/texturepack.bin(заголовокEBTX+ 16 слотов по 65536 байт).
- Интерфейс в EblanStudio:
- Вкладка меню:
Ассеты -> Импорт текстуры стены...(выбор слота 1..15). - Вкладка меню:
Ассеты -> Импорт спрайта...(добавление в список доступных спрайтов). - Вкладка меню:
Ассеты -> Импорт аудио (WAV)...(копирование звука вassets/sounds/с автоматической генерацией алиаса MCI). - Превью текстуры прямо в палитре тайлов в левой панели редактора.
- Вкладка меню:
Задача 3: Многоуровневые локации и стриминг подуровней [ВЫПОЛНЕНО / DONE]
3.1. Секторно-комнатная модель уровней
Вместо одной изолированной сетки 32 \times 32 мир организуется как граф связанных секторов (комнат).
- Каждый сектор — это отдельный бинарный файл подуровня (например,
map.dat,sublevel_02.dat) со своей сеткой32 \times 32, цветами пола/потолка и локальными спрайтами. - Сектора соединяются Порталами / Дверями перехода (Sector Portals).
3.2. Структура данных перехода (Portal Transition)
В заголовок и сущности карты добавлен тип CELL_PORTAL = 10 и структура:
// Структура перехода между подуровнями (42 байта packed)
struct LevelTransition {
uint8_t triggerCellX; // Координата X двери/триггера в текущем секторе
uint8_t triggerCellY; // Координата Y двери/триггера в текущем секторе
char targetMap[32]; // Имя целевого файла: "sublevel_02.dat"
uint16_t targetSpawnX; // Точка появления в новом секторе (X)
uint16_t targetSpawnY; // Точка появления в новом секторе (Y)
uint16_t targetAngle; // Направление взгляда после перехода
uint8_t fadeEffect; // 0 = мгновенно, 1 = затемнение экрана (Fade to Black)
uint8_t reserved; // Выравнивание
};
3.3. Логика динамической подгрузки и выгрузки в Ассемблере
- Процедура перехода
SwitchSublevel(szNextMap, spawnX, spawnY, spawnAngle, fadeEffect):- Шаг 1 (Fade Out): Плавное затемнение буфера экрана
screenBufferза 16 кадров с помощью целочисленного масштабирования цветовых каналов RGB. - Шаг 2 (Unload): Очистка текущих спрайтов (
mov spriteCount, 0), сброс флагов и переходных триггеров. - Шаг 3 (Load): Чтение нового файла карты через
LoadSublevelBinaryвgameMap, обновление цветов неба/пола (mapCeilingColor,mapFloorColor), загрузка массива спрайтов нового сектора. - Шаг 4 (Spawn): Установка новых координат игрока
playerX = spawnX * 64 + 32,playerY = spawnY * 64 + 32,playerAngle = spawnAngle. - Шаг 5 (Fade In): Плавное 16-кадровое осветление экрана.
- Шаг 1 (Fade Out): Плавное затемнение буфера экрана
- Память и производительность:
- Постоянный объем оперативной памяти (~1-2 МБ), буферы очищаются и заполняются новым сектором на лету, позволяя создавать бесконечные цепочки и комплексы комнат.
- Во время обычного геймплея оверхед пост-процесса затемнения равен нулю (
cmp fadeState, 0; je fade_done).
- Интеграция в EblanStudio:
- Добавлен тайл
10. Портал переходас неоново-фиолетовой палитрой и меткой портала на 2D-сетке. - Инспектор свойств перехода: выбор файла целевого подуровня (
.dat), кнопка обзора файловой системы, слайдеры целевого спавна и угла, переключатель Fade to Black, быстрое удаление и кнопка мгновенного перехода к подуровню в редакторе. - Поддержка сериализации и десериализации переходов в бинарный формат с сохранением 100% обратной совместимости.
- Добавлен тайл
Задача 4: Система кат-сцен и скриптовых последовательностей [ВЫПОЛНЕНО / DONE]
4.1. Архитектура: Бинарный трек событий (Keyframe Track)
Кат-сцена представляет собой упорядоченный во времени список событий (Action Track). Во время кат-сцены управление игрока блокируется, а виртуальный режиссер интерполирует камеру, спавнит звуки и выводит диалоговые субтитры.
4.2. Формат команд кат-сцены
Каждая команда — это фиксированная 16-байтовая структура:
enum CutsceneOpCode : uint8_t {
OP_END = 0, // Конец кат-сцены, возврат управления
OP_WAIT, // Ждать N кадров/тиков
OP_MOVE_CAM_TO, // Плавное перемещение камеры в (X, Y) со скоростью V
OP_PAN_CAM_TO, // Плавный поворот камеры на угол Angle
OP_SHOW_SUBTITLE, // Вывести текст субтитра на экране (ID строки)
OP_HIDE_SUBTITLE, // Скрыть субтитры
OP_PLAY_SOUND, // Проиграть звук (WAV алиас)
OP_FADE_SCREEN, // Затемнить / осветлить экран
OP_CHANGE_SUBLEVEL // Инициировать переход на другой подуровень
};
struct CutsceneEvent {
uint16_t tickTimestamp; // Кадр запуска от старта сцены
uint8_t opCode; // Тип команды (CutsceneOpCode)
uint8_t param8; // Доп. байт параметров (напр. флаг fade)
int32_t paramA; // Целевой X / угол / длительность
int32_t paramB; // Целевой Y / скорость
int32_t dataPtr; // Указатель на текст / имя звука
};
4.3. Реализация в движке (MASM32)
- Флаг состояния
isCutsceneActive:DWORD:- Когда
isCutsceneActive == 1, вPollInputигнорируются клавишиWASDи стрелочки.
- Когда
- Интерполятор камеры
UpdateCutscene:- Вызывается в
UpdatePlayer. - Если задано
targetCamX, плавно сдвигаетplayerXк цели:; Движение playerX -> targetCamX mov eax, targetCamX sub eax, playerX ; нормализация шага и добавление скорости - Аналогично для угла поворота
playerAngleпо кратчайшей дуге окружности 512.
- Вызывается в
- Отрисовка 2D-субтитров:
- В
include/engine_render2d.incиспользовать существующийDrawString8x8для вывода полупрозрачной плашки внизу экрана (Letterbox 2.35:1) и текста диалогов с центрированием.
- В
4.4. Инструментарий в EblanStudio
- Добавить в редактор панель "Cutscene Timeline":
- Горизонтальная шкала времени (в секундах / кадрах).
- Кнопки добавления ключевых точек:
[+ Камера],[+ Текст],[+ Звук],[+ Переход]. - Возможность кликом по карте расставить контрольные точки пролета камеры (Spline/Waypoints).
- Кнопка предпросмотра пролета прямо в окне редактора.
Чек-лист готовности и порядок реализации
| Этап | Задача | Затронутые файлы | Ожидаемый результат |
|---|---|---|---|
| Этап 1 — готово | Исправление Fish-Eye и угла лучей | include/engine_math.inc, include/engine_raycaster.inc |
Стены остаются ровными по краям экрана, нет искажения при вращении камеры. |
| Этап 2 — готово | Импорт текстур и спрайтов в редакторе | editor/src/stb_image.h, editor/src/editor_app.cpp |
Кнопка импорта в GUI загружает PNG и обновляет assets/textures/texturepack.bin. |
| Этап 3 — готово | Система связанных секторов (комнат) | editor/src/level_format.h, include/engine_map.inc |
Переход между комнатами по триггеру с выгрузкой старой карты и загрузкой новой. |
| Этап 4 — готово | Движок кат-сцен и диалогов | include/engine_cutscene.inc, include/engine_data.inc, main.asm |
Пролёт камеры по ключевым точкам, субтитры, звук, затемнения, переходы, блокировка инпута. |
| Этап 5 — готово | Визуальный таймлайн в EblanStudio | editor/src/editor_cutscene.inl, editor/src/editor_viewport.inl, editor/src/cutscene_preview.h |
Редактирование траектории и сценария, предпросмотр игрового вида внутри редактора, Undo/Redo, F5 для полной игры. |
Файл подготовлен и структурирован для передачи в работу Артему.