feat(studio,stacking,animations,collections): M16 ModBison Studio, object stacking, model animations, and poly collections for MVP 2
checkpoint / checkpoint (push) Successful in 6m32s
checkpoint / checkpoint (push) Successful in 6m32s
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
class_name StudioSimulationManager
|
||||
extends Node
|
||||
## Manages Play / Run / Stop simulation harness for ModBison Studio.
|
||||
## Takes full state snapshot before play and restores on stop.
|
||||
|
||||
signal simulation_started(mode: String)
|
||||
signal simulation_stopped
|
||||
|
||||
enum SimulationState { EDIT, PLAYING, PAUSED }
|
||||
|
||||
var state: SimulationState = SimulationState.EDIT
|
||||
var _snapshot: Array[Dictionary] = []
|
||||
var _spawned_avatar: Node = null
|
||||
var _core: EditorCore = null
|
||||
var _world_container: Node3D = null
|
||||
|
||||
|
||||
func setup(core: EditorCore, world_container: Node3D = null) -> void:
|
||||
_core = core
|
||||
_world_container = world_container
|
||||
|
||||
|
||||
func start_play(spawn_player: bool = true) -> void:
|
||||
if state == SimulationState.PLAYING:
|
||||
return
|
||||
|
||||
# 1. Capture snapshot of all objects
|
||||
_capture_snapshot()
|
||||
|
||||
state = SimulationState.PLAYING
|
||||
|
||||
# 2. Spawn test avatar if requested
|
||||
if spawn_player and _world_container != null:
|
||||
_spawn_test_avatar()
|
||||
|
||||
# 3. Activate moving objects
|
||||
for m in _get_moving_nodes():
|
||||
if m.has_method("start_motion"):
|
||||
m.start_motion()
|
||||
|
||||
simulation_started.emit("play" if spawn_player else "run")
|
||||
|
||||
|
||||
func pause_simulation() -> void:
|
||||
if state != SimulationState.PLAYING:
|
||||
return
|
||||
state = SimulationState.PAUSED
|
||||
for m in _get_moving_nodes():
|
||||
if m.has_method("stop_motion"):
|
||||
m.stop_motion()
|
||||
|
||||
|
||||
func resume_simulation() -> void:
|
||||
if state != SimulationState.PAUSED:
|
||||
return
|
||||
state = SimulationState.PLAYING
|
||||
for m in _get_moving_nodes():
|
||||
if m.has_method("start_motion"):
|
||||
m.start_motion()
|
||||
|
||||
|
||||
func stop_simulation() -> void:
|
||||
if state == SimulationState.EDIT:
|
||||
return
|
||||
|
||||
# 1. Stop all moving objects
|
||||
for m in _get_moving_nodes():
|
||||
if m.has_method("stop_motion"):
|
||||
m.stop_motion()
|
||||
|
||||
# 2. Despawn test avatar
|
||||
if _spawned_avatar != null and is_instance_valid(_spawned_avatar):
|
||||
_spawned_avatar.queue_free()
|
||||
_spawned_avatar = null
|
||||
|
||||
# 3. Restore state snapshot
|
||||
_restore_snapshot()
|
||||
|
||||
state = SimulationState.EDIT
|
||||
simulation_stopped.emit()
|
||||
|
||||
|
||||
func _get_moving_nodes() -> Array:
|
||||
if is_inside_tree() and get_tree() != null:
|
||||
return get_tree().get_nodes_in_group("moving_objects")
|
||||
var main_loop = Engine.get_main_loop()
|
||||
if main_loop is SceneTree:
|
||||
return (main_loop as SceneTree).get_nodes_in_group("moving_objects")
|
||||
return []
|
||||
|
||||
|
||||
func _capture_snapshot() -> void:
|
||||
_snapshot.clear()
|
||||
if _core == null or _core.model == null:
|
||||
return
|
||||
for obj in _core.model.payload.objects:
|
||||
_snapshot.append({
|
||||
"id": obj.id,
|
||||
"position": obj.position,
|
||||
"rotation": obj.rotation,
|
||||
"scale": obj.scale,
|
||||
"properties": obj.properties.duplicate(true)
|
||||
})
|
||||
|
||||
|
||||
func _restore_snapshot() -> void:
|
||||
if _core == null or _core.model == null:
|
||||
return
|
||||
for snap in _snapshot:
|
||||
var obj = _core.model.find_object(snap["id"])
|
||||
if obj != null:
|
||||
obj.position = snap["position"]
|
||||
obj.rotation = snap["rotation"]
|
||||
obj.scale = snap["scale"]
|
||||
obj.properties = snap["properties"].duplicate(true)
|
||||
_snapshot.clear()
|
||||
|
||||
|
||||
func _spawn_test_avatar() -> void:
|
||||
var player_scene = load("res://scenes/player.tscn")
|
||||
if player_scene != null:
|
||||
var p = player_scene.instantiate()
|
||||
p.name = "TestStudioPlayer"
|
||||
p.position = Vector3(0, 2, 0)
|
||||
_world_container.add_child(p)
|
||||
_spawned_avatar = p
|
||||
else:
|
||||
var p: CharacterBody3D = CharacterBody3D.new()
|
||||
p.name = "TestStudioPlayer"
|
||||
p.position = Vector3(0, 2, 0)
|
||||
_world_container.add_child(p)
|
||||
_spawned_avatar = p
|
||||
|
||||
|
||||
func is_playing() -> bool:
|
||||
return state == SimulationState.PLAYING
|
||||
|
||||
|
||||
func is_editing() -> bool:
|
||||
return state == SimulationState.EDIT
|
||||
Reference in New Issue
Block a user