'''此类为Prop的管理组件类,任何的Prop,其至少需要在此类的最上层的子层添加该组件 该管理器,在添加入Tree时,会自动的添加一个States节点作为其所有state的root, 并且添加一个默认的state作为其子节点。 ''' @tool @icon("res://addons/reedscene/prop/icon/prop_icon.svg") class_name PropComponent extends Node ## ============================== ## Export ## ============================== ##此物件的描述ID @export var prop_id: int ##初始的默认state_id @export var initial_state_id: int = 0 ##是否需要输出错误 @export var debug_log := false ##是否等待 @export var should_wait_owner_ready :bool = true ##状态切换的信号 signal state_changed(from_state: int, to_state: int, ctx: Dictionary) ##state的根节点,所有的state都需要连在根节点上 var _states_root: Node var _state_map: Dictionary = {} var _current: ReedPropState = null const states_root_name := "States" const DEFAULT_STATE_ID := 0 func _enter_tree() -> void: if Engine.is_editor_hint(): _editor_ensure_states_root() func _ready() -> void: _build_state_cache() if not Engine.is_editor_hint(): if should_wait_owner_ready: await owner.ready _init_states() if _current == null and initial_state_id >= 0: change_state(initial_state_id, false, { "reason": "INIT", "instant": true }) ##映射State到stateID func _build_state_cache() -> void: _state_map.clear() _states_root = get_node_or_null(states_root_name) if _states_root == null: push_warning("[PropComponent:%s] States root not found" % prop_id) return for c in _states_root.get_children(): if c is ReedPropState: var s := c as ReedPropState if _state_map.has(s.state_id): push_error("[PropComponent:%s] Duplicate state_id: %d" % [prop_id, s.state_id]) continue _state_map[s.state_id] = s if debug_log: print("[PropComponent:%s] States:", _state_map.keys()) ##检查当前是否存在当前Id的State func has_state(state_id: int) -> bool: return _state_map.has(state_id) ##获取当前的状态ID func get_current_state_id() -> int: return _current.state_id if _current else -1 ##初始化状态 func _init_states() -> void: var owner := get_parent() if owner == null: push_error("[PropComponent:%s] Owner node not found." % prop_id) return for s in _state_map.values(): var ok :bool = s.init(owner, self) if not ok: push_error("[PropComponent:%s] State init failed: %s" % [prop_id, s.name]) ## 切换状态,如果 use_trans 为 true,则会优先检查 next state 下是否存在可用的 Transition func change_state(state_id: int, use_trans: bool, ctx: Dictionary = {}) -> bool: if not _state_map.has(state_id): push_warning("[PropComponent:%s] State not found: %d" % [prop_id, state_id]) return false var next: ReedPropState = _state_map[state_id] if _current == next: return true if not next.can_enter(_current, ctx): if debug_log: print("[PropComponent:%s] can_enter rejected: %d" % [prop_id, state_id]) return false var from_state_id := get_current_state_id() var prev := _current # ---------- EXIT ---------- if _current: _current.on_exit(next, ctx) # ---------- SWITCH CURRENT ---------- _current = next # ---------- TRANSITION CHECK ---------- var transition_handled := false if use_trans: for child in _current.get_children(): if child is ReedTransition: if child.can_trigger(prev, ctx): if debug_log: print("[PropComponent:%s] Transition triggered: %s" % [prop_id, child.name]) transition_handled = child.execute(prev, _current, ctx) if transition_handled: break # ---------- ENTER ---------- if not transition_handled: _current.on_enter(prev, ctx) else: if debug_log: print("[PropComponent:%s] StateEnter skipped by Transition: %d" % [prop_id, state_id]) if debug_log: print("[PropComponent:%s] State %d -> %d | ctx=%s" % [prop_id, from_state_id, state_id, ctx]) return true ## ============================== ## Act Sync Entry ## ============================== func sync_to_state(state_id: int, act_id: int, instant := false) -> bool: var ctx := { "reason": "ACT_SYNC", "act_id": act_id, "instant": instant } return change_state(state_id, false ,ctx) ## ============================== ## Editor Tool ## ============================== func _editor_ensure_states_root() -> void: var states := get_node_or_null(states_root_name) if states != null: return states = Node.new() states.name = states_root_name add_child(states) # ⚠️ 关键:让它成为 Scene 的一部分 states.owner = get_tree().edited_scene_root if debug_log: print("[PropComponent] Created States root")