Files
pygame-physics-opus5.5/tests/interaction/test_velocity_tracker.py
T
2026-09-24 15:45:31 +02:00

76 lines
2.7 KiB
Python

"""Tests der geglätteten Wurfgeschwindigkeit."""
import random
import pytest
from sandbox.interaction import VelocityTracker
from sandbox.physics import Vector2
WINDOW = 0.1
SMOOTHING = 0.05
def _track(velocity: Vector2, fps: float, seconds: float) -> VelocityTracker:
"""Bewegt einen Zeiger mit konstanter Geschwindigkeit und liefert den Tracker."""
tracker = VelocityTracker(WINDOW, SMOOTHING)
tracker.reset(0.0, Vector2(0, 0))
frames = round(seconds * fps)
for frame in range(1, frames + 1):
t = frame / fps
tracker.add_sample(t, velocity * t)
return tracker
def test_constant_motion_is_measured_exactly() -> None:
tracker = _track(Vector2(600, -200), fps=60, seconds=0.5)
assert tracker.velocity.is_close(Vector2(600, -200), tolerance=1.0)
def test_result_does_not_depend_on_the_frame_rate() -> None:
slow = _track(Vector2(500, 0), fps=30, seconds=0.5)
fast = _track(Vector2(500, 0), fps=144, seconds=0.5)
assert slow.velocity.x == pytest.approx(fast.velocity.x, rel=0.01)
def test_velocity_decays_when_the_pointer_stops() -> None:
tracker = _track(Vector2(800, 0), fps=60, seconds=0.3)
resting = Vector2(800 * 0.3, 0)
for frame in range(1, 31): # eine halbe Sekunde stillhalten
tracker.add_sample(0.3 + frame / 60, resting)
if frame == 12: # nach 0,2 s ist der Schwung auf wenige Prozent abgeklungen
assert tracker.velocity.length() < 0.1 * 800
assert tracker.velocity.length() < 1.0
def test_jitter_is_smoothed() -> None:
rng = random.Random(0)
tracker = VelocityTracker(WINDOW, SMOOTHING)
tracker.reset(0.0, Vector2(0, 0))
for frame in range(1, 61):
t = frame / 60
noise = Vector2(rng.uniform(-3, 3), rng.uniform(-3, 3)) # zittrige Hand
tracker.add_sample(t, Vector2(400 * t, 0) + noise)
assert tracker.velocity.x == pytest.approx(400, rel=0.1)
assert abs(tracker.velocity.y) < 60
def test_samples_with_the_same_timestamp_replace_each_other() -> None:
tracker = VelocityTracker(WINDOW, SMOOTHING)
tracker.reset(0.0, Vector2(0, 0))
tracker.add_sample(0.0, Vector2(50, 0)) # gleicher Frame: keine Division durch 0
assert tracker.velocity == Vector2(0, 0)
tracker.add_sample(0.1, Vector2(50, 0))
assert tracker.velocity.x == 0 # die ersetzte Position ist der neue Bezugspunkt
def test_first_sample_without_reset_starts_a_measurement() -> None:
tracker = VelocityTracker(WINDOW, SMOOTHING)
tracker.add_sample(1.0, Vector2(5, 5))
assert tracker.velocity == Vector2(0, 0)
def test_invalid_parameters_are_rejected() -> None:
with pytest.raises(ValueError, match="positiv"):
VelocityTracker(0, SMOOTHING)