#@icon("") @tool class_name ActManager extends Node ##ActManager里记录了一系列的ActID和对应的Act,主要用来同步场景的Act,比如,我们现在使用ActID = 0的Act,那么就会让所有的Act的状态重置回到ActID = 0的Act的状态 @export var prop_state_map: Dictionary[int, Act] = {} ##用于生成一个基础的Act的工具按钮 @export_tool_button("Generate Default Act") var _gen_default_act: Callable = Callable(self, "_editor_generate_default_act") ##用于生成一个Empty的工具按钮 @export_tool_button("Generate Empty Act") var _gen_empty_act: Callable = Callable(self, "_editor_generate_empty_act") ##是否要输出报错信息 @export var debug_log: bool = false ##关卡的初始Act,默认Clamp到Act的数量,防止出现错误 @export var init_act_id: int = 0: set(value): var max_index := max(prop_state_map.size() - 1, 0) init_act_id = clamp(value, 0, max_index) ## ==================== ## Private Field ## ==================== var _current_act: Act = null var _current_act_id: int = -1 const DEFAULT_ACT_ID:int = 0 signal act_changed(from_act_id: int, to_act_id: int) func _ready() -> void: pass ##通过ID切换act func switch_act_with_id(act_id: int) -> void: if not prop_state_map.has(act_id): push_warning("[ActManager] Act id not found: %d" % act_id) return var act := prop_state_map[act_id] _switch_act_internal(act, act_id) ##内部通过ID和Act来切换状态 func _switch_act_internal(act: Act, act_id: int) -> void: if act == null: return var from_id := _current_act_id _current_act = act _current_act_id = act_id for pid in act.prop_state_map.keys(): var single := act.prop_state_map[pid] if single == null: continue var prop := _find_prop_by_id(pid) if prop == null: continue prop.change_state(single.state_id, single.use_trans) emit_signal("act_changed", from_id, act_id) ##用来扫描prop func _scan_scene_for_props(scene_root: Node) -> Dictionary: var result := {} if scene_root == null: return result _scan_node_recursive(scene_root, result) return result ##递归扫描 func _scan_node_recursive(node: Node, out: Dictionary) -> void: if node is PropComponent: var prop := node as PropComponent if out.has(prop.prop_id): push_warning( "[ActManagerInspector] Duplicate prop_id: %d (%s)" % [prop.prop_id, node.get_path()] ) else: out[prop.prop_id] = { "node": prop, "path": node.get_path() } for child in node.get_children(): _scan_node_recursive(child, out) ##生成一个默认的Act func _editor_generate_default_act() -> void: if not Engine.is_editor_hint(): return var scene := _get_owner_scene() if scene == null: _editor_popup( "ActManager must be a child of ReedScene.", "Generate Default Act - Failed" ) return var props_root := scene.get_props_root() if props_root == null: _editor_popup( "Props root not found:\n%s" % scene.props_root_path, "Generate Default Act - Failed" ) return var act := Act.new() act.prop_state_map.clear() var count := 0 for prop_node in props_root.get_children(): if not prop_node is Node: continue var prop_comp := _find_prop_component_top(prop_node) if prop_comp == null: continue var pid := prop_comp.prop_id var init_state := prop_comp.initial_state_id var single := SingleAct.new() single.state_id = init_state act.prop_state_map[pid] = single count += 1 prop_state_map[0] = act notify_property_list_changed() _editor_popup( "Default Act generated successfully.\n\nProp count: %d\nAct ID: 0" % count, "Generate Default Act - Success" ) if debug_log: print("[ActManager][Editor] Generated Default Act with", count, "props.") ##生成一个空的Act func _editor_generate_empty_act() -> void: if not Engine.is_editor_hint(): return var act := Act.new() act.prop_state_map.clear() # 明确强调“空 Act” var act_id := _find_next_free_act_id() prop_state_map[act_id] = act notify_property_list_changed() _editor_popup( "Empty Act generated successfully.\n\nAct ID: %d\nProp count: 0" % act_id, "Generate Empty Act - Success" ) if debug_log: print("[ActManager][Editor] Generated EMPTY Act with id =", act_id) ## ============================== ## 工具函数 ## ============================== func _editor_popup(message: String, title: String = "ActManager") -> void: if not Engine.is_editor_hint(): return var dialog := AcceptDialog.new() dialog.title = title dialog.dialog_text = message get_tree().root.add_child(dialog) dialog.popup_centered() ##找到场景scene节点 func _get_owner_scene() -> ReedScene: var p := get_parent() if p is ReedScene: return p as ReedScene return null ##找到PropComp func _find_prop_component_top(prop: Node) -> PropComponent: for child in prop.get_children(): if child is PropComponent: return child as PropComponent return null ##找到最近的空位ActID func _find_next_free_act_id() -> int: var id := 0 while prop_state_map.has(id): id += 1 return id ##通过ID寻找Prop func _find_prop_by_id(prop_id: int) -> PropComponent: var scene := _get_owner_scene() if scene == null: return null var props_root := scene.get_props_root() if props_root == null: return null return _find_prop_recursive(props_root, prop_id) ##递归的寻找Prop func _find_prop_recursive(node: Node, prop_id: int) -> PropComponent: if node is PropComponent and node.prop_id == prop_id: return node as PropComponent for child in node.get_children(): var r := _find_prop_recursive(child, prop_id) if r != null: return r return null