2025-12-30 10:15:32 +08:00
|
|
|
|
@tool
|
|
|
|
|
|
@icon("uid://p0oxphym6oqg")
|
|
|
|
|
|
|
|
|
|
|
|
'''
|
|
|
|
|
|
此类为一个level的最小单元,其可以承载任意多的prop和act
|
|
|
|
|
|
你可以这样理解,一个level(大关卡),带有n个小关卡,n = scene的数量
|
|
|
|
|
|
|
|
|
|
|
|
Scene 必须带有:
|
|
|
|
|
|
1.Act Manager
|
|
|
|
|
|
2.复数个Prop
|
|
|
|
|
|
|
|
|
|
|
|
其中: ActManager下,带有复数个Act,其主要用于记录各个Prop的不同state,当Act切换时,Prop对应的状态也会切换。
|
|
|
|
|
|
ActManager的主要作用就是管理这些Act的切换。
|
|
|
|
|
|
Prop可以简单的理解为场景中的非地形碰撞的,与玩家可交互的道具,AI,等。
|
|
|
|
|
|
所有的Prop会自带一个PropComponent,其核心功能是负责管理Prop自身的state和state的切换
|
|
|
|
|
|
|
|
|
|
|
|
举例:一个门,从State1 -> State2,state1是关闭状态,state2是打开状态,那么:
|
|
|
|
|
|
1. 我们在State1中定义,门是关的,State2中定义,门是开的。简单的实现比如我们去设置门的坐标
|
|
|
|
|
|
2. 我们会做一个State1 -> State2的流转函数,其定义了,State1->State2的具体行为,比如,播放一个门打开的动画。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
对于任意的添加到Scene的Prop,如果其自身的最上层子节点集中不含有PropComponent,Scene会默认的给他发一个PropComponent
|
|
|
|
|
|
注意,我并不推荐在Prop上直接挂载PropComponent,通过Scene来添加更为合适。
|
|
|
|
|
|
|
|
|
|
|
|
对于Scene,Scene通过PropComponent上的ID,通过ID获取到PropComponent所挂载的组件,这也是为什么我强制要求
|
|
|
|
|
|
PropComponent必须是处于Prop的最上层子节点集。
|
|
|
|
|
|
'''
|
2025-12-30 17:22:29 +08:00
|
|
|
|
|
2025-12-30 10:15:32 +08:00
|
|
|
|
class_name ReedScene extends Node2D
|
2025-12-30 17:22:29 +08:00
|
|
|
|
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
## Export Config
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
@export var props_root_path: NodePath = ^"Props"
|
|
|
|
|
|
@export var auto_attach_prop_component := true
|
|
|
|
|
|
@export var debug_log := true
|
|
|
|
|
|
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
## Internal State
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
|
|
|
|
|
|
var _act_manager: ActManager
|
|
|
|
|
|
var _props_root: Node
|
|
|
|
|
|
var _prop_map: Dictionary = {} # prop_id -> PropComponent
|
|
|
|
|
|
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
## Lifecycle
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
func _enter_tree() -> void:
|
|
|
|
|
|
if Engine.is_editor_hint():
|
|
|
|
|
|
_editor_auto_attach_prop_components()
|
|
|
|
|
|
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
## Resolve References
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
func _resolve_act_manager() -> void:
|
|
|
|
|
|
_act_manager = get_node_or_null("ActManager")
|
|
|
|
|
|
if _act_manager == null:
|
|
|
|
|
|
push_error("[ReedScene] ActManager not found.")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
func _resolve_props_root() -> void:
|
|
|
|
|
|
_props_root = get_node_or_null(props_root_path)
|
|
|
|
|
|
if _props_root == null:
|
|
|
|
|
|
push_error("[ReedScene] Props root not found: %s" % props_root_path)
|
|
|
|
|
|
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
## Prop Collection
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
|
|
|
|
|
|
func _collect_props() -> void:
|
|
|
|
|
|
_prop_map.clear()
|
|
|
|
|
|
|
|
|
|
|
|
if _props_root == null:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
for prop in _props_root.get_children():
|
|
|
|
|
|
if not prop is Node:
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
var prop_comp := _find_prop_component(prop)
|
|
|
|
|
|
if prop_comp == null:
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
var prop_id := prop_comp.prop_id
|
|
|
|
|
|
if prop_id < 0:
|
|
|
|
|
|
push_warning("[ReedScene] Prop has invaild ID: %s" % prop.name)
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
if _prop_map.has(prop_id):
|
|
|
|
|
|
push_error("[ReedScene] Duplicate Prop ID: %s" % prop_id)
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
_prop_map[prop_id] = prop_comp
|
|
|
|
|
|
|
|
|
|
|
|
if debug_log:
|
|
|
|
|
|
print("[ReedScene] Registered Prop:", prop_id)
|
|
|
|
|
|
|
|
|
|
|
|
func _find_prop_component(prop: Node) -> PropComponent:
|
|
|
|
|
|
for child in prop.get_children():
|
|
|
|
|
|
if child is PropComponent:
|
|
|
|
|
|
return child
|
|
|
|
|
|
return null
|
|
|
|
|
|
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
## Act Binding
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
func _bind_act_events() -> void:
|
|
|
|
|
|
if _act_manager == null:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
_act_manager.act_changed.connect(_on_act_changed)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _on_act_changed(from_act: StringName, to_act: StringName) -> void:
|
|
|
|
|
|
if debug_log:
|
|
|
|
|
|
print("[ReedScene] Act changed:", from_act, "->", to_act)
|
|
|
|
|
|
|
|
|
|
|
|
for prop_comp in _prop_map.values():
|
|
|
|
|
|
prop_comp.on_act_changed(from_act, to_act)
|
|
|
|
|
|
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
## Editor Helpers
|
|
|
|
|
|
## ==============================
|
|
|
|
|
|
func _editor_auto_attach_prop_components() -> void:
|
|
|
|
|
|
if not auto_attach_prop_component:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
var props_root := get_node_or_null(props_root_path)
|
|
|
|
|
|
if props_root == null:
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
for prop in props_root.get_children():
|
|
|
|
|
|
if not prop is Node:
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
if _find_prop_component(prop) != null:
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
var comp := PropComponent.new()
|
|
|
|
|
|
prop.add_child(comp)
|
|
|
|
|
|
comp.owner = get_tree().edited_scene_root
|
|
|
|
|
|
|
|
|
|
|
|
if debug_log:
|
|
|
|
|
|
print("[ReedScene][Editor] Auto attached PropComponent to:", prop.name)
|
|
|
|
|
|
|
|
|
|
|
|
func _ready() -> void:
|
|
|
|
|
|
_resolve_act_manager()
|
|
|
|
|
|
_resolve_props_root()
|
|
|
|
|
|
_collect_props()
|
|
|
|
|
|
_bind_act_events()
|