iter41-卡2:呈现层结构收敛批:67清+2豁免+2展平改善——拆私有族+六状态件+ui_kit收敛+束收拢+print删;含u14补做、并master并案与收尾产出物
This commit is contained in:
1 parent
bc75dab615
commit
7beb9bfdd5
94 files changed
+3417
-5314
No files matched your search
@@ -31,43 +31,47 @@ const HIT_PAD := 6.0 # 图上命中外扩(指
|
||||
const CONFIRM_WINDOW_S := 3.0 # 放弃确认态窗口(秒——超时回落)
|
||||
const COL_HP_BAR_BACK := UiKit.HP_BAR_BACK # 迷你血条深底(对暗面板可辨;值单点收 UiKit)
|
||||
|
||||
var _runner = null
|
||||
var _title: Label
|
||||
var _canvas: Control
|
||||
var _level_label: Label
|
||||
var _gp_value: Label
|
||||
var _hp_value: Label
|
||||
var _hp_bar: Control
|
||||
var _attr_value: Label
|
||||
var _bonus_row: HBoxContainer
|
||||
var _bonus_value: Label
|
||||
var _feat_value: Label # 特性持有行(组合根投喂逐件文案)
|
||||
var _cand_ids: Array[int] = [] # 本停点候选 id 集(图上命中合法集)
|
||||
var _content_size := Vector2(620, 240) # 图内容包络(open_choices 按图拟合——画布 min 尺寸随它)
|
||||
var _hover_id := -1 # 悬停预承诺候选(-1 = 无)
|
||||
var abandon_btn: Button # 放弃入口(可见性归组合根 set_abandon_available——只在冒险模式开)
|
||||
var status_badge: Button # 状态面板入口角标(顶栏 GP 徽右侧;连接归组合根)
|
||||
var _abandon_timer := ArmedTimer.new() # 放弃确认窗(_process 帧驱动倒计时机制收口;窗口=CONFIRM_WINDOW_S)
|
||||
var _drawn_disp: Dictionary[int, Dictionary] = {} # 本停点实际绘制记录(_draw_graph 逐帧在实际绘制点重建——display_probe 消费面)
|
||||
var _node_icons := {} # 节点图标贴图(load_tex 守卫——缺位 null → 字形回退,冒烟/无素材检出安全)
|
||||
var _noise_rect: TextureRect # 屏底石纹(换层色板渐变承载面——null = 纯色回退无挂点)
|
||||
var _tint_level := 0 # 当前已应用 tint 的层号(0 = 未应用)
|
||||
var _layout_cache := {"nodes": [], "canvas_size": Vector2.ZERO, "pos": {}} # 布局缓存(_layout 纯函数于 (nodes, canvas)——键=nodes 内容等价+画布尺寸,图态换代或画布尺寸变即自然失效)
|
||||
## 内部状态件(u2 子域拆件——契约 9 职责轴):_MapState=选路屏运行态与图绘制态(单一变化原因=
|
||||
## 选路呈现)。_layer_decor 域字典承载换层装饰三件(图标贴图/石纹面/tint 层号——装饰域归并形态)。
|
||||
## 探针直读冻结成员(_cand_ids/_hover_id/_content_size/_layout_cache/abandon_btn/status_badge)住宿主。
|
||||
class _MapState extends RefCounted:
|
||||
var _runner = null
|
||||
var _title: Label
|
||||
var _canvas: Control
|
||||
var _level_label: Label
|
||||
var _gp_value: Label
|
||||
var _hp_value: Label
|
||||
var _hp_bar: Control
|
||||
var _attr_value: Label
|
||||
var _bonus_row: HBoxContainer
|
||||
var _bonus_value: Label
|
||||
var _feat_value: Label # 特性持有行(组合根投喂逐件文案)
|
||||
var _abandon_timer := ArmedTimer.new() # 放弃确认窗(_process 帧驱动倒计时机制收口;窗口=CONFIRM_WINDOW_S)
|
||||
var _drawn_disp: Dictionary[int, Dictionary] = {} # 本停点实际绘制记录(_draw_graph 逐帧在实际绘制点重建——display_probe 消费面)
|
||||
var _layer_decor := {"node_icons": {}, "noise_rect": null, "tint_level": 0} # 换层装饰域(节点图标贴图 load_tex 守卫缺位 null→字形回退/屏底石纹面/当前已应用 tint 层号 0=未应用)
|
||||
|
||||
var _cand_ids: Array[int] = [] # 本停点候选 id 集(图上命中合法集;探针直读冻结——住宿主)
|
||||
var _content_size := Vector2(620, 240) # 图内容包络(open_choices 按图拟合——画布 min 尺寸随它;探针直读冻结)
|
||||
var _hover_id := -1 # 悬停预承诺候选(-1 = 无;探针直读冻结)
|
||||
var abandon_btn: Button # 放弃入口(可见性归组合根 set_abandon_available——只在冒险模式开;探针直读冻结)
|
||||
var status_badge: Button # 状态面板入口角标(顶栏 GP 徽右侧;连接归组合根;探针直读冻结)
|
||||
var _layout_cache := {"nodes": [], "canvas_size": Vector2.ZERO, "pos": {}} # 布局缓存(_layout 纯函数于 (nodes, canvas)——键=nodes 内容等价+画布尺寸,图态换代或画布尺寸变即自然失效;探针直读冻结)
|
||||
var _map := _MapState.new()
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_abandon_timer.expired.connect(_reset_abandon_confirm)
|
||||
_map._abandon_timer.expired.connect(_reset_abandon_confirm)
|
||||
# 节点图标贴图装载(load_tex 守卫,缺位回退现行字形)
|
||||
for t in TEX_NODE_ICONS:
|
||||
_node_icons[t] = UiKit.load_tex(TEX_NODE_ICONS[t])
|
||||
_map._layer_decor.node_icons[t] = UiKit.load_tex(TEX_NODE_ICONS[t])
|
||||
# 独立屏底(spec Layout——demo #v-map 暖棕竖向
|
||||
# 渐变(#4A3B2A 0%→#3A2E22 40%)+石纹弱质感 0.14+暗角聚焦;底纹缺位回退纯色)
|
||||
var base := UiKit.gradient_base(UiKit.BG_MAP_TOP, UiKit.BG_ROOT)
|
||||
var base := UiKit._gradient_base(UiKit.BG_MAP_TOP, UiKit.BG_ROOT)
|
||||
add_child(base)
|
||||
var tex := UiKit.backdrop_tile()
|
||||
if tex != null:
|
||||
base.add_child(tex)
|
||||
_noise_rect = tex # 世界侧 tint 承载面(换层色板渐变挂点——§2.7 切片档)
|
||||
_map._layer_decor.noise_rect = tex # 世界侧 tint 承载面(换层色板渐变挂点——§2.7 切片档)
|
||||
base.add_child(UiKit.vignette_rect())
|
||||
var center := CenterContainer.new()
|
||||
center.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
@@ -75,9 +79,16 @@ func _init() -> void:
|
||||
var box := VBoxContainer.new()
|
||||
box.add_theme_constant_override("separation", 10)
|
||||
center.add_child(box)
|
||||
# 顶栏语境(spec Layout:左关卡名 / 右 GP 常驻徽章——直角细线数据框;
|
||||
# 对齐 demo ④:关卡名入框板+GP 徽章=烛光胶囊(同商店GP框)+
|
||||
# 左右两极排布)
|
||||
_build_top_bar(box)
|
||||
_build_canvas(box)
|
||||
_build_status_bar(box)
|
||||
visible = false
|
||||
|
||||
|
||||
## 顶栏域(spec Layout:左关卡名 / 右 GP 常驻徽章——直角细线数据框;
|
||||
## 对齐 demo ④:关卡名入框板+GP 徽章=烛光胶囊(同商店GP框)+ 左右两极排布;
|
||||
## 状态角标置灰守卫归组合根 _sync_status_entry,信号连接归组合根——视图零连接)
|
||||
func _build_top_bar(box: VBoxContainer) -> void:
|
||||
var top := HBoxContainer.new()
|
||||
top.add_theme_constant_override("separation", 12)
|
||||
top.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
@@ -86,8 +97,8 @@ func _init() -> void:
|
||||
lvl_plate.add_theme_stylebox_override("panel",
|
||||
UiKit.panel_flat(UiKit.DARK_UPCOMING, UiKit.PANEL_BORDER, 0, 1, Vector4(12, 3, 12, 3)))
|
||||
top.add_child(lvl_plate)
|
||||
_level_label = UiKit.label("",UiKit.FS_BODY, true, UiKit.WARM)
|
||||
lvl_plate.add_child(_level_label)
|
||||
_map._level_label = UiKit.label("",UiKit.FS_BODY, true, UiKit.WARM)
|
||||
lvl_plate.add_child(_map._level_label)
|
||||
var top_sp := Control.new()
|
||||
top_sp.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
top.add_child(top_sp)
|
||||
@@ -98,31 +109,34 @@ func _init() -> void:
|
||||
var gp_row := HBoxContainer.new()
|
||||
gp_row.add_theme_constant_override("separation", 6)
|
||||
gp_box.add_child(gp_row)
|
||||
_gp_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_ON_GOLD)
|
||||
gp_row.add_child(_gp_value)
|
||||
# 状态面板入口角标(顶栏常驻;本屏只留状态——调试角标归全局浮层。
|
||||
# 置灰守卫归组合根 _sync_status_entry(其他模态开着=不可点;本屏自身的登记开态不计——has_open_excluding);
|
||||
# 信号连接归组合根(视图零连接))
|
||||
_map._gp_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_ON_GOLD)
|
||||
gp_row.add_child(_map._gp_value)
|
||||
status_badge = UiKit.button("状态", 0.0)
|
||||
status_badge.add_theme_font_size_override("font_size", UiKit.FS_HINT)
|
||||
status_badge.tooltip_text = "查看本局冒险进度(只读)"
|
||||
status_badge.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
top.add_child(status_badge)
|
||||
_title = UiKit.label(TITLE_FORK,UiKit.FS_SUB, true, UiKit.WARM)
|
||||
_title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
box.add_child(_title)
|
||||
# 节点图画布(图上点击 = 唯一提交通道——布局决策 2;mouse_filter STOP 接悬停/点击)
|
||||
_canvas = Control.new()
|
||||
_canvas.custom_minimum_size = Vector2(620, 240)
|
||||
_canvas.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
_canvas.draw.connect(_draw_graph.bind(_canvas))
|
||||
_canvas.gui_input.connect(_on_canvas_input)
|
||||
box.add_child(_canvas)
|
||||
# 底部状态栏(合并单条:亮米面板一站读齐=头像+生命+属性+本关加成/流派件——demo ④;
|
||||
# 道具槽不摆=道具读数无关卡画面成文出口(读快照私域越权);
|
||||
# _hp_value/_attr_value/_bonus_value/_feat_value 投喂键全部保留)
|
||||
# 底栏定高纪律(对齐 demo——单条 ~85px 紧凑亮条;任何子件不再能把栏撑爆:
|
||||
# 特性持有行限宽截断+tooltip 全文)
|
||||
_map._title = UiKit.label(TITLE_FORK,UiKit.FS_SUB, true, UiKit.WARM)
|
||||
_map._title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
box.add_child(_map._title)
|
||||
|
||||
|
||||
## 节点图画布域(图上点击 = 唯一提交通道——布局决策 2;mouse_filter STOP 接悬停/点击)
|
||||
func _build_canvas(box: VBoxContainer) -> void:
|
||||
_map._canvas = Control.new()
|
||||
_map._canvas.custom_minimum_size = Vector2(620, 240)
|
||||
_map._canvas.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
_map._canvas.draw.connect(_draw_graph.bind(_map._canvas))
|
||||
_map._canvas.gui_input.connect(_on_canvas_input)
|
||||
box.add_child(_map._canvas)
|
||||
|
||||
|
||||
## 底部状态栏域(合并单条:亮米面板一站读齐=头像+生命+属性+本关加成/流派件——demo ④;
|
||||
## 道具槽不摆=道具读数无关卡画面成文出口(读快照私域越权);
|
||||
## _hp_value/_attr_value/_bonus_value/_feat_value 投喂键全部保留。
|
||||
## 底栏定高纪律(对齐 demo——单条 ~85px 紧凑亮条;任何子件不再能把栏撑爆:
|
||||
## 特性持有行限宽截断+tooltip 全文))
|
||||
func _build_status_bar(box: VBoxContainer) -> void:
|
||||
var bottom := PanelContainer.new()
|
||||
bottom.custom_minimum_size = Vector2(0, 85)
|
||||
bottom.size_flags_vertical = Control.SIZE_SHRINK_END
|
||||
@@ -132,9 +146,37 @@ func _init() -> void:
|
||||
var strip := HBoxContainer.new()
|
||||
strip.add_theme_constant_override("separation", 18)
|
||||
bottom.add_child(strip)
|
||||
strip.add_child(_build_face_rect())
|
||||
var life_box := VBoxContainer.new()
|
||||
strip.add_child(life_box)
|
||||
life_box.add_child(UiKit.label("生命",UiKit.FS_CAPTION, false, UiKit.INK_HINT))
|
||||
_map._hp_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE)
|
||||
life_box.add_child(_map._hp_value)
|
||||
_map._hp_bar = Control.new()
|
||||
_map._hp_bar.custom_minimum_size = Vector2(130, 7)
|
||||
_map._hp_bar.draw.connect(_draw_hp_bar.bind(_map._hp_bar))
|
||||
life_box.add_child(_map._hp_bar)
|
||||
strip.add_child(_vdiv())
|
||||
var attr_box := VBoxContainer.new()
|
||||
strip.add_child(attr_box)
|
||||
attr_box.add_child(UiKit.label("属性",UiKit.FS_CAPTION, false, UiKit.INK_HINT))
|
||||
_map._attr_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE)
|
||||
attr_box.add_child(_map._attr_value)
|
||||
strip.add_child(_vdiv())
|
||||
_build_bonus_group(strip)
|
||||
var spacer := Control.new()
|
||||
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
strip.add_child(spacer)
|
||||
abandon_btn = UiKit.danger_button("放弃", "", 90.0) # 小号危险钮 ~90×38
|
||||
abandon_btn.pressed.connect(_on_abandon_pressed)
|
||||
abandon_btn.visible = false
|
||||
strip.add_child(abandon_btn)
|
||||
|
||||
|
||||
## 头像域:定高 48px=1×、宽随源图比自适应(源 46×48 → 46×48;纵横异倍消除)
|
||||
func _build_face_rect() -> TextureRect:
|
||||
var face := TextureRect.new()
|
||||
var face_tex := UiKit.load_tex(UiKit.TEX_HERO_PORTRAIT)
|
||||
# 定高 48px=1×、宽随源图比自适应(源 46×48 → 46×48;纵横异倍消除)
|
||||
var face_h := 48.0
|
||||
var face_w := face_h
|
||||
if face_tex != null:
|
||||
@@ -145,50 +187,26 @@ func _init() -> void:
|
||||
face.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
face.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
face.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
strip.add_child(face)
|
||||
var life_box := VBoxContainer.new()
|
||||
strip.add_child(life_box)
|
||||
life_box.add_child(UiKit.label("生命",UiKit.FS_CAPTION, false, UiKit.INK_HINT))
|
||||
_hp_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE)
|
||||
life_box.add_child(_hp_value)
|
||||
_hp_bar = Control.new()
|
||||
_hp_bar.custom_minimum_size = Vector2(130, 7)
|
||||
_hp_bar.draw.connect(_draw_hp_bar.bind(_hp_bar))
|
||||
life_box.add_child(_hp_bar)
|
||||
strip.add_child(_vdiv())
|
||||
var attr_box := VBoxContainer.new()
|
||||
strip.add_child(attr_box)
|
||||
attr_box.add_child(UiKit.label("属性",UiKit.FS_CAPTION, false, UiKit.INK_HINT))
|
||||
_attr_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE)
|
||||
attr_box.add_child(_attr_value)
|
||||
strip.add_child(_vdiv())
|
||||
# 本关加成框(零加成隐藏——spec 布局决策 4)+ 流派件持有行(组合根投喂)
|
||||
_bonus_row = HBoxContainer.new()
|
||||
strip.add_child(_bonus_row)
|
||||
return face
|
||||
|
||||
|
||||
## 本关加成框域(零加成隐藏——spec 布局决策 4)+ 流派件持有行(组合根投喂;限宽单行截断+tooltip 全文)
|
||||
func _build_bonus_group(strip: HBoxContainer) -> void:
|
||||
_map._bonus_row = HBoxContainer.new()
|
||||
strip.add_child(_map._bonus_row)
|
||||
var bonus_box := VBoxContainer.new()
|
||||
_bonus_row.add_child(bonus_box)
|
||||
_map._bonus_row.add_child(bonus_box)
|
||||
var bonus_inner := VBoxContainer.new()
|
||||
bonus_box.add_child(bonus_inner)
|
||||
var bonus_cap := UiKit.label("属性值提升",UiKit.FS_CAPTION, false, UiKit.INK_HINT) # 深墨(亮板可读)
|
||||
bonus_inner.add_child(bonus_cap)
|
||||
_bonus_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE) # 淡墨→深墨(同上)
|
||||
bonus_inner.add_child(_bonus_value)
|
||||
# 特性持有行(组合根投喂)
|
||||
# 限宽单行截断+tooltip 全文;
|
||||
# 墨色 INK_HINT(暖白系对亮板 ≈1:1 不可读——§7.2)
|
||||
_feat_value = UiKit.label("",UiKit.FS_HINT, false, UiKit.INK_HINT)
|
||||
_feat_value.custom_minimum_size = Vector2(240, 0)
|
||||
_feat_value.clip_text = true
|
||||
_feat_value.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
||||
bonus_box.add_child(_feat_value)
|
||||
var spacer := Control.new()
|
||||
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
strip.add_child(spacer)
|
||||
abandon_btn = UiKit.danger_button("放弃", "", 90.0) # 小号危险钮 ~90×38
|
||||
abandon_btn.pressed.connect(_on_abandon_pressed)
|
||||
abandon_btn.visible = false
|
||||
strip.add_child(abandon_btn)
|
||||
visible = false
|
||||
_map._bonus_value = UiKit.label("",UiKit.FS_BODY, true, UiKit.INK_TITLE) # 淡墨→深墨(同上)
|
||||
bonus_inner.add_child(_map._bonus_value)
|
||||
_map._feat_value = UiKit.label("",UiKit.FS_HINT, false, UiKit.INK_HINT)
|
||||
_map._feat_value.custom_minimum_size = Vector2(240, 0)
|
||||
_map._feat_value.clip_text = true
|
||||
_map._feat_value.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
||||
bonus_box.add_child(_map._feat_value)
|
||||
|
||||
|
||||
# 竖分隔线(底栏分组线——亮面板上低对比细线)
|
||||
@@ -202,10 +220,10 @@ static func _vdiv() -> ColorRect:
|
||||
func _draw_hp_bar(bar: Control) -> void:
|
||||
# 迷你血条(深底 UiKit.HP_BAR_BACK #28221C + 小人蓝填充——与战斗站桩血条同语言,
|
||||
# 「蓝只说己方」§4.2)。比例 = hero_hp / effective_max_hp
|
||||
if _runner == null:
|
||||
if _map._runner == null:
|
||||
return
|
||||
var max_hp := maxi(1, _runner.effective_max_hp())
|
||||
var ratio := clampf(float(_runner.hero_hp) / float(max_hp), 0.0, 1.0)
|
||||
var max_hp := maxi(1, _map._runner.effective_max_hp())
|
||||
var ratio := clampf(float(_map._runner.hero_hp) / float(max_hp), 0.0, 1.0)
|
||||
var full := Rect2(Vector2.ZERO, bar.size)
|
||||
bar.draw_rect(full, COL_HP_BAR_BACK)
|
||||
if ratio > 0.0:
|
||||
@@ -215,8 +233,8 @@ func _draw_hp_bar(bar: Control) -> void:
|
||||
# 放弃入口可见性(组合根在冒险启动时开、默认关——语义对象 = 整局冒险)
|
||||
# 特性持有投影(组合根投喂逐件文案;空文案=行隐藏)
|
||||
func set_feat_holdings(text: String) -> void:
|
||||
_feat_value.text = text
|
||||
_feat_value.tooltip_text = text # 截断全量兜底(限宽单行省略——悬停看全文)
|
||||
_map._feat_value.text = text
|
||||
_map._feat_value.tooltip_text = text # 截断全量兜底(限宽单行省略——悬停看全文)
|
||||
|
||||
|
||||
func set_abandon_available(v: bool) -> void:
|
||||
@@ -226,8 +244,8 @@ func set_abandon_available(v: bool) -> void:
|
||||
# 放弃二次确认(布局决策 3):首击转确认态(文案+危险红脉冲约 3 秒超时回落),二击才提交。
|
||||
# 单击不提交——ui_probe 战斗中 pressed.emit() 单击路径保持「未受理」语义(战斗中拒绝归组合根)。
|
||||
func _on_abandon_pressed() -> void:
|
||||
if not _abandon_timer.is_armed():
|
||||
_abandon_timer.arm(CONFIRM_WINDOW_S)
|
||||
if not _map._abandon_timer.is_armed():
|
||||
_map._abandon_timer.arm(CONFIRM_WINDOW_S)
|
||||
abandon_btn.text = "再点一次确认放弃——不可逆"
|
||||
if ArmedTimer.motion_still():
|
||||
abandon_btn.modulate = Color(1, 1, 1, 0.75) # 减动效静态基色(脉冲层不再驱动)
|
||||
@@ -237,45 +255,45 @@ func _on_abandon_pressed() -> void:
|
||||
|
||||
|
||||
func _reset_abandon_confirm() -> void:
|
||||
_abandon_timer.disarm()
|
||||
_map._abandon_timer.disarm()
|
||||
abandon_btn.modulate = Color(1, 1, 1, 1)
|
||||
abandon_btn.text = "放弃" # 文案收敛 level-map 4 字上限(确认态转义面见 _on_abandon_pressed)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not _abandon_timer.is_armed():
|
||||
if not _map._abandon_timer.is_armed():
|
||||
return
|
||||
_abandon_timer.tick(delta)
|
||||
if not _abandon_timer.is_armed():
|
||||
_map._abandon_timer.tick(delta)
|
||||
if not _map._abandon_timer.is_armed():
|
||||
return # 窗口到点回落(expired 信号已驱动 _reset_abandon_confirm)
|
||||
# 危险红边框脉冲(单段呼吸约 1Hz——闪烁基线 ≤3 次/秒内;减动效 = 静态半透不闪——档判据单点 motion_still)
|
||||
if ArmedTimer.motion_still():
|
||||
abandon_btn.modulate = Color(1, 1, 1, 0.75)
|
||||
else:
|
||||
var k := 0.5 + 0.5 * sin(_abandon_timer.elapsed * TAU)
|
||||
var k := 0.5 + 0.5 * sin(_map._abandon_timer.elapsed * TAU)
|
||||
abandon_btn.modulate = Color(1, 1, 1, 0.65 + 0.35 * k)
|
||||
|
||||
|
||||
# 打开选路口(cands = 候选节点引用数组;runner 只读用于整图渲染与状态栏刷新)
|
||||
func open_choices(cands: Array, runner: LevelRunner) -> void:
|
||||
var was_visible := visible # 进入转场判据(就地刷新/模态栈恢复不重放淡入)
|
||||
_runner = runner
|
||||
_map._runner = runner
|
||||
_hover_id = -1
|
||||
_reset_abandon_confirm()
|
||||
var visited: Array[int] = []
|
||||
if runner != null:
|
||||
visited = runner.visited_ids()
|
||||
if cands.size() > 1:
|
||||
_title.text = TITLE_FORK
|
||||
_map._title.text = TITLE_FORK
|
||||
elif visited.is_empty():
|
||||
_title.text = TITLE_ENTRY # 入口停点(尚未走出第一步)
|
||||
_map._title.text = TITLE_ENTRY # 入口停点(尚未走出第一步)
|
||||
else:
|
||||
_title.text = TITLE_SINGLE
|
||||
_map._title.text = TITLE_SINGLE
|
||||
_cand_ids = []
|
||||
for cand in cands:
|
||||
_cand_ids.append(_id_of(cand))
|
||||
_fit_canvas(_runner.nodes())
|
||||
_apply_level_tint(int(_runner.level_row.get("level_index", 0)))
|
||||
_fit_canvas(_map._runner.nodes())
|
||||
_apply_level_tint(int(_map._runner.level_row.get("level_index", 0)))
|
||||
visible = true
|
||||
if not was_visible:
|
||||
# 独立屏淡入(spec Transitions:约 200ms;alpha 淡入非明度变化——art-bible §2 明度恒定)
|
||||
@@ -302,7 +320,7 @@ func _fit_canvas(nodes: Array) -> void:
|
||||
_content_size = Vector2(LAYER_BASE_X + maxl * LAYER_STEP_X + NODE_HALF.x + 8.0,
|
||||
SLOT_BASE_Y + maxslot * SLOT_STEP_Y + NODE_HALF.y + 24.0) # +24 = 类型文字标签行
|
||||
_content_size = _content_size.max(Vector2(620, 256)) # 下限(抬高容纳标签行)
|
||||
_canvas.custom_minimum_size = _content_size
|
||||
_map._canvas.custom_minimum_size = _content_size
|
||||
|
||||
|
||||
# 换层色板渐变挂点(art-bible §2.7 下探过渡切片档——关卡结算确认→下一关→独立屏淡入链路上的
|
||||
@@ -313,39 +331,39 @@ const BOARD_TINTS := {1: Color(1, 1, 1), 2: Color(0.84, 0.99, 1.28), 3: Color(0.
|
||||
|
||||
|
||||
func _apply_level_tint(level_index: int) -> void:
|
||||
if _noise_rect == null or level_index == _tint_level:
|
||||
if _map._layer_decor.noise_rect == null or level_index == _map._layer_decor.tint_level:
|
||||
return
|
||||
_tint_level = level_index
|
||||
_map._layer_decor.tint_level = level_index
|
||||
var target: Color = BOARD_TINTS.get(level_index, Color(1, 1, 1))
|
||||
var tw := create_tween()
|
||||
tw.tween_property(_noise_rect, "modulate",
|
||||
tw.tween_property(_map._layer_decor.noise_rect, "modulate",
|
||||
Color(target.r, target.g, target.b, UiKit.BACKDROP_TILE_ALPHA), UiKit.motion(0.45)) # 0.14 弱质感档随 tint 保持
|
||||
|
||||
|
||||
# 状态栏投喂(命令式纪律——组合根经 level_map_status_payload 取成品后喂入;零推送信号订阅、零核心态拼装)
|
||||
func apply_status(payload: Dictionary) -> void:
|
||||
_level_label.text = String(payload["level_label"])
|
||||
_gp_value.text = String(payload["gp_text"])
|
||||
_hp_value.text = String(payload["hp_text"])
|
||||
_map._level_label.text = String(payload["level_label"])
|
||||
_map._gp_value.text = String(payload["gp_text"])
|
||||
_map._hp_value.text = String(payload["hp_text"])
|
||||
if bool(payload["hp_bar_redraw"]):
|
||||
_hp_bar.queue_redraw()
|
||||
_attr_value.text = String(payload["attr_text"])
|
||||
_bonus_value.text = String(payload["bonus_text"])
|
||||
_map._hp_bar.queue_redraw()
|
||||
_map._attr_value.text = String(payload["attr_text"])
|
||||
_map._bonus_value.text = String(payload["bonus_text"])
|
||||
# 特性持有行可见性(与加成行并框——任一非空整框显示;文案归组合根 set_feat_holdings)
|
||||
_bonus_row.visible = bool(payload["bonus_row_visible"]) or _feat_value.text != ""
|
||||
_map._bonus_row.visible = bool(payload["bonus_row_visible"]) or _map._feat_value.text != ""
|
||||
|
||||
|
||||
# ---- 图上命中(布局决策 2——唯一提交通道;探针 press_candidate 同路径) ----
|
||||
|
||||
func _on_canvas_input(ev: InputEvent) -> void:
|
||||
if _runner == null or not visible:
|
||||
if _map._runner == null or not visible:
|
||||
return
|
||||
if ev is InputEventMouseMotion:
|
||||
var nid := _candidate_at(ev.position) # gui_input 事件坐标 = 接收控件局部坐标(push_input 同成立)
|
||||
if nid != _hover_id:
|
||||
_hover_id = nid
|
||||
_canvas.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND if nid >= 0 else Control.CURSOR_ARROW
|
||||
_canvas.queue_redraw()
|
||||
_map._canvas.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND if nid >= 0 else Control.CURSOR_ARROW
|
||||
_map._canvas.queue_redraw()
|
||||
elif ev is InputEventMouseButton and ev.button_index == MOUSE_BUTTON_LEFT and ev.pressed:
|
||||
var nid2 := _candidate_at(ev.position)
|
||||
if nid2 >= 0:
|
||||
@@ -354,10 +372,10 @@ func _on_canvas_input(ev: InputEvent) -> void:
|
||||
|
||||
# 候选命中:位置 = 布局公式(与 _draw_graph 同源),矩形 = 节点方块 + 外扩容差;非候选格不响应
|
||||
func _candidate_at(local_pos: Vector2) -> int:
|
||||
if _runner == null:
|
||||
if _map._runner == null:
|
||||
return -1
|
||||
var nodes: Array[Variant] = _runner.nodes()
|
||||
var pos := _layout(nodes, _canvas)
|
||||
var nodes: Array[Variant] = _map._runner.nodes()
|
||||
var pos := _layout(nodes, _map._canvas)
|
||||
for nid in _cand_ids:
|
||||
var node := _node_by_id(nid, nodes)
|
||||
if node.is_empty():
|
||||
@@ -372,7 +390,7 @@ func _candidate_at(local_pos: Vector2) -> int:
|
||||
func _submit_choice(nid: int) -> void:
|
||||
# 独立屏分支:战斗/Boss 节点 = 出屏切回战斗屏;奖励/恢复/商店节点 =
|
||||
# 本屏保持激活——兑付覆盖层由节点事件在本屏域内弹出(模态栈遮挡恢复语义复用),兑付确认后回图刷新
|
||||
var node := _node_by_id(nid, _runner.nodes())
|
||||
var node := _node_by_id(nid, _map._runner.nodes())
|
||||
var t := String(node.get("type", ""))
|
||||
if t != "reward" and t != "rest" and t != "shop":
|
||||
visible = false
|
||||
@@ -381,13 +399,13 @@ func _submit_choice(nid: int) -> void:
|
||||
|
||||
# 探针复用:按候选序号走图上命中同路径(候选节点中心坐标 → 命中检测 → 提交——布局决策 2 探针面改造)
|
||||
func press_candidate(index: int) -> void:
|
||||
if index < 0 or index >= _cand_ids.size() or _runner == null:
|
||||
if index < 0 or index >= _cand_ids.size() or _map._runner == null:
|
||||
return
|
||||
var nodes: Array[Variant] = _runner.nodes()
|
||||
var nodes: Array[Variant] = _map._runner.nodes()
|
||||
var node := _node_by_id(int(_cand_ids[index]), nodes)
|
||||
if node.is_empty():
|
||||
return
|
||||
var pos: Vector2 = _layout(nodes, _canvas)[node]
|
||||
var pos: Vector2 = _layout(nodes, _map._canvas)[node]
|
||||
var nid := _candidate_at(pos) # 节点中心必命中自身(命中面含节点方块)
|
||||
if nid >= 0:
|
||||
_submit_choice(nid)
|
||||
@@ -395,7 +413,7 @@ func press_candidate(index: int) -> void:
|
||||
|
||||
func _id_of(node: Dictionary) -> int:
|
||||
# 编号显示经行进器读面(编号空间解析单一出口——单链 = 下标 / 图 = node_depth)
|
||||
return _runner.node_id_of(node)
|
||||
return _map._runner.node_id_of(node)
|
||||
|
||||
|
||||
# ---- 节点呈现决策面(信息迷雾 v2.1:类型仅在可见集内出示,Boss 标记不入雾)----
|
||||
@@ -421,20 +439,48 @@ static func node_display(node: Dictionary, nid: int, type_vis: Array,
|
||||
# ---- 整图自绘(程序化占位——分层布局:层 = 入口 BFS 深度,同层垂直排布)----
|
||||
|
||||
func _draw_graph(canvas: Control) -> void:
|
||||
if _runner == null or not visible:
|
||||
if _map._runner == null or not visible:
|
||||
return
|
||||
_drawn_disp.clear() # 绘制记录随本帧重建——只反映实际发生的绘制(接线坏的判据面)
|
||||
var nodes: Array[Variant] = _runner.nodes()
|
||||
var pos := _layout(nodes, canvas)
|
||||
var font := get_theme_default_font() # 绘制路径字体单次取用(三处 draw_string 共享——零语义差)
|
||||
var current_id: int = _runner.current_node_id()
|
||||
# 当前节点 id(单链=下标 / 图=编号)——visited_ids() 已按编号空间解析
|
||||
var visited: Array[Variant] = _runner.visited_ids()
|
||||
var cand_ids: Array[Variant] = _runner.next_candidate_ids()
|
||||
var type_vis: Array[int] = _runner.type_visible_ids() # 本停点类型可见集(每帧一取——纯函数零状态)
|
||||
# 连线(通道)先行画(方块覆盖其上);悬停预承诺 = 所属通道再增亮(加粗)
|
||||
# 选路停点(候选非空)非候选通道降透明——金岔路从结构网分离(干线共线重叠缺陷的
|
||||
# 视觉主因:不同源通道共用同一垂直干线,金边与石色边焊接成「整列可走」假象)
|
||||
_map._drawn_disp.clear() # 绘制记录随本帧重建——只反映实际发生的绘制(接线坏的判据面)
|
||||
var ctx := _draw_context(canvas)
|
||||
_draw_passage_layer(canvas, ctx)
|
||||
for node in ctx["nodes"]:
|
||||
_draw_room(canvas, node, ctx)
|
||||
|
||||
|
||||
## 绘制上下文束(单次取数——布局/字体/编号空间/可见集,绘制域共享只读面)
|
||||
func _draw_context(canvas: Control) -> Dictionary:
|
||||
var nodes: Array[Variant] = _map._runner.nodes()
|
||||
return {
|
||||
"nodes": nodes,
|
||||
"pos": _layout(nodes, canvas),
|
||||
"font": get_theme_default_font(), # 绘制路径字体单次取用(三处 draw_string 共享——零语义差)
|
||||
"current_id": _map._runner.current_node_id(),
|
||||
# 当前节点 id(单链=下标 / 图=编号)——visited_ids() 已按编号空间解析
|
||||
"visited": _map._runner.visited_ids(),
|
||||
"cand_ids": _map._runner.next_candidate_ids(),
|
||||
"type_vis": _map._runner.type_visible_ids(), # 本停点类型可见集(每帧一取——纯函数零状态)
|
||||
}
|
||||
|
||||
|
||||
## 房间底色域(行进态三色:已到暗金/当前奖励金/未达暗——绘制域与图标域共享)
|
||||
func _room_color(node: Dictionary, ctx: Dictionary) -> Color:
|
||||
var nid := _id_of(node)
|
||||
var col := COL_ROOM_FUTURE
|
||||
if (ctx["visited"] as Array).has(nid):
|
||||
col = COL_ROOM_DONE
|
||||
if nid == ctx["current_id"]:
|
||||
col = COL_ROOM_CURRENT
|
||||
return col
|
||||
|
||||
|
||||
## 通道层绘制域:连线先行画(方块覆盖其上);悬停预承诺 = 所属通道再增亮(加粗)。
|
||||
## 选路停点(候选非空)非候选通道降透明——金岔路从结构网分离(干线共线重叠缺陷的
|
||||
## 视觉主因:不同源通道共用同一垂直干线,金边与石色边焊接成「整列可走」假象)
|
||||
func _draw_passage_layer(canvas: Control, ctx: Dictionary) -> void:
|
||||
var nodes: Array = ctx["nodes"]
|
||||
var pos: Dictionary = ctx["pos"]
|
||||
var cand_ids: Array = ctx["cand_ids"]
|
||||
var dim_passages: bool = not cand_ids.is_empty()
|
||||
for node in nodes:
|
||||
var from: Vector2 = pos[node]
|
||||
@@ -442,61 +488,74 @@ func _draw_graph(canvas: Control) -> void:
|
||||
var target := _node_by_id(tid, nodes)
|
||||
if target.is_empty():
|
||||
continue
|
||||
var to: Vector2 = pos[target]
|
||||
var lit: bool = _id_of(node) == current_id and cand_ids.has(tid)
|
||||
var hovered: bool = lit and _hover_id == tid
|
||||
var lit: bool = _id_of(node) == ctx["current_id"] and cand_ids.has(tid)
|
||||
var col := COL_PASSAGE_LIT if lit else (Color(COL_PASSAGE, 0.35) if dim_passages else COL_PASSAGE)
|
||||
var width := 4.0 if hovered else (3.0 if lit else 2.0) # 2/3/4 三档
|
||||
_draw_passage(canvas, from, to, col, width)
|
||||
# 房间方块
|
||||
for node in nodes:
|
||||
var p: Vector2 = pos[node]
|
||||
var t := String(node.get("type", ""))
|
||||
var nid := _id_of(node)
|
||||
var col := COL_ROOM_FUTURE
|
||||
if visited.has(nid):
|
||||
col = COL_ROOM_DONE
|
||||
if nid == current_id:
|
||||
col = COL_ROOM_CURRENT
|
||||
var rect := Rect2(p - NODE_HALF, NODE_HALF * 2.0)
|
||||
canvas.draw_rect(rect, col)
|
||||
var disp := node_display(node, nid, type_vis, nid == current_id, cand_ids.has(nid))
|
||||
var rec: Dictionary[String, Variant] = {"draw_icon": false, "draw_label": false,
|
||||
"label_text": "", "boss_border": false}
|
||||
if bool(disp["boss_border"]):
|
||||
# Boss 描边 = 紫赤 2px(§4.2 色相独占)+ 外缘 1px 深墨环(灰度冗余通道强制:
|
||||
# 紫赤灰度 72 对石纹噪底 65 灰度不可辨;灰度/色弱下 Boss 环经深墨环可辨)
|
||||
canvas.draw_rect(Rect2(rect.position - Vector2(3, 3), rect.size + Vector2(6, 6)), UiKit.INK_ROUTE, false, 1.0)
|
||||
canvas.draw_rect(rect, COL_BOSS_BORDER, false, 2.0)
|
||||
rec["boss_border"] = true
|
||||
elif cand_ids.has(nid):
|
||||
# 悬停预承诺 = 亮金描边加粗(4px),常态候选 = 亮金描边 2px(spec States 悬停预承诺行)
|
||||
canvas.draw_rect(rect, COL_PASSAGE_LIT, false, 4.0 if _hover_id == nid else 2.0)
|
||||
# 节点图标(20px 烘焙 1:1 消费;双色墨制=乘法调制——当前金底深墨,暗底系 WARM 原色;
|
||||
# 贴图缺位 → 字形回退=贴图在位字形退役惯例)
|
||||
if bool(disp["draw_icon"]):
|
||||
rec["draw_icon"] = true
|
||||
var icon: Texture2D = _node_icons.get(t)
|
||||
if icon != null:
|
||||
var tint := UiKit.ICON_TINT_ON_GOLD if col == COL_ROOM_CURRENT else Color(1.0, 1.0, 1.0)
|
||||
canvas.draw_texture_rect(icon, Rect2(p - Vector2(NODE_ICON_PX, NODE_ICON_PX) / 2.0,
|
||||
Vector2(NODE_ICON_PX, NODE_ICON_PX)), false, tint)
|
||||
else:
|
||||
var label := String(NODE_LABELS.get(t, "?"))
|
||||
canvas.draw_string(font, p + Vector2(-6, 2), label, HORIZONTAL_ALIGNMENT_LEFT, -1, 16, UiKit.INK_ROUTE)
|
||||
# 编号(右上角——与图标占位区零重叠;双色墨随态)
|
||||
var num_ink := UiKit.INK_ROUTE if col == COL_ROOM_CURRENT else UiKit.WARM
|
||||
canvas.draw_string(font, Vector2(rect.end.x - 16.0, rect.position.y + 8.0),
|
||||
str(nid), HORIZONTAL_ALIGNMENT_RIGHT, 14, 10, num_ink)
|
||||
# 类型文字标签(demo ④:节点下方 11px;当前位=「当前位置」金、候选=类型名+「 · 可选」烛光黄、
|
||||
# 其余=类型名暖米弱化;文字+图标+形状三通道)
|
||||
if bool(disp["draw_label"]):
|
||||
rec["draw_label"] = true
|
||||
rec["label_text"] = String(disp["label_text"])
|
||||
var type_ink := COL_ROOM_CURRENT if nid == current_id else (UiKit.CANDLE if cand_ids.has(nid) else UiKit.WARM_FAINT)
|
||||
canvas.draw_string(font, Vector2(p.x - 44.0, rect.end.y + 15.0),
|
||||
String(disp["label_text"]), HORIZONTAL_ALIGNMENT_CENTER, 88, 11, type_ink)
|
||||
_drawn_disp[nid] = rec
|
||||
var width := 4.0 if lit and _hover_id == tid else (3.0 if lit else 2.0) # 2/3/4 三档
|
||||
_draw_passage(canvas, from, pos[target], col, width)
|
||||
|
||||
|
||||
## 房间方块域:底色随行进态+Boss/候选描边+图标/字形+编号+类型文字标签
|
||||
func _draw_room(canvas: Control, node: Dictionary, ctx: Dictionary) -> void:
|
||||
var pos: Dictionary = ctx["pos"]
|
||||
var p: Vector2 = pos[node]
|
||||
var t := String(node.get("type", ""))
|
||||
var nid := _id_of(node)
|
||||
var col := _room_color(node, ctx)
|
||||
var rect := Rect2(p - NODE_HALF, NODE_HALF * 2.0)
|
||||
canvas.draw_rect(rect, col)
|
||||
var disp := node_display(node, nid, ctx["type_vis"], nid == ctx["current_id"], (ctx["cand_ids"] as Array).has(nid))
|
||||
var rec: Dictionary[String, Variant] = {"draw_icon": false, "draw_label": false,
|
||||
"label_text": "", "boss_border": false}
|
||||
if bool(disp["boss_border"]):
|
||||
# Boss 描边 = 紫赤 2px(§4.2 色相独占)+ 外缘 1px 深墨环(灰度冗余通道强制:
|
||||
# 紫赤灰度 72 对石纹噪底 65 灰度不可辨;灰度/色弱下 Boss 环经深墨环可辨)
|
||||
canvas.draw_rect(Rect2(rect.position - Vector2(3, 3), rect.size + Vector2(6, 6)), UiKit.INK_ROUTE, false, 1.0)
|
||||
canvas.draw_rect(rect, COL_BOSS_BORDER, false, 2.0)
|
||||
rec["boss_border"] = true
|
||||
elif (ctx["cand_ids"] as Array).has(nid):
|
||||
# 悬停预承诺 = 亮金描边加粗(4px),常态候选 = 亮金描边 2px(spec States 悬停预承诺行)
|
||||
canvas.draw_rect(rect, COL_PASSAGE_LIT, false, 4.0 if _hover_id == nid else 2.0)
|
||||
if _draw_room_icon(canvas, node, disp, ctx):
|
||||
rec["draw_icon"] = true
|
||||
# 编号(右上角——与图标占位区零重叠;双色墨随态)
|
||||
var num_ink := UiKit.INK_ROUTE if col == COL_ROOM_CURRENT else UiKit.WARM
|
||||
canvas.draw_string(ctx["font"], Vector2(rect.end.x - 16.0, rect.position.y + 8.0),
|
||||
str(nid), HORIZONTAL_ALIGNMENT_RIGHT, 14, 10, num_ink)
|
||||
var label_rec := _draw_room_label(canvas, rect, disp, nid, ctx)
|
||||
rec["draw_label"] = bool(label_rec.get("draw_label", false))
|
||||
rec["label_text"] = String(label_rec.get("label_text", ""))
|
||||
_map._drawn_disp[nid] = rec
|
||||
|
||||
|
||||
## 节点图标域(20px 烘焙 1:1 消费;双色墨制=乘法调制——当前金底深墨,暗底系 WARM 原色;
|
||||
## 贴图缺位 → 字形回退=贴图在位字形退役惯例)
|
||||
func _draw_room_icon(canvas: Control, node: Dictionary, disp: Dictionary, ctx: Dictionary) -> bool:
|
||||
if not bool(disp["draw_icon"]):
|
||||
return false
|
||||
var p: Vector2 = ctx["pos"][node]
|
||||
var col := _room_color(node, ctx)
|
||||
var t := String(node.get("type", ""))
|
||||
var icon: Texture2D = _map._layer_decor.node_icons.get(t)
|
||||
if icon != null:
|
||||
var tint := UiKit.ICON_TINT_ON_GOLD if col == COL_ROOM_CURRENT else Color(1.0, 1.0, 1.0)
|
||||
canvas.draw_texture_rect(icon, Rect2(p - Vector2(NODE_ICON_PX, NODE_ICON_PX) / 2.0,
|
||||
Vector2(NODE_ICON_PX, NODE_ICON_PX)), false, tint)
|
||||
else:
|
||||
var label := String(NODE_LABELS.get(t, "?"))
|
||||
canvas.draw_string(ctx["font"], p + Vector2(-6, 2), label, HORIZONTAL_ALIGNMENT_LEFT, -1, 16, UiKit.INK_ROUTE)
|
||||
return true
|
||||
|
||||
|
||||
## 类型文字标签域(demo ④:节点下方 11px;当前位=「当前位置」金、候选=类型名+「 · 可选」烛光黄、
|
||||
## 其余=类型名暖米弱化;文字+图标+形状三通道)
|
||||
func _draw_room_label(canvas: Control, rect: Rect2, disp: Dictionary, nid: int, ctx: Dictionary) -> Dictionary:
|
||||
if not bool(disp["draw_label"]):
|
||||
return {}
|
||||
var p: Vector2 = rect.position + NODE_HALF # 节点中心反推(方块原点=中心−半宽高)
|
||||
var type_ink := COL_ROOM_CURRENT if nid == ctx["current_id"] else (UiKit.CANDLE if (ctx["cand_ids"] as Array).has(nid) else UiKit.WARM_FAINT)
|
||||
canvas.draw_string(ctx["font"], Vector2(p.x - 44.0, rect.end.y + 15.0),
|
||||
String(disp["label_text"]), HORIZONTAL_ALIGNMENT_CENTER, 88, 11, type_ink)
|
||||
return {"draw_label": true, "label_text": String(disp["label_text"])}
|
||||
|
||||
|
||||
func _layout(nodes: Array, canvas: Control) -> Dictionary:
|
||||
@@ -520,20 +579,20 @@ func _layout(nodes: Array, canvas: Control) -> Dictionary:
|
||||
|
||||
# ---- 探针只读出口(形态仿 fx_probe 先例:只读快照) ----
|
||||
|
||||
# 选路布局只读快照(node → 局部位置;画布固定取现行 _canvas,调用侧零私有域触达)
|
||||
# 选路布局只读快照(node → 局部位置;画布固定取现行 _map._canvas,调用侧零私有域触达)
|
||||
func layout_probe(nodes: Array) -> Dictionary:
|
||||
return _layout(nodes, _canvas)
|
||||
return _layout(nodes, _map._canvas)
|
||||
|
||||
|
||||
# 路由画布只读快照(origin=全局原点;min_size=最小拟合尺寸——画布拟合断言消费面)
|
||||
func canvas_probe() -> Dictionary:
|
||||
return {"origin": _canvas.get_global_position(), "min_size": _canvas.custom_minimum_size}
|
||||
return {"origin": _map._canvas.get_global_position(), "min_size": _map._canvas.custom_minimum_size}
|
||||
|
||||
|
||||
# 类型可见性绘制只读记录(id → 本帧实际绘制事实:图标/文字/描边/文案;_draw_graph 在实际绘制点写入——
|
||||
# 接线层断言消费点:绕开决策面直接画,这里就露出「雾下也画了」)
|
||||
func display_probe() -> Dictionary:
|
||||
return _drawn_disp
|
||||
return _map._drawn_disp
|
||||
|
||||
|
||||
# 分层(layout/fit 共享件):layer = 入口 BFS 深度;同层 slot 垂直排布;未达节点兜底排末层
|
||||
@@ -577,7 +636,7 @@ func _entry(nodes: Array) -> Dictionary:
|
||||
|
||||
|
||||
func _out_ids(node: Dictionary, _nodes: Array) -> Array:
|
||||
return _runner.node_out_ids(node)
|
||||
return _map._runner.node_out_ids(node)
|
||||
|
||||
|
||||
func _node_by_id(nid: int, nodes: Array) -> Dictionary:
|
||||
|
||||
Reference in new issue
Block a user