'''此类为Prop的管理组件类,任何的Prop,其至少需要在此类的最上层的子层添加该组件 该管理器,在添加入Tree时,会自动的添加一个States节点作为其所有state的root, 并且添加一个默认的state作为其子节点。 ''' @tool @icon("res://addons/reedscene/prop/icon/prop_icon.svg") class_name PropComponent extends Node ## ============================== ## Export ## ============================== ##此物件的描述ID,无法主动修改,由PropManager发信 @export_custom(PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY) var prop_id: int = -1 ##初始的默认state_id @export var initial_state_id: int = 0 ##如果为真,则无论ActManger的配置为任何,在Inital的时候都会使用自己定义的initial state @export var overwrite_init_state: bool = false ##是否需要输出错误 @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 and overwrite_init_state: #change_state(initial_state_id, false, { #"reason": "INIT", #"instant": true #}) ## 用于初始化状态 func init() -> void: _init_states() ## 用于检查初始状态复写的Check func _init_state_check() ->void: if _current == null and initial_state_id >= 0 and overwrite_init_state: 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 if not _states_root is ReedPropStateManager: push_error("[PropComponent:%s] States root is not ReedPropStateManager" % 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 # 创建 StateManager 而不是普通 Node states = ReedPropStateManager.new() states.name = states_root_name add_child(states) # 让其成为 Scene 的一部分(非常重要) states.owner = get_tree().edited_scene_root # 自动添加一个默认 State var default_state := ReedPropState.new() default_state.name = "Default" states.add_child(default_state) default_state.owner = get_tree().edited_scene_root if debug_log: print("[PropComponent] Created States(StateManager) + Default State")