From bee0682f4cf8178262c6da54f0280bceeef23e35 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Fri, 30 Oct 2026 03:47:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=A1=E2=91=A0T1(=E7=BB=84=E5=90=88?= =?UTF-8?q?=E6=A0=B9=E6=B3=A8=E5=86=8C=E9=9D=A2=E6=89=B9):=20ui=5Fregistry?= =?UTF-8?q?=EF=BC=8B=E4=B8=89=E5=9F=9F=E5=AE=B9=E5=99=A8=E5=BB=BA=E4=BB=B6?= =?UTF-8?q?=E2=80=94=E2=80=94UiRegistry(LAYER=5FCONTRACT=E9=80=90=E5=AD=97?= =?UTF-8?q?=E8=BF=81=E5=85=A5+node(key)19=E9=94=AEmatch+apply=5Flayer=5Fco?= =?UTF-8?q?ntract=E5=94=AF=E4=B8=80=E8=90=BD=E4=BD=8D=E5=8F=A3)/UiScreens(?= =?UTF-8?q?9=E5=8F=A5=E6=9F=84)/UiBattle(5=E5=8F=A5=E6=9F=84)/UiModals(13?= =?UTF-8?q?=E5=8F=A5=E6=9F=84+flow+register=5Flayer=E9=80=90=E5=AD=97?= =?UTF-8?q?=E8=BF=81=E5=85=A5);=E5=9B=9B=E4=BB=B6=E5=85=A8RefCounted?= =?UTF-8?q?=E9=9B=B6=E4=BF=A1=E5=8F=B7=E8=BF=9E=E6=8E=A5;=E7=B1=BB?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E5=88=B7=E6=96=B0+.uid=E5=90=8C=E6=AD=A5;S9/?= =?UTF-8?q?S13=E9=9B=B6=E6=96=B0=E9=94=AE+source=5Fguard=E7=BB=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/presentation/ui_battle.gd | 10 +++ game/presentation/ui_battle.gd.uid | 1 + game/presentation/ui_modals.gd | 27 +++++++ game/presentation/ui_modals.gd.uid | 1 + game/presentation/ui_registry.gd | 101 +++++++++++++++++++++++++++ game/presentation/ui_registry.gd.uid | 1 + game/presentation/ui_screens.gd | 16 +++++ game/presentation/ui_screens.gd.uid | 1 + 8 files changed, 158 insertions(+) create mode 100644 game/presentation/ui_battle.gd create mode 100644 game/presentation/ui_battle.gd.uid create mode 100644 game/presentation/ui_modals.gd create mode 100644 game/presentation/ui_modals.gd.uid create mode 100644 game/presentation/ui_registry.gd create mode 100644 game/presentation/ui_registry.gd.uid create mode 100644 game/presentation/ui_screens.gd create mode 100644 game/presentation/ui_screens.gd.uid diff --git a/game/presentation/ui_battle.gd b/game/presentation/ui_battle.gd new file mode 100644 index 00000000..206e671c --- /dev/null +++ b/game/presentation/ui_battle.gd @@ -0,0 +1,10 @@ +## 战区视图域句柄册:战斗屏 A–D 区视图与结算演出覆盖层的注册面域容器。 +## 纯字段无方法;RefCounted 不挂树——节点本体树位与 add_child 归属由组合根与装配承接件负责。 +class_name UiBattle +extends RefCounted + +var stage: BattleStageView # B 区(含 log_view 明细带) +var log_view: BattleLogView +var info_panel: HeroInfoPanelView # C 区(攻击/AC 数据框+两预留区) +var board_zone: BoardZoneView # D 区(含 ap_bar/board_view/toast/fx) +var settlement_fx: SettlementFxView # 结算演出覆盖层(跨区弹道/光带——A–D 之上、模态之下) diff --git a/game/presentation/ui_battle.gd.uid b/game/presentation/ui_battle.gd.uid new file mode 100644 index 00000000..4e684bae --- /dev/null +++ b/game/presentation/ui_battle.gd.uid @@ -0,0 +1 @@ +uid://d35j5hry1f40v diff --git a/game/presentation/ui_modals.gd b/game/presentation/ui_modals.gd new file mode 100644 index 00000000..493497ac --- /dev/null +++ b/game/presentation/ui_modals.gd @@ -0,0 +1,27 @@ +## 模态层域句柄册:十三个模态覆盖层句柄+模态栈编排(ModalFlow——登记/开合/输入锁谓词)的注册面域容器。 +## RefCounted 不挂树;模态登记唯一口=register_layer(anchors 撑满宿主+排入 ModalStack)。 +class_name UiModals +extends RefCounted + +var flow: ModalFlow +var legend_overlay: LegendOverlay +var node_overlay: NodeOverlay +var level_screen: LevelMapScreen +var curio_overlay: CurioPickOverlay +var end_overlay: BattleEndOverlay +var shop_overlay: ShopOverlay +var camp_overlay: CampOverlay +var settings_overlay: SettingsOverlay +var status_panel: StatusPanel +var career_overlay: CareerOverlay +var save_select_overlay: SaveSelectOverlay +var confirm_dialog: ConfirmDialog +var debug_overlay: DebugOverlay + + +func register_layer(m: Control, tags: Array = []) -> void: + # 撑满宿主(Control 默认锚 = 0×0——全屏变暗层与居中布局整体失效;route 选路层预览截图实证后 + # 统一收口:六个模态同病,探针经信号直发绕过真实点击从未暴露。anchors_and_offsets 而非 anchors + # ——后者会把控件重置回最小内容尺寸,ui_assembler 头注同款纪律) + m.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) + flow.register(m, tags) # 排除组随层登记(non_locking=调试浮窗/screen_state=关卡地图屏) diff --git a/game/presentation/ui_modals.gd.uid b/game/presentation/ui_modals.gd.uid new file mode 100644 index 00000000..4ac82a5c --- /dev/null +++ b/game/presentation/ui_modals.gd.uid @@ -0,0 +1 @@ +uid://dbs4qveqvr5hg diff --git a/game/presentation/ui_registry.gd b/game/presentation/ui_registry.gd new file mode 100644 index 00000000..bccce61f --- /dev/null +++ b/game/presentation/ui_registry.gd @@ -0,0 +1,101 @@ +## 界面注册面:呈现层界面元素清单的唯一事实源——哪些层、什么序、地址在哪。 +## 持有三域容器(screens/battle/modals)、LAYER_CONTRACT 合同表、node(key) 合同寻址、 +## apply_layer_contract(root) 唯一落位口(全仓唯一 move_child 点)。 +## RefCounted 不挂树:零信号连接、零会话期引用、零核心写调用——组合根单点装配不变。 +class_name UiRegistry +extends RefCounted + +const ModalStack := preload("res://presentation/modal_stack.gd") + +# ==================== 视觉层合同(唯一事实源——树序=登记序=z 序;改序只改此表) ==================== +# kind: shell=屏壳容器(成员随壳不占独立树位;level_screen 例外另占登记位)/modal=模态层(入登记册, +# tags 随登记)/state=全屏态(占树位不入登记册)/node=非视觉节点(占树位不入登记册)。 +# host=宿住屏壳(树序随宿主、登记序按本合同);shell=模态成员的屏壳(成员与屏壳同槽:屏壳占该树位、 +# 成员占该登记位)。落位=apply_layer_contract(全仓唯一层序落位点,add_child 之后统一排序+登记)。 +const LAYER_CONTRACT: Array[Dictionary] = [ + {"key": "adventure_screen", "kind": "shell"}, + {"key": "menu_screen", "kind": "shell"}, + {"key": "row_pacer", "kind": "node"}, + {"key": "legend_overlay", "kind": "modal", "tags": []}, + {"key": "node_overlay", "kind": "modal", "tags": []}, + {"key": "level_screen", "kind": "modal", "tags": [ModalStack.TAG_SCREEN_STATE], "host": "adventure_screen"}, + {"key": "curio_overlay", "kind": "modal", "tags": []}, + {"key": "end_overlay", "kind": "modal", "tags": []}, + {"key": "shop_overlay", "kind": "modal", "tags": []}, + {"key": "camp_overlay", "kind": "modal", "tags": [], "shell": "camp_screen"}, + {"key": "settings_overlay", "kind": "modal", "tags": []}, + {"key": "status_panel", "kind": "modal", "tags": []}, + {"key": "career_overlay", "kind": "modal", "tags": []}, + {"key": "save_select_overlay", "kind": "modal", "tags": []}, # 选档界面(营地交互重做卡③——登记生涯同档) + {"key": "inter_overlay", "kind": "state", "tags": []}, + {"key": "confirm_dialog", "kind": "modal", "tags": []}, + {"key": "debug_overlay", "kind": "modal", "tags": [ModalStack.TAG_NON_LOCKING]}, + {"key": "debug_badge", "kind": "float"}, # 调试入口全局浮层——末位=最顶绘制序; + # float 类不注册 ModalStack(open() 遮挡记账只隐藏登记层)→ 任何 UI 打开都不遮它 +] + +var screens: UiScreens +var battle: UiBattle +var modals: UiModals + + +func _init() -> void: + screens = UiScreens.new() + battle = UiBattle.new() + modals = UiModals.new() + + +# 合同层寻址(key→节点;纯查表不含层序语义——层序唯一事实源=LAYER_CONTRACT) +func node(key: String) -> Node: + match key: + "adventure_screen": return screens.adventure_screen + "menu_screen": return screens.menu_screen + "row_pacer": return screens.row_pacer + "legend_overlay": return modals.legend_overlay + "node_overlay": return modals.node_overlay + "level_screen": return modals.level_screen + "curio_overlay": return modals.curio_overlay + "end_overlay": return modals.end_overlay + "shop_overlay": return modals.shop_overlay + "camp_screen": return screens.camp_screen + "camp_overlay": return modals.camp_overlay + "settings_overlay": return modals.settings_overlay + "status_panel": return modals.status_panel + "career_overlay": return modals.career_overlay + "save_select_overlay": return modals.save_select_overlay + "inter_overlay": return screens.inter_overlay + "confirm_dialog": return modals.confirm_dialog + "debug_overlay": return modals.debug_overlay + "debug_badge": return screens.debug_badge + return null + + +# 合同装配(_build_ui 尾调用):按 LAYER_CONTRACT 序统一落位——直接子层 move_child 到合同槽、 +# 模态层按合同序登记;宿住层(host)树序随宿主只登记;成员层(shell)与屏壳同槽(屏壳占树位、成员占登记位)。 +# 本函数是全仓唯一层序落位点(move_child 单口)——改层序只改 LAYER_CONTRACT。 +func apply_layer_contract(root: Control) -> void: + var slot := 0 + for entry: Dictionary in LAYER_CONTRACT: + var tags: Array[Variant] = entry.get("tags", []) + if entry.has("shell"): + var shell: Node = node(String(entry["shell"])) + var member: Node = node(String(entry["key"])) + if shell != null: + root.move_child(shell, slot) + slot += 1 + if member != null: + modals.register_layer(member as Control, tags) + else: + push_error("[合同装配] 层缺失: %s" % String(entry["key"])) + continue + var layer: Node = node(String(entry["key"])) + if layer == null: + push_error("[合同装配] 层缺失: %s" % String(entry["key"])) + continue + if entry.has("host"): + modals.register_layer(layer as Control, tags) + continue + root.move_child(layer, slot) + slot += 1 + if String(entry["kind"]) == "modal": + modals.register_layer(layer as Control, tags) diff --git a/game/presentation/ui_registry.gd.uid b/game/presentation/ui_registry.gd.uid new file mode 100644 index 00000000..06405e33 --- /dev/null +++ b/game/presentation/ui_registry.gd.uid @@ -0,0 +1 @@ +uid://d1hahbtan1te8 diff --git a/game/presentation/ui_screens.gd b/game/presentation/ui_screens.gd new file mode 100644 index 00000000..b7a76b3e --- /dev/null +++ b/game/presentation/ui_screens.gd @@ -0,0 +1,16 @@ +## 屏壳与全屏容器域句柄册:三屏壳、屏内一级子层、全屏态、浮层角标、排播泵节点的注册面域容器。 +## 纯字段无方法;RefCounted 不挂树——节点本体树位与 add_child 归属由组合根与装配承接件负责。 +class_name UiScreens +extends RefCounted + +const RowPacer := preload("res://presentation/row_pacer.gd") # 排播泵取型(row_pacer.gd 非 class_name 全局) + +var menu_screen: Control +var camp_screen: Control +var adventure_screen: Control +var start_overlay: Control +var battle_root: Control +var inter_overlay: Control +var inter_label: Label +var debug_badge: Button +var row_pacer: RowPacer diff --git a/game/presentation/ui_screens.gd.uid b/game/presentation/ui_screens.gd.uid new file mode 100644 index 00000000..08356b8a --- /dev/null +++ b/game/presentation/ui_screens.gd.uid @@ -0,0 +1 @@ +uid://dd8ep7nhmyrdq