Add missing stickman placeholder and stage scene I/O functionality
- Implemented `MissingStickmanPlaceholder` class to visually indicate missing stickman assets in the scene. - Created `StageSceneIO` class for handling JSON serialization and deserialization of stage documents, including encoding and decoding of actions and rules. - Added tests for vector handling, rule encoding/decoding, safe file writing, root validation, and handling of missing assets. - Introduced a new stickman asset file `bad.stk` for testing purposes. - Enhanced test coverage for phase 5 file features, ensuring robust handling of scene data and missing assets.
This commit is contained in:
+48
-23
@@ -127,18 +127,60 @@ func spawn(id: String, world_position: Vector2) -> Node2D:
|
||||
var pos := world_position + offset
|
||||
match String(entry.get("kind", "")):
|
||||
"terrain":
|
||||
return _spawn_terrain(entry, pos)
|
||||
return spawn_terrain_asset(id, pos)
|
||||
"prop":
|
||||
return _spawn_prop(entry, pos)
|
||||
return spawn_prop_asset(selected_prop_id, pos)
|
||||
"stickman":
|
||||
return _spawn_stickman(pos)
|
||||
return spawn_stickman_asset(selected_stickman_path, pos)
|
||||
"area":
|
||||
return _spawn_area(pos)
|
||||
return spawn_area(pos)
|
||||
_:
|
||||
push_warning("StageSpawner: unknown spawn kind '%s'." % entry.get("kind", ""))
|
||||
return null
|
||||
|
||||
|
||||
## Load-safe factories take real object origins and never apply palette offsets.
|
||||
func spawn_terrain_asset(asset_id: String, object_position: Vector2) -> TerrainBlock:
|
||||
var entry := _find_entry(asset_id)
|
||||
if entry.is_empty() or String(entry.get("kind", "")) != "terrain":
|
||||
push_warning("StageSpawner: unknown terrain '%s'." % asset_id)
|
||||
return null
|
||||
return _spawn_terrain(entry, object_position)
|
||||
|
||||
|
||||
func spawn_prop_asset(asset_id: String, object_position: Vector2) -> PropBlock:
|
||||
var template: Dictionary = PROP_LIBRARY.get_entry(asset_id)
|
||||
if template.is_empty():
|
||||
push_warning("StageSpawner: unknown prop '%s'." % asset_id)
|
||||
return null
|
||||
var prop: PropBlock = PROP_UTILS.spawn_prop(_world, object_position, template["payload"], int(template["material_preset"]), Vector2.ZERO)
|
||||
prop.spawn_id = asset_id
|
||||
return prop
|
||||
|
||||
|
||||
func spawn_stickman_asset(stk_path: String, root_position: Vector2) -> StickmanRig:
|
||||
var normalized := stk_path
|
||||
var data: Dictionary = _stickman_cache.get(normalized, {})
|
||||
if data.is_empty():
|
||||
data = STICKMAN_FACTORY.load_stk(normalized)
|
||||
_stickman_cache[normalized] = data
|
||||
if data.is_empty():
|
||||
push_warning("StageSpawner: no stickman data for '%s'." % normalized)
|
||||
return null
|
||||
var rig: StickmanRig = STICKMAN_FACTORY.spawn_from_data(data)
|
||||
if rig == null:
|
||||
push_warning("StageSpawner: failed to spawn stickman.")
|
||||
return null
|
||||
rig.position = root_position
|
||||
rig.source_stk_path = normalized
|
||||
_world.add_child(rig)
|
||||
return rig
|
||||
|
||||
|
||||
func spawn_area(object_position: Vector2) -> TriggerArea:
|
||||
return _spawn_area(object_position) as TriggerArea
|
||||
|
||||
|
||||
## World-space AABB for a spawnable node: union of the Polygon2D child's world
|
||||
## points; for a stickman rig, union of its mounted `Body/*` shape geometry; a
|
||||
## point rect otherwise.
|
||||
@@ -257,11 +299,7 @@ func _spawn_terrain(entry: Dictionary, world_position: Vector2) -> TerrainBlock:
|
||||
|
||||
|
||||
func _spawn_prop(entry: Dictionary, world_position: Vector2) -> PropBlock:
|
||||
var t: Dictionary = PROP_LIBRARY.get_entry(selected_prop_id)
|
||||
if t.is_empty():
|
||||
push_warning("StageSpawner: unknown selected prop '%s'." % selected_prop_id)
|
||||
return null
|
||||
return PROP_UTILS.spawn_prop(_world, world_position, t["payload"], int(t["material_preset"]), Vector2.ZERO)
|
||||
return spawn_prop_asset(String(entry.get("id", selected_prop_id)), world_position)
|
||||
|
||||
|
||||
func _spawn_area(world_position: Vector2) -> Node2D:
|
||||
@@ -273,20 +311,7 @@ func _spawn_area(world_position: Vector2) -> Node2D:
|
||||
|
||||
|
||||
func _spawn_stickman(world_position: Vector2) -> StickmanRig:
|
||||
var data: Dictionary = _stickman_cache.get(selected_stickman_path, {})
|
||||
if data.is_empty():
|
||||
data = STICKMAN_FACTORY.load_stk(selected_stickman_path)
|
||||
_stickman_cache[selected_stickman_path] = data
|
||||
if data.is_empty():
|
||||
push_warning("StageSpawner: no stickman data for '%s'." % selected_stickman_path)
|
||||
return null
|
||||
var rig: StickmanRig = STICKMAN_FACTORY.spawn_from_data(data)
|
||||
if rig == null:
|
||||
push_warning("StageSpawner: failed to spawn stickman.")
|
||||
return null
|
||||
rig.position = world_position
|
||||
_world.add_child(rig)
|
||||
return rig
|
||||
return spawn_stickman_asset(selected_stickman_path, world_position)
|
||||
|
||||
|
||||
static func _points_center(pts: PackedVector2Array) -> Vector2:
|
||||
|
||||
Reference in New Issue
Block a user