fix(ui): render LOS boundary wall tiles through fog without marking explored (#585)
- game_state.gd: add boundary_positions Dictionary field; BoundaryWall tiles from visible_tiles go to boundary_positions instead of visible_positions — rendered by tile_renderer but not tracked as explored fog memory - fog_state.gd: update_from_state() writes VIS_FORWARD for boundary_positions so fog lifts over margin wall content; boundary tiles excluded from exploration step so they don't persist as EXP_EXPLORED when player turns away - tile_renderer.gd: no changes needed — renders all visible_tiles by type, sector-agnostic - test_fog_shader.gd: 4 new tests — boundary excluded from visible_positions, tracked in boundary_positions, cleared each snapshot, fog lifts to VIS_FORWARD Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -268,6 +268,79 @@ func test_game_state_visible_positions_cleared_on_new_snapshot() -> void:
|
||||
assert_that(GameState.visible_positions.has(Vector2i(10, 10))).is_true()
|
||||
|
||||
|
||||
# -- #585: BoundaryWall tiles — visible in fog, not persistently explored ------
|
||||
|
||||
func test_boundary_wall_tiles_not_in_visible_positions() -> void:
|
||||
## #585: BoundaryWall margin tiles must NOT enter visible_positions.
|
||||
## They are rendered via tile_renderer (from visible_tiles) but must not
|
||||
## update the player's fog exploration memory.
|
||||
GameState.apply_snapshot({
|
||||
"tick": 1,
|
||||
"visible_tiles": [
|
||||
{"x": 5, "y": 5, "z": 0, "visibility": "Forward"},
|
||||
{"x": 6, "y": 5, "z": 0, "visibility": "BoundaryWall"},
|
||||
],
|
||||
})
|
||||
assert_that(GameState.visible_positions.has(Vector2i(5, 5))).is_true()
|
||||
assert_that(GameState.visible_positions.has(Vector2i(6, 5))).is_false()
|
||||
assert_that(GameState.boundary_positions.has(Vector2i(6, 5))).is_true()
|
||||
|
||||
|
||||
func test_boundary_wall_tiles_in_visibility_sectors() -> void:
|
||||
## BoundaryWall visibility sector is still tracked in visibility_sectors
|
||||
## (for potential future use — wall coloring, etc.)
|
||||
GameState.apply_snapshot({
|
||||
"tick": 1,
|
||||
"visible_tiles": [
|
||||
{"x": 3, "y": 3, "z": 0, "visibility": "BoundaryWall"},
|
||||
],
|
||||
})
|
||||
assert_that(GameState.visibility_sectors.has(Vector2i(3, 3))).is_true()
|
||||
assert_that(GameState.visibility_sectors[Vector2i(3, 3)]).is_equal("BoundaryWall")
|
||||
|
||||
|
||||
func test_boundary_positions_cleared_on_new_snapshot() -> void:
|
||||
## BoundaryWall positions are cleared each snapshot so stale walls don't persist.
|
||||
GameState.apply_snapshot({
|
||||
"tick": 1,
|
||||
"visible_tiles": [{"x": 7, "y": 7, "z": 0, "visibility": "BoundaryWall"}],
|
||||
})
|
||||
assert_that(GameState.boundary_positions.has(Vector2i(7, 7))).is_true()
|
||||
GameState.apply_snapshot({
|
||||
"tick": 2,
|
||||
"visible_tiles": [{"x": 10, "y": 10, "z": 0, "visibility": "Forward"}],
|
||||
})
|
||||
assert_that(GameState.boundary_positions.has(Vector2i(7, 7))).is_false()
|
||||
assert_that(GameState.boundary_positions.size()).is_equal(0)
|
||||
|
||||
|
||||
func test_boundary_wall_fog_vis_forward() -> void:
|
||||
## #585: BoundaryWall tiles must lift fog (VIS_FORWARD = 255) so wall content composites.
|
||||
## visible_positions excludes boundary tiles; fog_state writes vis bytes for them separately.
|
||||
## Reads _vis_bytes directly (packed byte array) to avoid ImageTexture.get_image() lag.
|
||||
var fog_state = _get_fog_state()
|
||||
if fog_state == null:
|
||||
return
|
||||
GameState.apply_snapshot({
|
||||
"tick": 1,
|
||||
"visible_tiles": [
|
||||
{"x": 0, "y": 0, "z": 0, "visibility": "Forward"}, # normal LOS tile
|
||||
{"x": 1, "y": 0, "z": 0, "visibility": "BoundaryWall"}, # margin tile
|
||||
],
|
||||
})
|
||||
fog_state.update_from_state()
|
||||
var ox: int = fog_state.map_bounds.position.x
|
||||
var oy: int = fog_state.map_bounds.position.y
|
||||
var w: int = fog_state.map_bounds.size.x
|
||||
var vis: PackedByteArray = fog_state._vis_bytes
|
||||
var normal_idx: int = (0 - oy) * w + (0 - ox)
|
||||
var boundary_idx: int = (0 - oy) * w + (1 - ox)
|
||||
assert_int(vis[normal_idx]).is_equal(FogState.VIS_FORWARD) # normal tile: VIS_FORWARD
|
||||
assert_int(vis[boundary_idx]).is_equal(FogState.VIS_FORWARD) # boundary also fog-lifted
|
||||
GameState.visible_positions.clear()
|
||||
GameState.boundary_positions.clear()
|
||||
|
||||
|
||||
# -- Z-layer compliance (D-049) -----------------------------------------------
|
||||
|
||||
func test_fog_overlay_z_layer() -> void:
|
||||
|
||||
Reference in New Issue
Block a user