godot-plateformer/addons/reedscene/scene/ReedScene.gd

299 lines
8.7 KiB
GDScript3
Raw Normal View History

2025-12-30 10:15:32 +08:00
@tool
@icon("uid://p0oxphym6oqg")
'''
level的最小单元prop和act
leveln个小关卡n = scene的数量
Scene
2026-01-02 23:56:22 +08:00
1.SceneManager
2.Act Manager
3.Prop
2025-12-30 10:15:32 +08:00
ActManager下ActProp的不同stateAct切换时Prop对应的状态也会切换
ActManager的主要作用就是管理这些Act的切换
Prop可以简单的理解为场景中的非地形碰撞的AI
Prop会自带一个PropComponentProp自身的state和state的切换
State1 -> State2state1是关闭状态state2是打开状态
1. State1中定义State2中定义
2. State1 -> State2的流转函数State1->State2的具体行为
Scene的PropPropComponentScene会默认的给他发一个PropComponent
Prop上直接挂载PropComponentScene来添加更为合适
SceneScene通过PropComponent上的IDID获取到PropComponent所挂载的组件
PropComponent必须是处于Prop的最上层子节点集
2025-12-31 13:07:31 +08:00
Scene自身也有SceneIDSceneID是实现跨Scene修改的核心SceneID是插件内置的系统主动生成的
Scene来说SceneID是唯一且绝对的2D游戏可能没有这些问题
Scene1的时候Scene9的一个ActChange西Scene的玩家所
2025-12-30 10:15:32 +08:00
'''
2025-12-30 10:15:32 +08:00
class_name ReedScene extends Node2D
2025-12-31 13:07:31 +08:00
## ==============================
## Const Config
## ==============================
##Act管理器的命名
const ACT_MANAGER_NAME := "ActManager"
##Prop的根节点命名
const PROPS_ROOT_NAME := "Props"
##场景管理器的根节点命名
const SCENE_MANAGER_NAME := "SceneManager"
2026-01-02 23:56:22 +08:00
##Prop的路徑
const PROPS_ROOT_PATH: NodePath = ^"Props"
##PropManager脚本的路徑
const PROPS_MANAGER_SCRIPT: Script = preload("res://addons/reedscene/prop/PropManager.gd")
2025-12-31 13:07:31 +08:00
## ==============================
## Export Config
## ==============================
2026-01-02 23:56:22 +08:00
##是否要自動的為Props下的Node添加PropComponent
@export var auto_attach_prop_component := true
2026-01-02 23:56:22 +08:00
##是否要打印DebugLog
@export var debug_log := false
## ==============================
## Internal State
## ==============================
2026-01-02 18:37:09 +08:00
var _scene_id_comp: ReedSceneID
var _act_manager: ActManager
var _props_root: Node
var _prop_map: Dictionary = {} # prop_id -> PropComponent
2026-01-02 18:37:09 +08:00
var _scene_manager: SceneManager
## ==============================
2026-01-02 18:37:09 +08:00
## Build In
## ==============================
func _enter_tree() -> void:
if Engine.is_editor_hint():
2025-12-31 13:07:31 +08:00
_editor_ensure_scene_nodes() ##进入场景树自动添加ActManager,PropsRoot,和SceneManager
2026-01-02 18:37:09 +08:00
_editor_ensure_scene_id_comp() ##進入場景樹則自動添加一個IDComp
2026-01-02 18:37:09 +08:00
func _notification(what):
if what == NOTIFICATION_PARENTED:
if get_parent() != null and not (get_parent() is ReedScene):
push_warning("ReedSceneID must stay under ReedScene.")
func _ready() -> void:
_resolve_scene_id_comp()
_resolve_scene_manager()
_resolve_act_manager()
_resolve_props_root()
_collect_props()
_bind_act_events()
2026-01-02 23:56:22 +08:00
if Engine.is_editor_hint():
return
## 初始化Prop
var pcs : Array = _prop_map.values()
for pc in pcs:
pc.init()
## act manger 切换一次
_act_manager.switch_act_with_id(_act_manager.DEFAULT_ACT_ID)
## 如果prop有复写init state的选项则overwrite
for pc in pcs:
pc._init_state_check()
ReedSceneRegistry.register_scene(self)
## ==============================
## Resolve References
## ==============================
2026-01-02 18:37:09 +08:00
func _resolve_scene_id_comp() -> void:
_scene_id_comp = null
for child in get_children():
if child is ReedSceneID:
_scene_id_comp = child
break
if _scene_id_comp == null:
push_error("[ReedScene] ReedSceneID not found.")
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:
2026-01-02 23:56:22 +08:00
_props_root = get_node_or_null(PROPS_ROOT_PATH)
if _props_root == null:
2026-01-02 23:56:22 +08:00
push_error("[ReedScene] Props root not found: %s" % PROPS_ROOT_PATH)
2026-01-02 18:37:09 +08:00
func _resolve_scene_manager() -> void:
_scene_manager = get_node_or_null(SCENE_MANAGER_NAME)
if _scene_manager == null:
push_error("[ReedScene] SceneManager not found.")
## ==============================
## Prop Collection
## ==============================
func _collect_props() -> void:
_prop_map.clear()
if _props_root == null:
2026-01-02 23:56:22 +08:00
push_warning("[ReedScene]:Scene[ID:%s] dont have a prop root" % _scene_id_comp.get_scene_id())
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)
2026-01-02 23:56:22 +08:00
##獲取到一個Prop的PropComp
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)
2025-12-31 22:59:51 +08:00
func _on_act_changed(from_act: int, to_act: int) -> void:
if debug_log:
print("[ReedScene] Act changed:", from_act, "->", to_act)
2025-12-31 13:07:31 +08:00
##进入场景树自动添加ActManager,PropsRoot,和SceneManager
func _editor_ensure_scene_nodes() -> void:
_editor_ensure_node(SCENE_MANAGER_NAME, SceneManager)
_editor_ensure_node(ACT_MANAGER_NAME, ActManager)
2026-01-02 23:56:22 +08:00
_editor_ensure_node_from_script(PROPS_ROOT_NAME,PROPS_MANAGER_SCRIPT)
2025-12-31 13:07:31 +08:00
##添加命名和节点
func _editor_ensure_node(name: String, type: Variant) -> Node:
var node := get_node_or_null(name)
if node != null:
return node
2025-12-31 13:07:31 +08:00
node = type.new()
node.name = name
add_child(node)
2025-12-31 13:07:31 +08:00
node.owner = get_tree().edited_scene_root
2025-12-31 13:07:31 +08:00
if debug_log:
print("[ReedScene][Editor] Created node:", name)
2025-12-31 13:07:31 +08:00
return node
2026-01-02 23:56:22 +08:00
##通過脚本添加節點
func _editor_ensure_node_from_script(
name: String,
script: Script
) -> Node:
assert(script != null)
var node := get_node_or_null(name)
if node != null:
return node
node = script.new()
node.name = name
add_child(node)
node.owner = get_tree().edited_scene_root
if debug_log:
print("[ReedScene][Editor] Created node from script:", name)
return node
2026-01-02 18:37:09 +08:00
##保證存在ID節點
func _editor_ensure_scene_id_comp() -> ReedSceneID:
# 1. 查找已有的 ReedSceneID只找直接子节点
var id_comp: ReedSceneID = null
for child in get_children():
if child is ReedSceneID:
id_comp = child
break
# 2. 不存在就创建
if id_comp == null:
id_comp = ReedSceneID.new()
id_comp.name = "SceneID"
add_child(id_comp)
# 关键:设 owner才能被保存到场景
id_comp.owner = get_tree().edited_scene_root
if debug_log:
print("[ReedScene][Editor] Created ReedSceneID")
# 3. 确保在子节点最上层index = 0
if get_child(0) != id_comp:
move_child(id_comp, 0)
return id_comp
2026-01-02 23:56:22 +08:00
## ==============================
## Externel API
## ==============================
## 外部取得Prop映射對
func get_prop_map() -> Dictionary:
return _prop_map
## 切換Act
2026-01-02 18:37:09 +08:00
func switch_act_by_id(act_id: int) -> void:
if not _act_manager:
push_warning("[ReedScene] ActManager requested before ready.")
_act_manager.switch_act_with_id(act_id)
2026-01-02 23:56:22 +08:00
## 獲取關卡管理器
2026-01-02 18:37:09 +08:00
func get_scene_manager() -> SceneManager:
if _scene_manager == null:
push_warning("[ReedScene] SceneManager requested before ready.")
return _scene_manager
2026-01-02 23:56:22 +08:00
## 獲取SceneID Comp
2026-01-02 18:37:09 +08:00
func get_scene_id_comp() -> ReedSceneID:
if _scene_id_comp == null:
push_warning("[ReedScene] Scene not has a ID Comp.")
return _scene_id_comp
2026-01-02 23:56:22 +08:00
## 獲取Prop的根節點
func get_props_root() -> Node2D:
return _props_root
## 獲取SceneID
func get_scene_id() -> int:
if get_scene_id_comp().has_id():
return get_scene_id_comp().scene_id
return -1
2026-01-04 21:21:01 +08:00
## Prop的数量
func get_prop_count() -> int:
return get_prop_map().values().size()