103 lines
4.9 KiB
Markdown
103 lines
4.9 KiB
Markdown
# План: 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"`
|