Files
football/docs/plans/2026-05-12-match-logic-impl.md
2026-05-12 10:54:09 +03:00

103 lines
4.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# План: 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"`