Add MrGameEng.Pathfinding and MrGameEng.Collisions modules
CI / build-test (push) Failing after 1m5s

Pathfinding (depends on Core only): GridPathfinder with A* (octile/
Manhattan heuristic), Dijkstra and BFS over a game-implemented
IPathGrid; 4/8 connectivity, diagonals never cut corners. FlowField +
FlowFieldBuilder (multi-source Dijkstra) give crowds O(1) steering per
agent per frame. All buffers are grid-sized once and invalidated by a
generation stamp - repeated queries allocate nothing and clear nothing.

Collisions (Graphics exception: Transform2D, RectF): Collider component
(circle/AABB, offset, two-way layer masks), CollisionWorld - a uniform
spatial hash on flat arrays rebuilt from scratch each tick (O(n) for
movers, zero alloc after warm-up, deterministic pair order), pair
collection, QueryAabb and closest-hit Raycast. scene.UseCollisions()
registers CollisionSystem after movement systems.

30 new tests (string-map mazes, cost weighting, corner cutting, flow
descent; pair/mask/query/raycast). Sample gains a PathfindingScene
('path' console command): click to set the goal, 250 agents follow the
flow field, the A* path is highlighted, colliding agents flash red.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-06-11 13:39:28 +03:00
co-authored by Claude Fable 5
parent b3415120c3
commit a395e58458
20 changed files with 2053 additions and 2 deletions
+37
View File
@@ -35,6 +35,8 @@
| `MrGameEng.Assets.Generator` | Roslyn incremental source generator: классы с типизированными хендлами ресурсов |
| `MrGameEng.Atlases` | Текстурные атласы: офлайн-сборка из дерева картинок (`AtlasBuilder`) и рантайм-загрузка (`TextureAtlas`); CLI — `tools/MrGameEng.AtlasTool` |
| `MrGameEng.Tilemaps` | Тайловые карты, создаваемые кодом: `TileGrid` + `TileSet` + компонент `Tilemap`, отрисовка видимых клеток через батчер |
| `MrGameEng.Pathfinding` | Поиск пути по гриду: A*, Dijkstra, BFS и flow fields для толп; чистая логика без зависимостей |
| `MrGameEng.Collisions` | Определение столкновений: компонент `Collider`, spatial hash, пары/запросы/raycast |
| `MrGameEng.UI` | Игровой UI на [Myra](https://github.com/rds1983/Myra): `Desktop` на сцену, виджеты, скининг |
| `MrGameEng.DevConsole` | Ингейм-консоль разработчика: логи `Log`, команды, история, автодополнение |
@@ -183,6 +185,41 @@ CLI-обёртка: `dotnet run --project tools/MrGameEng.AtlasTool -- <исто
от экрана, а не от размера грида. Тайлы батчатся со спрайтами по обычному порядку
слой → depth → текстура: пол из одной текстуры атласа — один draw call.
## Поиск пути
`MrGameEng.Pathfinding` — алгоритмы поиска пути по гриду; зависит только от Core
и не владеет данными мира — игра реализует `IPathGrid` (Width/Height,
`IsPassable`, `Cost ≥ 1`) поверх своего рельефа или `TileGrid`.
- `GridPathfinder.FindPath(start, goal, path, algorithm)` — **A\*** (octile/Manhattan
эвристика), **Dijkstra** (с учётом цены клеток) и **BFS** (быстрейший для
равномерных гридов, цену игнорирует). Связность 4 или 8; диагонали никогда
не срезают углы.
- `FlowFieldBuilder.Build(goals, field)` — multi-source Dijkstra строит **flow field**:
дистанция + нормализованное направление на клетку. Толпа любого размера дальше
стоит O(1) на агента в кадр — основной инструмент для масс агентов (LittleSim).
- Оптимизация под ECS: все буферы созданы один раз под размер грида и
инвалидируются generation-штампом — повторные запросы не аллоцируют и не чистят
массивы. Один экземпляр на систему; результаты детерминированы.
## Коллизии
`MrGameEng.Collisions` — определение столкновений (без разрешения физики — она в бэклоге):
- Компонент `Collider` (`struct : IComponent`): круг или AABB (без вращения),
`Offset`, битовые маски `Layer`/`CollidesWith` (пара регистрируется, только если
маски согласны в обе стороны). Создание через `Collider.Circle(r)` / `Collider.Box(w,h)`.
- `CollisionWorld` — uniform spatial hash на плоских массивах (головы бакетов +
связные списки индексов), **перестраивается с нуля каждый тик** за O(n): для
движущихся сущностей это дешевле инкрементальных обновлений. Ноль аллокаций
после прогрева; порядок пар детерминирован (порядок чанков Friflo).
- `scene.UseCollisions(cellSize)` добавляет `CollisionSystem` — регистрируй её
**после** систем движения; системы, читающие `world.Pairs`, — после неё.
- Запросы для игровых систем: `Pairs` (пересекающиеся пары кадра),
`QueryAabb(rect, span)`, `Raycast(from, to, mask)` (ближайшее попадание).
- `cellSize` подбирается под типичный размер коллайдера; крупные коллайдеры
занимают несколько ячеек — корректность не страдает, страдает константа.
## Рендеринг
`SpriteBatch` в движке **не используется** — в `MrGameEng.Graphics` свой батчер,