Files
football/docs/plans/2026-05-08-physics-dynamics.md
2026-05-12 10:54:09 +03:00

147 lines
4.4 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.

# План: Физика и динамика шайбы (M2)
**Цель:** Реализовать трение, потерю энергии при отскоках и порог остановки для шайбы.
**Архитектура:** Внедрение коэффициентов трения (`Friction`) и упругости (`Restitution`) в логику обновления мира. Использование простого множительного затухания скорости.
**Стек:** Go, Ebitengine (для контекста мира).
**Спека:** [docs/specs/2026-05-08-physics-dynamics-design.md](../specs/2026-05-08-physics-dynamics-design.md)
---
## Файловая структура
- `internal/game/world.go` — добавление констант физики и обновление логики `Update`.
- `internal/game/world_test.go` — новые unit-тесты для проверки затухания скорости и потерь при отскоках.
---
## Задачи
### Задача 1: Константы физики
**Файлы:**
- Изменить: `internal/game/world.go`
- [ ] **Шаг 1: Добавить константы в начало файла**
```go
const (
PuckFriction = 0.99 // Коэффициент трения (каждый кадр)
PuckRestitution = 0.8 // Коэффициент упругости (при ударе о борт)
PuckStopThreshold = 0.1 // Порог остановки
)
```
- [ ] **Шаг 2: Коммит**
```bash
git add internal/game/world.go
git commit -m "phys: add physics constants"
```
### Задача 2: Реализация трения и порога остановки
**Файлы:**
- Изменить: `internal/game/world.go`
- [ ] **Шаг 1: Обновить `World.Update` для применения трения**
В начале `Update` добавить:
```go
w.puck.Velocity.X *= PuckFriction
w.puck.Velocity.Y *= PuckFriction
if math.Abs(w.puck.Velocity.X) < PuckStopThreshold {
w.puck.Velocity.X = 0
}
if math.Abs(w.puck.Velocity.Y) < PuckStopThreshold {
w.puck.Velocity.Y = 0
}
```
- [ ] **Шаг 2: Коммит**
```bash
git add internal/game/world.go
git commit -m "phys: implement puck friction and stop threshold"
```
### Задача 3: Реализация потерь при отскоках
**Файлы:**
- Изменить: `internal/game/world.go`
- [ ] **Шаг 1: Обновить логику отскоков в `World.Update`**
Заменить инверсию скорости на инверсию с множителем `PuckRestitution`.
Пример для X:
```go
if w.puck.X - w.puck.Radius <= 0 || w.puck.X + w.puck.Radius >= float64(screenWidth) {
w.puck.Velocity.X = -w.puck.Velocity.X * PuckRestitution
// Добавить коррекцию позиции, чтобы не застрять в стене
if w.puck.X - w.puck.Radius < 0 {
w.puck.X = w.puck.Radius
} else if w.puck.X + w.puck.Radius > float64(screenWidth) {
w.puck.X = float64(screenWidth) - w.puck.Radius
}
}
```
Аналогично для Y.
- [ ] **Шаг 2: Коммит**
```bash
git add internal/game/world.go
git commit -m "phys: implement energy loss on bounce"
```
### Задача 4: Тестирование физики
**Файлы:**
- Создать: `internal/game/world_test.go`
- [ ] **Шаг 1: Написать тест на затухание скорости**
```go
func TestPuckFriction(t *testing.T) {
w := NewWorld()
w.puck.Velocity = Vector2{X: 10, Y: 0}
w.Update()
if w.puck.Velocity.X >= 10 {
t.Errorf("Expected velocity to decrease due to friction, got %f", w.puck.Velocity.X)
}
}
```
- [ ] **Шаг 2: Написать тест на отскок с потерей энергии**
```go
func TestPuckBounceLoss(t *testing.T) {
w := NewWorld()
w.puck.X = 1 // Почти у левого края
w.puck.Velocity = Vector2{X: -10, Y: 0}
w.Update()
expected := 10 * PuckRestitution
if math.Abs(w.puck.Velocity.X - expected) > 0.001 {
t.Errorf("Expected velocity after bounce to be %f, got %f", expected, w.puck.Velocity.X)
}
}
```
- [ ] **Шаг 3: Запустить тесты**
`go test ./internal/game/ -v`
- [ ] **Шаг 4: Коммит**
```bash
git add internal/game/world_test.go
git commit -m "test: add physics tests"
```