5.9 KiB
План: Тактический ИИ и Ролевая Логика (M4)
Цель: Реализовать роль Вратаря с логикой перекрытия углов и систему зонирования для нападающих и защитников.
Архитектура:
- Введение
RoleGoalieв перечисление ролей. - Реализация специализированного метода
updateGoalieAI, который вычисляет целевую точку на векторе «Центр ворот -> Шайба» с ограничением по радиусу. - Внедрение системы зон (Защитная, Средняя, Атакующая) для динамического изменения агрессивности игроков.
Стек: Go
Спека: docs/specs/2026-05-09-tactical-ai-design.md
Файловая структура
internal/entities/player.go— добавлениеRoleGoalie.internal/game/world.go— константы зон, логика ИИ вратаря и зонирования.internal/game/world_test.go— тесты на поведение вратаря и смену зон.
Задачи
Задача 1: Расширение ролей и константы зон
Файлы:
-
Изменить:
internal/entities/player.go -
Изменить:
internal/game/world.go -
Шаг 1: Добавить
RoleGoalieвPlayerRole
type PlayerRole int
const (
RoleStriker PlayerRole = iota
RoleDefender
RoleGoalie // Добавить это
)
- Шаг 2: Добавить константы зон в
world.go
const (
ZoneWidth = WorldWidth / 3
GoalieMaxDistance = 80.0 // Максимальный выход вратаря из ворот
)
- Шаг 3: Коммит
git add internal/entities/player.go internal/game/world.gogit commit -m "feat(ai): add RoleGoalie and zone constants"
Задача 2: Реализация ИИ Вратаря (Перехватчик)
Файлы:
-
Изменить:
internal/game/world.go -
Шаг 1: Реализовать
updateGoalieAIЛогика:
- Определить центр своих ворот (
GoalLeftилиGoalRight). - Вычислить вектор от центра ворот к шайбе.
- Целевая точка = Центр ворот + (Нормализованный вектор * min(дистанция_до_шайбы, GoalieMaxDistance)).
- Ограничить Y в пределах ворот (например, +/- 100 пикселей от центра).
func (w *World) updateGoalieAI(p *entities.Player, puckPos entities.Vector2D) entities.Vector2D {
goalPos := GoalLeft
if p.Team == TeamRight {
goalPos = GoalRight
}
// Вектор от ворот к шайбе
dir := puckPos.Sub(goalPos)
dist := dir.Len()
// Ограничиваем выход из ворот
moveDist := dist
if moveDist > GoalieMaxDistance {
moveDist = GoalieMaxDistance
}
target := goalPos.Add(dir.Normalize().Mul(moveDist))
// Ограничение по Y (чтобы не уходил за пределы ворот)
if target.Y < WorldCenterY-100 { target.Y = WorldCenterY-100 }
if target.Y > WorldCenterY+100 { target.Y = WorldCenterY+100 }
return target
}
- Шаг 2: Интегрировать в
updatePlayerAI
switch p.Role {
case entities.RoleGoalie:
target = w.updateGoalieAI(p, puckPos)
// ... остальные роли
}
- Шаг 3: Коммит
git commit -m "feat(ai): implement goalie interceptor logic"
Задача 3: Система зонирования для полевых игроков
Файлы:
-
Изменить:
internal/game/world.go -
Шаг 1: Реализовать определение зоны
func (w *World) getPlayerZone(p *entities.Player) int {
// 0: Защитная, 1: Средняя, 2: Атакующая
// Для TeamLeft: X < ZoneWidth (Защитная), X < 2*ZoneWidth (Средняя), else (Атакующая)
// Для TeamRight: X > 2*ZoneWidth (Защитная), X > ZoneWidth (Средняя), else (Атакующая)
if p.Team == TeamLeft {
if p.Pos.X < ZoneWidth { return 0 }
if p.Pos.X < 2*ZoneWidth { return 1 }
return 2
} else {
if p.Pos.X > 2*ZoneWidth { return 0 }
if p.Pos.X > ZoneWidth { return 1 }
return 2
}
}
-
Шаг 2: Обновить логику Striker и Defender с учетом зон
-
Striker: В зоне 0 (защитной) стремится к центру поля, в зоне 2 (атакующей) — агрессивно к шайбе.
-
Defender: В зоне 0 — агрессивно к шайбе, в зоне 2 — возвращается к своим воротам.
-
Шаг 3: Коммит
git commit -m "feat(ai): implement player zoning logic"
Задача 4: Тестирование и верификация
Файлы:
-
Изменить:
internal/game/world_test.go -
Шаг 1: Тест
TestWorld_GoaliePositioning -
Проверить, что вратарь TeamLeft при шайбе в центре поля стоит в районе
GoalLeftи не уходит дальшеGoalieMaxDistance. -
Проверить, что вратарь смещается вслед за шайбой по Y.
-
Шаг 2: Тест
TestWorld_ZoningBehavior -
Проверить, что защитник в атакующей зоне стремится вернуться назад.
-
Шаг 3: Запуск тестов
go test ./internal/game/ -v -
Шаг 4: Коммит
git commit -m "test(ai): add goalie and zoning tests"