Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
#include "sim/target.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
// Кучки: 5 на арене (рядом со стартом), 3 в северной комнате,
|
|
|
|
|
|
// 3 в западной, 1 одиночная в восточной. Всего 12.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Северная кучка стоит НАПРОТИВ прохода x=30..31: из коридора до неё есть
|
|
|
|
|
|
// чистая линия. Это тот самый тест-кейс из спека — в узком проходе правило
|
|
|
|
|
|
// «не стрелять сквозь своих» упирается в геометрию, и отряд обязан вытянуться
|
|
|
|
|
|
// в колонну: стреляет передний, задние молчат.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Кучка обязана быть В ПРЕДЕЛАХ ДАЛЬНОСТИ от середины прохода (y≈14), иначе
|
|
|
|
|
|
// стрелять из коридора не по чему и тест-кейс проверяет пустоту. При weaponRange
|
|
|
|
|
|
// 7.2 ближняя мишень стоит в ~6.5 юнита: запас есть, но небольшой — если менять
|
|
|
|
|
|
// дальность, эти координаты надо пересчитывать вместе с ней.
|
|
|
|
|
|
const float kTargetSpots[NUM_TARGETS][2] = {
|
|
|
|
|
|
{30.5f, 20.5f}, {31.5f, 22.5f}, {29.5f, 23.5f}, {32.5f, 21.5f}, {30.5f, 24.5f},
|
|
|
|
|
|
{29.5f, 8.5f}, {31.5f, 7.5f}, {27.5f, 10.5f},
|
|
|
|
|
|
{ 7.5f, 40.5f}, { 9.5f, 42.5f}, { 6.5f, 43.5f},
|
|
|
|
|
|
{43.5f, 35.5f},
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Сопротивление отбросу по слотам. Не случайное: в каждой кучке есть кто-то
|
|
|
|
|
|
// тяжёлый, кого клинком не сдвинуть, и кто-то лёгкий, кто улетает от первого
|
|
|
|
|
|
// же удара. Иначе «отброс» и «сопротивление» — два числа, которых не видно.
|
|
|
|
|
|
const float kTargetKnockResist[NUM_TARGETS] = {
|
|
|
|
|
|
0.00f, 0.65f, 0.15f, 0.40f, 0.00f,
|
|
|
|
|
|
0.55f, 0.10f, 0.30f,
|
|
|
|
|
|
0.20f, 0.70f, 0.05f,
|
|
|
|
|
|
0.85f,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
// Кто стоит в каждой точке в боевом режиме. Ближняя кучка — та, на которую
|
|
|
|
|
|
// отряд наткнётся первой: бегун, двое бредущих, плевок и ещё бегун. Громилы
|
|
|
|
|
|
// сидят в дальних комнатах: до них надо дойти.
|
|
|
|
|
|
const EnemyKind kTargetKinds[NUM_TARGETS] = {
|
|
|
|
|
|
EnemyKind::RUSHER, EnemyKind::SHAMBLER, EnemyKind::SHAMBLER,
|
|
|
|
|
|
EnemyKind::SPITTER, EnemyKind::RUSHER,
|
|
|
|
|
|
EnemyKind::SHAMBLER, EnemyKind::SPITTER, EnemyKind::BRUTE,
|
|
|
|
|
|
EnemyKind::RUSHER, EnemyKind::SHAMBLER, EnemyKind::SPITTER,
|
|
|
|
|
|
EnemyKind::BRUTE,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Твари СВЕРХ мишеней: расставлены по всей карте, а не только у старта.
|
|
|
|
|
|
// Без них зачистка первой кучки заканчивала вылазку, и карта стояла пустой.
|
|
|
|
|
|
// В песочнице приёмки их нет вообще — та расстановка не менялась.
|
|
|
|
|
|
const float kExtraSpots[NUM_EXTRA_ENEMIES][2] = {
|
|
|
|
|
|
{14.5f, 12.5f}, {18.5f, 16.5f}, {12.5f, 24.5f},
|
|
|
|
|
|
{36.5f, 12.5f}, {40.5f, 18.5f}, {38.5f, 27.5f},
|
|
|
|
|
|
{21.5f, 36.5f}, {25.5f, 41.5f}, {33.5f, 39.5f},
|
|
|
|
|
|
{16.5f, 32.5f}, {30.5f, 33.5f}, {41.5f, 43.5f},
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Хваты стоят ПОДАЛЬШЕ от старта, в глубине карты: захват — это ловушка для
|
|
|
|
|
|
// отряда, который уже разошёлся по позициям, а не встречающий у порога.
|
|
|
|
|
|
const EnemyKind kExtraKinds[NUM_EXTRA_ENEMIES] = {
|
|
|
|
|
|
EnemyKind::SHAMBLER, EnemyKind::RUSHER, EnemyKind::SHAMBLER,
|
|
|
|
|
|
EnemyKind::SPITTER, EnemyKind::SHAMBLER, EnemyKind::RUSHER,
|
|
|
|
|
|
EnemyKind::LURKER, EnemyKind::BRUTE, EnemyKind::SPITTER,
|
|
|
|
|
|
EnemyKind::RUSHER, EnemyKind::SHAMBLER, EnemyKind::LURKER,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Разрушаемая обстановка. Стоит ПАРАМИ и по краям комнат, а не по центру:
|
|
|
|
|
|
// брошенный скарб жмётся к стенам, и ровно поэтому он читается как обстановка,
|
|
|
|
|
|
// а не как расставленные мишени. Две штуки — у самого старта: игрок обязан
|
|
|
|
|
|
// узнать, что хлам ломается, до того как в него полетит первая тварь.
|
|
|
|
|
|
const float kPropSpots[NUM_PROPS][2] = {
|
|
|
|
|
|
{24.5f, 24.5f}, {23.5f, 25.5f}, // у старта: пара ящиков под рукой
|
|
|
|
|
|
{33.5f, 19.5f}, // ближняя кучка: укрытие сбоку
|
|
|
|
|
|
{28.5f, 6.5f}, {26.5f, 6.5f}, // северная комната, вдоль стены
|
|
|
|
|
|
{ 5.5f, 41.5f}, // западная комната
|
|
|
|
|
|
{44.5f, 33.5f}, {42.5f, 44.5f}, // восточная и юго-восточный угол
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const EnemyKind kPropKinds[NUM_PROPS] = {
|
|
|
|
|
|
EnemyKind::CRATE, EnemyKind::BARREL,
|
|
|
|
|
|
EnemyKind::CRATE,
|
|
|
|
|
|
EnemyKind::LOCKER, EnemyKind::BARREL,
|
|
|
|
|
|
EnemyKind::CRATE,
|
|
|
|
|
|
EnemyKind::BARREL, EnemyKind::LOCKER,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
} // namespace
|
|
|
|
|
|
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
EnemyDef EnemyDefOf(EnemyKind kind)
|
|
|
|
|
|
{
|
|
|
|
|
|
EnemyDef d;
|
|
|
|
|
|
switch (kind)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Бредущий: основа толпы. Медленный настолько, что от него можно уйти
|
|
|
|
|
|
// шагом, — и ровно поэтому страшен только гурьбой.
|
|
|
|
|
|
case EnemyKind::SHAMBLER:
|
|
|
|
|
|
d.name = "SHAMBLER";
|
|
|
|
|
|
d.hp = 210.0f; d.radius = 0.34f; d.speed = 0.95f; d.knockResist = 0.25f;
|
|
|
|
|
|
d.aggroRadius = 9.5f; d.attackRange = 0.85f; d.damage = 13.0f;
|
|
|
|
|
|
d.windup = 0.42f; d.interval = 1.25f;
|
|
|
|
|
|
// Взмах лапой: широкий сектор перед собой. Отходить от него назад
|
|
|
|
|
|
// бесполезно — он и так короткий; уходить надо вбок.
|
|
|
|
|
|
d.attack = AttackKind::SWIPE; d.swipeArcDeg = 100.0f;
|
|
|
|
|
|
d.lightPower = 0.05f;
|
|
|
|
|
|
d.r = 116; d.g = 52; d.b = 52;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
// Бегун: тонкий и быстрый. Успевает добежать до перезарядки — и тогда
|
|
|
|
|
|
// стрелок остаётся с ним один на один.
|
|
|
|
|
|
case EnemyKind::RUSHER:
|
|
|
|
|
|
d.name = "RUSHER";
|
|
|
|
|
|
d.hp = 110.0f; d.radius = 0.27f; d.speed = 3.3f; d.knockResist = 0.0f;
|
|
|
|
|
|
d.aggroRadius = 12.0f; d.attackRange = 0.75f; d.damage = 14.0f;
|
|
|
|
|
|
d.windup = 0.28f; d.interval = 1.10f;
|
|
|
|
|
|
// Рывок: разрыв в три метра он закрывает за пятую долю секунды и
|
|
|
|
|
|
// сносит ВСЕХ по прямой. Замах длиннее прежнего удара намеренно —
|
|
|
|
|
|
// это единственное окно, в котором отряд успевает разойтись с оси.
|
|
|
|
|
|
d.attack = AttackKind::LUNGE; d.lungeDist = 3.4f; d.lungeTime = 0.20f;
|
|
|
|
|
|
d.lightPower = 0.07f;
|
|
|
|
|
|
d.r = 158; d.g = 74; d.b = 44;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
// Плевок: единственный, кто достаёт издалека. Держит дистанцию и бьёт
|
|
|
|
|
|
// по площадям — из-за него отряд не может просто встать в линию.
|
|
|
|
|
|
case EnemyKind::SPITTER:
|
|
|
|
|
|
d.name = "SPITTER";
|
|
|
|
|
|
d.hp = 110.0f; d.radius = 0.31f; d.speed = 1.15f; d.knockResist = 0.1f;
|
|
|
|
|
|
d.aggroRadius = 10.5f; d.attackRange = 6.2f; d.damage = 16.0f;
|
|
|
|
|
|
d.windup = 0.55f; d.interval = 1.60f;
|
|
|
|
|
|
d.ranged = true; d.projectileSpeed = 8.5f;
|
|
|
|
|
|
// Снаряд летит дальше, чем плевок «достаёт»: отойти от него на шаг
|
|
|
|
|
|
// мало, надо разрывать дистанцию или прятаться за стену.
|
|
|
|
|
|
d.attack = AttackKind::SPIT; d.spitRange = 8.4f;
|
|
|
|
|
|
d.lightPower = 0.10f;
|
|
|
|
|
|
d.r = 96; d.g = 132; d.b = 72;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
// Громила: медленный, толстый, с одного удара снимает половину бойца.
|
|
|
|
|
|
// Клинком его надо разбирать вдвоём, и это правильная цена.
|
|
|
|
|
|
case EnemyKind::BRUTE:
|
|
|
|
|
|
d.name = "BRUTE";
|
|
|
|
|
|
d.hp = 520.0f; d.radius = 0.46f; d.speed = 1.05f; d.knockResist = 0.85f;
|
|
|
|
|
|
d.aggroRadius = 8.5f; d.attackRange = 1.25f; d.damage = 46.0f;
|
|
|
|
|
|
d.windup = 0.95f; d.interval = 2.60f;
|
|
|
|
|
|
// Удар оземь: круг вокруг себя, а не выпад в жертву. Разбирать
|
|
|
|
|
|
// громилу вдвоём теперь стоит денег — оба стоят в круге.
|
|
|
|
|
|
d.attack = AttackKind::SLAM; d.slamRadius = 2.15f;
|
|
|
|
|
|
d.lightPower = 0.12f;
|
|
|
|
|
|
d.r = 142; d.g = 60; d.b = 78;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
// Хват: сам по себе слаб, но держит бойца на месте, пока его не убьют.
|
|
|
|
|
|
// Опасен не уроном, а тем, что вырывает одного из строя: линия огня
|
|
|
|
|
|
// рушится, отряд разваливается, и остальные твари доедают.
|
|
|
|
|
|
case EnemyKind::LURKER:
|
|
|
|
|
|
d.name = "LURKER";
|
|
|
|
|
|
d.hp = 150.0f; d.radius = 0.30f; d.speed = 1.90f; d.knockResist = 0.15f;
|
|
|
|
|
|
d.aggroRadius = 11.0f; d.attackRange = 0.90f; d.damage = 9.0f;
|
|
|
|
|
|
d.windup = 0.50f; d.interval = 2.40f;
|
|
|
|
|
|
// Урон тикает, пока держит: 9 за тик каждые 0.45 с — само по себе
|
|
|
|
|
|
// терпимо, смертельна именно неподвижность.
|
|
|
|
|
|
d.attack = AttackKind::GRAB; d.grabTime = 2.60f; d.grabTick = 0.45f;
|
|
|
|
|
|
d.lightPower = 0.09f;
|
|
|
|
|
|
d.r = 88; d.g = 62; d.b = 118;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
// --- разрушаемая обстановка -------------------------------------------
|
|
|
|
|
|
// Всё боевое по нулям: ни скорости, ни агро, ни урона. Даже если бы
|
|
|
|
|
|
// UpdateEnemies до них дошёл (он не доходит — см. IsProp), ящику нечем
|
|
|
|
|
|
// ни идти, ни бить. Единственное, что у них есть, — HP и радиус.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Сопротивление отбросу единица: ящик от попадания не ездит по полу.
|
|
|
|
|
|
// Живучесть подобрана от ОДНОГО магазина: труху сносит очередью на ходу,
|
|
|
|
|
|
// шкафчик требует остановиться — и в этом вся разница между ними.
|
|
|
|
|
|
case EnemyKind::CRATE:
|
|
|
|
|
|
d.name = "CRATE";
|
|
|
|
|
|
d.hp = 60.0f; d.radius = 0.38f; d.knockResist = 1.0f;
|
|
|
|
|
|
d.r = 104; d.g = 76; d.b = 46;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case EnemyKind::BARREL:
|
|
|
|
|
|
d.name = "BARREL";
|
|
|
|
|
|
d.hp = 95.0f; d.radius = 0.33f; d.knockResist = 1.0f;
|
|
|
|
|
|
d.r = 92; d.g = 84; d.b = 58;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case EnemyKind::LOCKER:
|
|
|
|
|
|
d.name = "LOCKER";
|
|
|
|
|
|
d.hp = 140.0f; d.radius = 0.36f; d.knockResist = 1.0f;
|
|
|
|
|
|
d.r = 78; d.g = 88; d.b = 96;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
// Мишень приёмки: всё по нулям, поведения нет. Вид атаки ей выставлен
|
|
|
|
|
|
// формально — с нулевым уроном и нулевой дальностью он не сработает
|
|
|
|
|
|
// никогда, а UpdateEnemies до неё вообще не доходит.
|
|
|
|
|
|
default:
|
|
|
|
|
|
d.name = "TARGET";
|
|
|
|
|
|
d.hp = g_tune.targetHP;
|
|
|
|
|
|
d.radius = g_tune.targetRadius;
|
|
|
|
|
|
d.attack = AttackKind::SWIPE;
|
|
|
|
|
|
d.r = 120; d.g = 44; d.b = 44;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
return d;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char* EnemyName(EnemyKind kind) { return EnemyDefOf(kind).name; }
|
|
|
|
|
|
|
|
|
|
|
|
void MakeTarget(ecs::World& world, EnemyKind kind, Vec2 pos, float knockResist,
|
|
|
|
|
|
const Tilemap* map)
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
{
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
const EnemyDef def = EnemyDefOf(kind);
|
|
|
|
|
|
|
|
|
|
|
|
Target t;
|
|
|
|
|
|
t.self = world.Create();
|
|
|
|
|
|
t.kind = kind;
|
|
|
|
|
|
t.pos = pos;
|
|
|
|
|
|
t.home = t.pos;
|
|
|
|
|
|
t.vel = {};
|
|
|
|
|
|
t.hp = def.hp;
|
|
|
|
|
|
t.maxHp = def.hp;
|
|
|
|
|
|
t.radius = def.radius;
|
|
|
|
|
|
t.respawnTimer = 0.0f;
|
|
|
|
|
|
t.alive = true;
|
|
|
|
|
|
// У мишени приёмки сопротивление отбросу расписано по слотам, у твари оно —
|
|
|
|
|
|
// свойство вида. Отрицательное значение означает «взять из каталога».
|
|
|
|
|
|
t.knockResist = (knockResist >= 0.0f) ? knockResist : def.knockResist;
|
|
|
|
|
|
|
|
|
|
|
|
t.speed = def.speed;
|
|
|
|
|
|
t.aggroRadius = def.aggroRadius;
|
|
|
|
|
|
t.attackRange = def.attackRange;
|
|
|
|
|
|
t.damage = def.damage;
|
|
|
|
|
|
t.windup = def.windup;
|
|
|
|
|
|
t.interval = def.interval;
|
|
|
|
|
|
t.ranged = def.ranged;
|
|
|
|
|
|
t.projectileSpeed = def.projectileSpeed;
|
|
|
|
|
|
|
|
|
|
|
|
t.attack = def.attack;
|
|
|
|
|
|
t.swipeArcDeg = def.swipeArcDeg;
|
|
|
|
|
|
t.lungeDist = def.lungeDist;
|
|
|
|
|
|
t.lungeTime = def.lungeTime;
|
|
|
|
|
|
t.spitRange = def.spitRange;
|
|
|
|
|
|
t.slamRadius = def.slamRadius;
|
|
|
|
|
|
t.grabTime = def.grabTime;
|
|
|
|
|
|
t.grabTick = def.grabTick;
|
|
|
|
|
|
|
|
|
|
|
|
// Точки расставлены руками, а планировка генерируется: тварь, поставленная
|
|
|
|
|
|
// в стену, никогда бы оттуда не вышла — она сдвигается только когда идёт
|
|
|
|
|
|
// за кем-то, а из стены ей никого не видно.
|
|
|
|
|
|
if (map)
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
{
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
map->ResolveCircle(t.pos, t.radius);
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
t.home = t.pos;
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
world.Add<Target>(t.self, t);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SpawnTargets(ecs::World& world, bool hostile, const Tilemap* map)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Три полосы подряд в одном пуле: мишени, твари сверх них, обстановка.
|
|
|
|
|
|
// В песочнице приёмки живёт только первая — ни одной лишней сущности,
|
|
|
|
|
|
// и все замеры остаются сравнимыми с прежними.
|
|
|
|
|
|
const int total = hostile ? (NUM_TARGETS + NUM_EXTRA_ENEMIES + NUM_PROPS) : NUM_TARGETS;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < total; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
const int extraIdx = i - NUM_TARGETS;
|
|
|
|
|
|
const int propIdx = extraIdx - NUM_EXTRA_ENEMIES;
|
|
|
|
|
|
const bool extra = (extraIdx >= 0 && propIdx < 0);
|
|
|
|
|
|
const bool prop = (propIdx >= 0);
|
|
|
|
|
|
|
|
|
|
|
|
const EnemyKind kind = !hostile ? EnemyKind::DUMMY
|
|
|
|
|
|
: prop ? kPropKinds[propIdx]
|
|
|
|
|
|
: extra ? kExtraKinds[extraIdx]
|
|
|
|
|
|
: kTargetKinds[i];
|
|
|
|
|
|
|
|
|
|
|
|
const Vec2 pos = prop ? Vec2{kPropSpots[propIdx][0], kPropSpots[propIdx][1]}
|
|
|
|
|
|
: extra ? Vec2{kExtraSpots[extraIdx][0], kExtraSpots[extraIdx][1]}
|
|
|
|
|
|
: Vec2{kTargetSpots[i][0], kTargetSpots[i][1]};
|
|
|
|
|
|
|
|
|
|
|
|
MakeTarget(world, kind, pos, hostile ? -1.0f : kTargetKnockResist[i], map);
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KnockTarget(Target& t, Vec2 dir, float speed)
|
|
|
|
|
|
{
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
// Обстановка не ездит по полу от попаданий. Домой её никто не тянет (это
|
|
|
|
|
|
// свойство мишени приёмки), так что сдвинутый ящик уехал бы навсегда.
|
|
|
|
|
|
if (t.IsProp()) return;
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
t.vel += dir * (speed * t.KnockScale());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateTargets(std::vector<Target>& targets, float dt)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Отдача гасится и мишень возвращается на своё место: расстановка уровня
|
|
|
|
|
|
// захардкожена, и «уползание» мишеней ломало бы все замеры разом.
|
|
|
|
|
|
const float damp = std::exp(-g_tune.targetKnockDamp * dt);
|
|
|
|
|
|
const float pull = 1.0f - std::exp(-g_tune.targetReturnRate * dt);
|
|
|
|
|
|
|
|
|
|
|
|
for (Target& t : targets)
|
|
|
|
|
|
{
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
t.hurtTimer = std::max(0.0f, t.hurtTimer - dt);
|
|
|
|
|
|
|
|
|
|
|
|
if (t.IsDummy())
|
|
|
|
|
|
{
|
|
|
|
|
|
// Мишень приёмки: ручки tuning продолжают крутить именно её.
|
|
|
|
|
|
t.radius = g_tune.targetRadius;
|
|
|
|
|
|
t.maxHp = g_tune.targetHP;
|
|
|
|
|
|
}
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
|
|
|
|
|
|
t.pos += t.vel * dt;
|
|
|
|
|
|
t.vel *= damp;
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
// Возврат на своё место — свойство МИШЕНИ, а не тела: тварь, которую
|
|
|
|
|
|
// тянет домой, не может ни догнать отряд, ни отойти от него.
|
|
|
|
|
|
if (t.IsDummy()) t.pos += (t.home - t.pos) * pull;
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
|
|
|
|
|
|
if (t.alive) continue;
|
|
|
|
|
|
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
// Разбитый хлам остаётся разбитым: RespawnDelay() возвращает ему
|
|
|
|
|
|
// отрицательный срок, и без этой проверки он воскресал бы в тот же кадр.
|
|
|
|
|
|
if (t.IsProp()) continue;
|
|
|
|
|
|
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
t.respawnTimer -= dt;
|
|
|
|
|
|
if (t.respawnTimer <= 0.0f)
|
|
|
|
|
|
{
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
const EnemyDef def = EnemyDefOf(t.kind);
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
t.alive = true;
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
t.hp = t.IsDummy() ? g_tune.targetHP : def.hp;
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
t.pos = t.home;
|
|
|
|
|
|
t.vel = {};
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
t.victim = -1;
|
|
|
|
|
|
t.aggro = false;
|
|
|
|
|
|
t.attackTimer = 0.0f;
|
|
|
|
|
|
t.windupTimer = 0.0f;
|
|
|
|
|
|
// Недоведённый рывок и незакрытый захват пережили бы смерть и
|
|
|
|
|
|
// вернулись бы вместе с тварью. Захваченного бойца при этом никто
|
|
|
|
|
|
// не держит: его таймер гаснет сам, пока держать некому.
|
|
|
|
|
|
t.lungeTimer = 0.0f;
|
|
|
|
|
|
t.lungeMask = 0;
|
|
|
|
|
|
t.grabbed = -1;
|
|
|
|
|
|
t.grabTimer = 0.0f;
|
|
|
|
|
|
t.grabTickTimer = 0.0f;
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CountAliveTargets(const std::vector<Target>& targets)
|
|
|
|
|
|
{
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
// Хлам здесь не считается: это знаменатель «по скольким целям отряд может
|
|
|
|
|
|
// работать» (спек 6.5) и цифра в HUD. Нетронутый ящик в углу не делает
|
|
|
|
|
|
// огневую позицию хуже и зачистку — незаконченной.
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
int n = 0;
|
|
|
|
|
|
for (const Target& t : targets)
|
Tile2D: движок отдельным продуктом, игра — проектом в нём (M11-M20)
Десять вех одним состоянием: разделять их пофайлово нечем, потому что
src/game.cpp менялся почти в каждой. Собирается начисто без предупреждений,
все проверки проходят.
ДВИЖОК (engine/, цель tile2d)
Каталог свой, и решение «это движок» принимается тем, куда положен файл.
Компилятор нашёл три зависимости движка от игры, и все сняты: размеры кадра
и карты уехали в engine/config.h, потолок населения этажа стал своим
(MAX_LEVEL_SPAWNS против игровой MAX_TARGETS), запасная точка старта стала
центром карты вместо позиции отряда.
engine/projection.* единственное место, где движок знает про изометрию;
видов сразу два — абстракция с одной реализацией ничем
не проверена и обычно оказывается неправильной
engine/project.* манифест проекта: пути, вид, кривая глубины
engine/app.* окно, кадр, fixed timestep — вместо двух копий цикла
engine/tilemap_draw движок научился показывать свою карту
РЕДАКТОР (editor/, цель tile2d_editor)
Открывает любой проект и ни одной игры по имени не знает.
--tool одиннадцать безоконных команд: комнаты, каталог, кривая, сборка
этажа, ASCII-карта, проверка набора. Правку делают файлами,
последствия читают командой (docs/19-agent.md)
терминал снизу: те же инструменты, git, сборка и запросы к claude/codex,
открытый проект уходит потомкам через TILE2D_PROJECT
ПРИМЕР (samples/walk, цель tile2d_walk)
Второй потребитель движка. Игра и редактор самостоятельность движка
проверить не могут: редактор мира не рисует, а игра — то место, куда общий
код и уезжает незаметно.
ИГРА (src/)
Экстракшен: вес и два порога переноски, конечный боезапас, расходники
применяются сами, общая сумка отряда, трата опыта на улучшения.
Каждое из правил проверяется прогоном, а не глазами, и проверки поймали:
вес дважды не связывал ничего (мерил по бинтам прогона, а не по добыче);
боец с клинком не тратил найденные патроны при запасном стволе в сумке;
массив виджетов экрана переполнился и молча съел хвост схрона; проверка
улучшений сама ломала забег, вызывая NewRun посреди спуска.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 01:07:19 +07:00
|
|
|
|
if (t.alive && !t.IsProp()) ++n;
|
Прототип боевого ядра: отряд, хоррор-слой, ближний бой
Тактический отряд с автоматическим огнём в изометрии, собственный
софтверный растеризатор (raylib только окно, ввод и финальный блит).
Ядро (спек, раздел 6):
- LaneClear: проверка линии огня по своим, стенам и дальности;
- решатель огневых позиций с гистерезисом и коммитом;
- резервирование линий огня и расступание из чужих секторов;
- пули-снаряды, дружественный урон физически возможен.
Хоррор-слой (render-only): свет и туман войны с памятью карты,
светящиеся трассеры, кровь, виньетка, зерно, напряжение.
Ближний бой: сектор удара, три фазы, связка из трёх ударов,
своя дисциплина «не бить сквозь своего».
Проверка: squad_proto.exe --accept прогоняет критерии приёмки
раздела 11 плюс блок M7 по ближнему бою — все PASS,
FRIENDLY_HITS = 0 за 3 минуты боя.
Сборка: cmake -S . -B build && cmake --build build --config Release
raylib 6.0 подтягивается через FetchContent.
Документация — CLAUDE.md как оглавление, содержание в docs/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 17:00:49 +07:00
|
|
|
|
return n;
|
|
|
|
|
|
}
|