# План: Game Rules & Match Logic (M5) **Цель:** Реализовать систему судейства, подсчёт голов, таймер матча и управление состояниями игры (Playing, GoalPause, MatchEnded). **Архитектура:** Введение `MatchManager` в качестве верхнего уровня управления. Он владеет `World` и контролирует, когда физика и ИИ мира должны обновляться, а когда игра должна быть заморожена. **Стек:** Go. **Спека:** [docs/specs/2026-05-12-match-logic-design.md](../specs/2026-05-12-match-logic-design.md) --- ## Файловая структура - `internal/game/world.go` — добавление методов для проверки гола и сброса позиций. - `internal/game/match_manager.go` — новый файл с логикой управления матчем, счетом и таймерами. - `cmd/game/main.go` — замена `World` на `MatchManager` в основном цикле игры. --- ## Задачи ### Задача 1: Методы управления состоянием мира **Файлы:** - Изменить: `internal/game/world.go` - [ ] **Шаг 1: Реализовать `CheckGoal()`** - Метод должен проверять `Puck.Position.X`. - Если `X < 0` $\rightarrow$ возвращает `(entities.TeamBlue, true)`. - Если `X > WorldWidth` $\rightarrow$ возвращает `(entities.TeamRed, true)`. - Иначе $\rightarrow$ `(entities.TeamRed, false)`. - [ ] **Шаг 2: Реализовать `ResetPositions()`** - Установить `Puck.Position` в центр поля, `Puck.Velocity = 0`. - Для каждого игрока в `Players` установить `Position = HomePosition` и `Velocity = 0`. - [ ] **Шаг 3: Коммит** `git add internal/game/world.go && git commit -m "feat(game): add CheckGoal and ResetPositions to World"` ### Задача 2: Реализация MatchManager **Файлы:** - Создать: `internal/game/match_manager.go` - [ ] **Шаг 1: Определить типы и структуру** - `GameState` (enum: `Playing`, `GoalPause`, `MatchEnded`). - `MatchManager` структура: - `World *World` - `State GameState` - `ScoreRed, ScoreBlue int` - `MatchDuration float64` (в секундах) - `CurrentTime float64` - `PauseDuration float64` - `PauseTimer float64` - [ ] **Шаг 2: Реализовать `Update(dt float64)`** - Логика переключения состояний: - Если `Playing`: - Проверить `World.CheckGoal()`. Если гол $\rightarrow$ `State = GoalPause`, обновить счет, `PauseTimer = PauseDuration`. - Если не гол $\rightarrow$ вызвать `World.Update(dt)`. - Обновить `CurrentTime += dt`. Если `CurrentTime >= MatchDuration` $\rightarrow$ `State = MatchEnded`. - Если `GoalPause`: - `PauseTimer -= dt`. - Если `PauseTimer <= 0` $\rightarrow$ вызвать `World.ResetPositions()`, `State = Playing`. - Если `MatchEnded`: - Ничего не делать. - [ ] **Шаг 3: Коммит** `git add internal/game/match_manager.go && git commit -m "feat(game): implement MatchManager for game rules"` ### Задача 3: Интеграция в Main Loop **Файлы:** - Изменить: `cmd/game/main.go` - [ ] **Шаг 1: Обновить структуру `Game`** - Заменить `world *game.World` на `matchManager *game.MatchManager`. - [ ] **Шаг 2: Обновить инициализацию в `NewGame()`** - Создать `world := game.NewWorld()`. - Создать `matchManager := game.NewMatchManager(world)`. - [ ] **Шаг 3: Обновить `Update()` и `Draw()`** - В `Update()` вызывать `g.matchManager.Update(dt)`. - В `Draw()` передавать `g.matchManager.World` в функцию отрисовки. - [ ] **Шаг 4: Коммит** `git add cmd/game/main.go && git commit -m "feat(game): integrate MatchManager into main loop"` ### Задача 4: Тестирование и верификация - [ ] **Шаг 1: Проверка сценария "Гол"** - Запустить игру, забить гол. - Ожидание: Игра замирает, через несколько секунд все возвращаются в центр. - [ ] **Шаг 2: Проверка сценария "Конец матча"** - Установить короткий `MatchDuration` (например, 10 сек). - Ожидание: Через 10 секунд игра замирает навсегда. - [ ] **Шаг 3: Коммит** `git commit -m "test(game): verify match logic flow"`