feat(client): D-033 entity colors, peripheral dimming, facing indicator (#130)
Replace hardcoded entity colors with D-033 relationship palette: Player=#e0e8ff, Npc=unknown teal #4a9ebb, Object=grey #8b8ba0. Phase 1 defaults by entity kind; Phase 2 (#361) will derive color from RelationshipState via knowledge graph. Entities in peripheral vision dimmed to 50% alpha (D-015). Player entity gets a Polygon2D triangle indicator showing facing direction, rotated from GameState.player_facing. 82 tests total, 0 failures. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,11 @@ var _test_entities: Array = [
|
||||
{"entity_id": 2, "x": 7.0, "y": 5.0, "z": 0, "kind": {"variant": "Npc", "data": null}},
|
||||
]
|
||||
|
||||
var _test_entities_v2: Array = [
|
||||
{"entity_id": 1, "x": 5.0, "y": 5.0, "z": 0, "kind": {"variant": "Player", "data": null}, "visibility": "Forward"},
|
||||
{"entity_id": 2, "x": 7.0, "y": 5.0, "z": 0, "kind": {"variant": "Npc", "data": null}, "visibility": "Peripheral"},
|
||||
]
|
||||
|
||||
|
||||
# -- Constants --
|
||||
|
||||
@@ -72,6 +77,27 @@ func test_game_state_same_count_different_visibility_new_tick() -> void:
|
||||
assert_that(GameState.visible_positions.has(Vector2i(1, 1))).is_false()
|
||||
assert_that(GameState.visible_positions.has(Vector2i(2, 2))).is_true()
|
||||
|
||||
func test_game_state_stores_game_time() -> void:
|
||||
var gt := {"day": 1, "time_of_day": 720, "day_phase": "Evening", "paused": false}
|
||||
GameState.apply_snapshot({"tick": 1, "game_time": gt})
|
||||
assert_that(GameState.game_time.day).is_equal(1)
|
||||
assert_that(GameState.game_time.time_of_day).is_equal(720)
|
||||
|
||||
func test_game_state_stores_player_facing() -> void:
|
||||
GameState.apply_snapshot({"tick": 1, "player_facing": "Southeast"})
|
||||
assert_that(GameState.player_facing).is_equal("Southeast")
|
||||
|
||||
func test_game_state_derives_visible_positions_from_visible_tiles() -> void:
|
||||
var vtiles := [
|
||||
{"x": 5, "y": 5, "z": 0, "visibility": "Forward"},
|
||||
{"x": 6, "y": 5, "z": 0, "visibility": "Peripheral"},
|
||||
]
|
||||
GameState.apply_snapshot({"tick": 1, "visible_tiles": vtiles})
|
||||
assert_that(GameState.visible_positions.has(Vector2i(5, 5))).is_true()
|
||||
assert_that(GameState.visible_positions.has(Vector2i(6, 5))).is_true()
|
||||
assert_that(GameState.visibility_sectors[Vector2i(5, 5)]).is_equal("Forward")
|
||||
assert_that(GameState.visibility_sectors[Vector2i(6, 5)]).is_equal("Peripheral")
|
||||
|
||||
func test_game_state_warns_on_missing_player() -> void:
|
||||
GameState.player_entity_id = 999
|
||||
GameState.player_position = Vector2(5, 5)
|
||||
@@ -130,6 +156,20 @@ func test_sim_bridge_test_tiles_contain_all_types() -> void:
|
||||
assert_that(types.has("wall")).is_true()
|
||||
assert_that(types.has("door")).is_true()
|
||||
|
||||
func test_sim_bridge_test_snapshot_has_v2_fields() -> void:
|
||||
SimBridge._test_tick = 0
|
||||
var snap = SimBridge._test_snapshot()
|
||||
assert_that(snap.has("version")).is_true()
|
||||
assert_that(snap.version).is_equal(2)
|
||||
assert_that(snap.has("game_time")).is_true()
|
||||
assert_that(snap.has("player_facing")).is_true()
|
||||
assert_that(snap.has("visible_tiles")).is_true()
|
||||
assert_that(snap.visible_tiles.size()).is_greater(0)
|
||||
var vtile = snap.visible_tiles[0]
|
||||
assert_that(vtile.has("visibility")).is_true()
|
||||
# Entities should have visibility
|
||||
assert_that(snap.entities[0].has("visibility")).is_true()
|
||||
|
||||
|
||||
# -- EntityRenderer: lifecycle --
|
||||
|
||||
@@ -195,6 +235,64 @@ func test_entity_renderer_empty_entities_clears_all() -> void:
|
||||
renderer.queue_free()
|
||||
|
||||
|
||||
# -- EntityRenderer: D-033 colors and v2 features --
|
||||
|
||||
func test_entity_renderer_player_uses_d033_color() -> void:
|
||||
var renderer := _make_entity_renderer()
|
||||
renderer.update_entities(_test_entities_v2)
|
||||
var player_node = renderer.entity_nodes[1] as ColorRect
|
||||
assert_that(player_node.color).is_equal(Constants.ENTITY_COLOR_PLAYER)
|
||||
renderer.queue_free()
|
||||
|
||||
func test_entity_renderer_npc_uses_unknown_teal() -> void:
|
||||
var renderer := _make_entity_renderer()
|
||||
renderer.update_entities(_test_entities_v2)
|
||||
var npc_node = renderer.entity_nodes[2] as ColorRect
|
||||
assert_that(npc_node.color).is_equal(Constants.ENTITY_COLOR_UNKNOWN)
|
||||
renderer.queue_free()
|
||||
|
||||
func test_entity_renderer_object_uses_grey() -> void:
|
||||
var renderer := _make_entity_renderer()
|
||||
var obj := [{"entity_id": 3, "x": 1.0, "y": 1.0, "z": 0, "kind": {"variant": "Object", "data": null}, "visibility": "Forward"}]
|
||||
renderer.update_entities(obj)
|
||||
var node = renderer.entity_nodes[3] as ColorRect
|
||||
assert_that(node.color).is_equal(Constants.ENTITY_COLOR_OBJECT)
|
||||
renderer.queue_free()
|
||||
|
||||
func test_entity_renderer_peripheral_entity_dimmed() -> void:
|
||||
var renderer := _make_entity_renderer()
|
||||
renderer.update_entities(_test_entities_v2)
|
||||
var npc_node = renderer.entity_nodes[2]
|
||||
assert_that(npc_node.modulate.a).is_equal_approx(Constants.PERIPHERAL_ALPHA, 0.01)
|
||||
renderer.queue_free()
|
||||
|
||||
func test_entity_renderer_forward_entity_full_alpha() -> void:
|
||||
var renderer := _make_entity_renderer()
|
||||
renderer.update_entities(_test_entities_v2)
|
||||
var player_node = renderer.entity_nodes[1]
|
||||
assert_that(player_node.modulate.a).is_equal_approx(1.0, 0.01)
|
||||
renderer.queue_free()
|
||||
|
||||
func test_entity_renderer_player_has_facing_indicator() -> void:
|
||||
GameState.player_entity_id = 1
|
||||
var renderer := _make_entity_renderer()
|
||||
renderer.update_entities(_test_entities_v2)
|
||||
var player_node = renderer.entity_nodes[1]
|
||||
var indicator = player_node.get_node_or_null("FacingIndicator")
|
||||
assert_that(indicator != null).is_true()
|
||||
assert_that(indicator is Polygon2D).is_true()
|
||||
renderer.queue_free()
|
||||
|
||||
func test_entity_renderer_npc_has_no_facing_indicator() -> void:
|
||||
GameState.player_entity_id = 1
|
||||
var renderer := _make_entity_renderer()
|
||||
renderer.update_entities(_test_entities_v2)
|
||||
var npc_node = renderer.entity_nodes[2]
|
||||
var indicator = npc_node.get_node_or_null("FacingIndicator")
|
||||
assert_that(indicator == null).is_true()
|
||||
renderer.queue_free()
|
||||
|
||||
|
||||
# -- FogRenderer: position registration --
|
||||
|
||||
func _make_fog_renderer() -> TileMapLayer:
|
||||
|
||||
Reference in New Issue
Block a user