2025-12-31 13:07:31 +08:00
|
|
|
|
#@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")
|
2026-01-01 10:47:30 +08:00
|
|
|
|
##用于生成一个Empty的工具按钮
|
|
|
|
|
|
@export_tool_button("Generate Empty Act")
|
|
|
|
|
|
var _gen_empty_act: Callable = Callable(self, "_editor_generate_empty_act")
|
2025-12-31 13:07:31 +08:00
|
|
|
|
##是否要输出报错信息
|
|
|
|
|
|
@export var debug_log: bool = false
|
2026-01-01 10:47:30 +08:00
|
|
|
|
##关卡的初始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)
|
2025-12-31 13:07:31 +08:00
|
|
|
|
|
2026-01-01 13:03:35 +08:00
|
|
|
|
## ====================
|
|
|
|
|
|
## Private Field
|
|
|
|
|
|
## ====================
|
|
|
|
|
|
var _current_act: Act = null
|
|
|
|
|
|
var _current_act_id: int = -1
|
2025-12-31 22:59:51 +08:00
|
|
|
|
signal act_changed(from_act_id: int, to_act_id: int)
|
|
|
|
|
|
|
2026-01-01 13:03:35 +08:00
|
|
|
|
func _ready() -> void:
|
|
|
|
|
|
##初始默认把act 切换到Default状态
|
|
|
|
|
|
switch_act_with_id(0)
|
|
|
|
|
|
|
|
|
|
|
|
##通过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)
|
|
|
|
|
|
|
2025-12-31 13:07:31 +08:00
|
|
|
|
##用来扫描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)
|
|
|
|
|
|
|
2026-01-01 10:47:30 +08:00
|
|
|
|
##生成一个默认的Act
|
2025-12-31 13:07:31 +08:00
|
|
|
|
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_node_or_null(scene.props_root_path)
|
|
|
|
|
|
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
|
2026-01-01 10:47:30 +08:00
|
|
|
|
|
|
|
|
|
|
var single := SingleAct.new()
|
|
|
|
|
|
single.state_id = init_state
|
|
|
|
|
|
|
|
|
|
|
|
act.prop_state_map[pid] = single
|
2025-12-31 13:07:31 +08:00
|
|
|
|
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.")
|
|
|
|
|
|
|
2026-01-01 10:47:30 +08:00
|
|
|
|
##生成一个空的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)
|
|
|
|
|
|
|
2025-12-31 13:07:31 +08:00
|
|
|
|
## ==============================
|
|
|
|
|
|
## 工具函数
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
2026-01-01 10:47:30 +08:00
|
|
|
|
##找到场景scene节点
|
2025-12-31 13:07:31 +08:00
|
|
|
|
func _get_owner_scene() -> ReedScene:
|
|
|
|
|
|
var p := get_parent()
|
|
|
|
|
|
if p is ReedScene:
|
|
|
|
|
|
return p as ReedScene
|
|
|
|
|
|
return null
|
|
|
|
|
|
|
2026-01-01 10:47:30 +08:00
|
|
|
|
##找到PropComp
|
2025-12-31 13:07:31 +08:00
|
|
|
|
func _find_prop_component_top(prop: Node) -> PropComponent:
|
|
|
|
|
|
for child in prop.get_children():
|
|
|
|
|
|
if child is PropComponent:
|
|
|
|
|
|
return child as PropComponent
|
|
|
|
|
|
return null
|
2026-01-01 10:47:30 +08:00
|
|
|
|
|
|
|
|
|
|
##找到最近的空位ActID
|
|
|
|
|
|
func _find_next_free_act_id() -> int:
|
|
|
|
|
|
var id := 0
|
|
|
|
|
|
while prop_state_map.has(id):
|
|
|
|
|
|
id += 1
|
|
|
|
|
|
return id
|
2026-01-01 13:03:35 +08:00
|
|
|
|
|
|
|
|
|
|
##通过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_node_or_null(scene.props_root_path)
|
|
|
|
|
|
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
|