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

4.4 KiB
Raw Blame History

План: Физика и динамика шайбы (M2)

Цель: Реализовать трение, потерю энергии при отскоках и порог остановки для шайбы.

Архитектура: Внедрение коэффициентов трения (Friction) и упругости (Restitution) в логику обновления мира. Использование простого множительного затухания скорости.

Стек: Go, Ebitengine (для контекста мира).

Спека: docs/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: Добавить константы в начало файла

const (
    PuckFriction    = 0.99 // Коэффициент трения (каждый кадр)
    PuckRestitution = 0.8  // Коэффициент упругости (при ударе о борт)
    PuckStopThreshold = 0.1 // Порог остановки
)
  • Шаг 2: Коммит
git add internal/game/world.go
git commit -m "phys: add physics constants"

Задача 2: Реализация трения и порога остановки

Файлы:

  • Изменить: internal/game/world.go

  • Шаг 1: Обновить World.Update для применения трения

В начале Update добавить:

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: Коммит
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:

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: Коммит
git add internal/game/world.go
git commit -m "phys: implement energy loss on bounce"

Задача 4: Тестирование физики

Файлы:

  • Создать: internal/game/world_test.go

  • Шаг 1: Написать тест на затухание скорости

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: Написать тест на отскок с потерей энергии
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: Коммит
git add internal/game/world_test.go
git commit -m "test: add physics tests"