Debug view improvements, warp animation

* Add a visible frame one tile beyond the normal screen in debug mode.

* Fix the display of motion paths for mounted traps in debug mode.

* Add an animation for the warp trap.
This commit is contained in:
James Campbell
2026-07-22 11:56:21 -04:00
parent d84e4627c3
commit 59e4bcce1c
8 changed files with 249 additions and 41 deletions

View File

@@ -131,6 +131,30 @@ def test_window_sized_once_for_tallest_level(make_game, tmp_path, monkeypatch):
assert g.win_h == 4 * 32 + HUD_H
def test_debug_view_adds_overscan_margin(tmp_path):
from game.game import Game, HUD_H
from game import settings as S
p = tmp_path / "d.yaml"
p.write_text("name: t\ntile_size: 32\ndebug: true\nmap: |\n #####\n #P.G#\n #####\n")
g = Game([str(p)], str(tmp_path / "noassets"))
m = S.DEBUG_VIEW_MARGIN * 32
assert m > 0
# the level draws shifted into an enlarged play surface...
assert g.level.render_offset == (m, m)
assert g.world.get_size() == (g.level.width + 2 * m, g.level.height + 2 * m)
# ...and the fixed window budgeted the margin so it isn't clipped.
assert g.win_h == g.level.height + 2 * m + HUD_H
def test_no_overscan_without_debug(tmp_path):
from game.game import Game
p = tmp_path / "n.yaml"
p.write_text("name: t\ntile_size: 32\nmap: |\n #####\n #P.G#\n #####\n")
g = Game([str(p)], str(tmp_path / "noassets"))
assert g.level.render_offset == (0, 0)
assert g.world.get_size() == (g.level.width, g.level.height)
def test_battery_visual_scales_by_pct(make_level):
lvl = make_level(SIMPLE + "battery_pct: 4\n")
assert lvl.battery_pct == 4

View File

@@ -163,6 +163,41 @@ traps:
assert warped
def test_warp_flash_pulses_and_fades(make_game):
g = make_game("""
name: t
tile_size: 32
map: |
##########
#.......G#
#P.......#
##########
traps:
- type: warp
at: [4, 2]
to: [7, 1]
""")
warp = g.level.traps[0]
assert warp._pulse == 0.0 # dormant: no aura
place(g, 4, 2) # stand on the warp tile
step(g) # -> teleports, aura flashes on
assert warp._pulse > 0.9
# The aura paints at BOTH the source and the destination — even though the
# warp is invisible and we're not in debug.
a = AssetStore("noassets")
surf = pygame.Surface((g.level.width, g.level.height))
surf.fill((0, 0, 0))
warp.render(surf, a)
assert surf.get_at(warp.base_rect.center)[:3] != (0, 0, 0)
assert surf.get_at(warp._dest_rect().center)[:3] != (0, 0, 0)
# It quickly fades back to nothing within the pulse window.
for _ in range(int(warp._PULSE_TIME / DT) + 2):
step(g)
assert warp._pulse == 0.0
# --- phase block -------------------------------------------------------------
def test_phase_block_intangible_until_triggered(make_game):
g = make_game("""
@@ -304,6 +339,24 @@ traps:
assert pb.alpha == 1.0 and pb.solid # snapped fully visible for the freeze
def test_debug_overscan_reveals_offmap_trap(make_level):
# In debug the play surface is enlarged and shifted (render_offset) so a trap
# placed just off the map is drawn into the overscan instead of being clipped.
from game import settings as S
lvl = make_level(
"name: t\ntile_size: 32\ndebug: true\nmap: |\n #####\n #...#\n #####\n"
"traps:\n - type: block\n at: [5, 1]\n deadly: true\n") # col 5 = off-map
a = AssetStore("noassets")
m = S.DEBUG_VIEW_MARGIN * lvl.tile
lvl.render_offset = (m, m)
surf = pygame.Surface((lvl.width + 2 * m, lvl.height + 2 * m))
surf.fill((0, 0, 0))
lvl.draw(surf, a)
cx = 5 * lvl.tile + m + lvl.tile // 2
cy = 1 * lvl.tile + m + lvl.tile // 2
assert surf.get_at((cx, cy))[:3] != (0, 0, 0) # off-map block painted in overscan
# --- generic invisible flag --------------------------------------------------
def test_invisible_flag_on_any_trap(make_level):
lvl = make_level("""