Mi2dRPGamEng/tests/test_aim.py

96 lines
3.0 KiB
Python

import math
import pytest
from engine.aim import apply_cone_deviation, snap_to_8way
from engine.camera import OrthoCamera
class FixedUniformRng:
def __init__(self, value: float):
self._value = value
def uniform(self, _a, _b):
return self._value
@pytest.mark.parametrize(
"dx,dy,expected",
[
(5, 0, (1, 0)),
(0, 5, (0, 1)),
(-5, 0, (-1, 0)),
(0, -5, (0, -1)),
(5, 5, (1, 1)),
(-5, 5, (-1, 1)),
(-5, -5, (-1, -1)),
(5, -5, (1, -1)),
(0, 0, (0, 1)),
(5, 0.1, (1, 0)), # nearly east, snaps to east not northeast
],
)
def test_snap_to_8way(dx, dy, expected):
assert snap_to_8way(dx, dy) == expected
def test_snap_to_8way_covers_full_circle():
for degrees in range(0, 360, 5):
radians = math.radians(degrees)
dx, dy = math.cos(radians), math.sin(radians)
dirx, diry = snap_to_8way(dx, dy)
assert (dirx, diry) != (0, 0)
assert abs(dirx) <= 1 and abs(diry) <= 1
def test_apply_cone_deviation_with_zero_cone_is_a_no_op():
assert apply_cone_deviation(1, 0, 0.0, FixedUniformRng(50.0)) == (1, 0)
def test_apply_cone_deviation_with_zero_deviation_keeps_direction():
assert apply_cone_deviation(1, 0, 30.0, FixedUniformRng(0.0)) == (1, 0)
def test_apply_cone_deviation_can_shift_to_an_adjacent_direction():
# east (1,0) deviated by +40 degrees should snap to northeast (1,1) -> y-down world,
# so a positive angle rotates toward (0,1)/south side
result = apply_cone_deviation(1, 0, 90.0, FixedUniformRng(40.0))
assert result != (1, 0)
assert abs(result[0]) <= 1 and abs(result[1]) <= 1
def test_apply_cone_deviation_stays_within_grid_directions():
rng = FixedUniformRng(179.0)
for base_dx, base_dy in [(1, 0), (0, 1), (-1, 0), (0, -1)]:
dirx, diry = apply_cone_deviation(base_dx, base_dy, 20.0, rng)
assert (dirx, diry) != (0, 0)
def test_screen_to_world_center_of_viewport_is_camera_target():
camera = OrthoCamera(viewport_w=800, viewport_h=600, tiles_visible_y=12.0)
camera.set_target(5.0, 5.0)
wx, wy = camera.screen_to_world(400, 300)
assert wx == pytest.approx(5.0, abs=0.05)
assert wy == pytest.approx(5.0, abs=0.05)
def test_screen_to_world_top_left_is_up_and_left_of_target():
camera = OrthoCamera(viewport_w=800, viewport_h=600, tiles_visible_y=12.0)
camera.set_target(5.0, 5.0)
wx, wy = camera.screen_to_world(0, 0)
assert wx < 5.0
assert wy < 5.0
def test_screen_to_world_round_trips_with_scale_offset():
camera = OrthoCamera(viewport_w=800, viewport_h=600, tiles_visible_y=12.0)
camera.set_target(3.0, 7.0)
(scale_x, scale_y), (offset_x, offset_y) = camera.scale_offset()
wx, wy = camera.screen_to_world(200, 450)
ndc_x = wx * scale_x + offset_x
ndc_y = wy * scale_y + offset_y
# (200,450) in an 800x600 viewport -> ndc (-0.5, -0.5) in the y-up NDC space
assert ndc_x == pytest.approx(-0.5, abs=1e-6)
assert ndc_y == pytest.approx(-0.5, abs=1e-6)