Files
gplan-2/game/probe/layout_probe.gd
T

94 lines
4.5 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VERTICAL SLICE - NOT FOR PRODUCTION
# 布局几何断言探针(现行事实源=tools/probe_gate.sh 默认段;呈现层三区布局的分辨率维度验收)
# 用途:battle.md §验收「1280×800 与 16:9 全屏下三区无遮挡/无重叠/无裁切」的可执行化
# GDD 锚:design/gdd/ux/battle.md §Layout Zones(B/C/D 三区几何)
# 硬约束:档位表是数据、断言是一份函数据——加档只改表不动断言(禁每档建一个探针)
extends Node
const ProbeUiUtil := preload("res://probe/probe_ui_util.gd") # 隔离样板单点
# 分辨率档位表(逻辑视口尺寸;数据侧——增删档位只改这里,断言代码零改动)
const VIEWPORTS := [
{"label": "基座 1280x800", "size": Vector2i(1280, 800)},
{"label": "16:9 全屏 1920x1080", "size": Vector2i(1920, 1080)},
]
const MIN_CELL := 36.0 # 格子可读门槛(battle.md §棋盘格尺寸公式 1280 档 12×12 → 36px)
var _problems: PackedStringArray = []
func _ready() -> void:
await get_tree().process_frame
var main: Node = load("res://presentation/main.tscn").instantiate()
add_child(main)
await get_tree().process_frame
ProbeUiUtil.isolate_save(main, "smoke_layout_probe", true, false, true)
main.debug_overlay.seed_edit.text = "42" # 种子钉死(确定性禁依赖默认随机分支)
main._start_adventure_from_menu()
for i in range(8):
await get_tree().process_frame
# 进战斗屏——三区(B 战斗画面/C 角色信息/D 扫雷图)同屏常驻,菜单屏不构成断言面
main.level_screen.press_candidate(0)
for i in range(20):
await get_tree().process_frame
for vp in VIEWPORTS:
# content_scale_size 是headless 下改逻辑视口的唯一有效入口(get_window().size
# 在 headless 下不改变视口——用旧 API 会得到永远为真的假断言)
get_tree().root.content_scale_size = vp["size"]
for i in range(5):
await get_tree().process_frame
_check_one(vp["label"], main)
# 复原本项目基座(探针不该把进程留在末档尺寸)
get_tree().root.content_scale_size = Vector2i(1280, 800)
if _problems.is_empty():
print("[layout_probe] PASS — %d 档几何不变量全过(三区非零/不越视口/互不重叠/view 含于 D 区/格子 ≥%.0fpx)"
% [VIEWPORTS.size(), MIN_CELL])
get_tree().quit(0)
else:
for p in _problems:
print("[layout_probe] FAIL — " + p)
print("[layout_probe] FAIL — %d 项断言未过" % _problems.size())
get_tree().quit(1)
# 一份不变量断言,逐档代入——代码量与档数无关
func _check_one(label: String, main: Node) -> void:
var vr: Rect2 = get_viewport().get_visible_rect()
if vr.size != Vector2(VIEWPORTS[0]["size"]) and vr.size.y < 1.0:
_problems.append("[%s] 逻辑视口退化 %s" % [label, vr.size])
var rects := {}
for key in ["stage", "info_panel", "board_zone"]:
var ctl: Control = main.get(key)
if ctl == null:
_problems.append("[%s] %s = null(三区未装配)" % [label, key])
return
var r := Rect2(ctl.global_position, ctl.size)
rects[key] = r
if r.size.x <= 0.0 or r.size.y <= 0.0:
_problems.append("[%s] %s 零尺寸 %s" % [label, key, r.size])
elif not vr.encloses(r):
_problems.append("[%s] %s 越视口 %s ⊄ %s" % [label, key, r, vr])
# 判据覆盖边界(如实记录,勿当已拦截):本探针按名点名三区做几何判定,
# 不遍历战斗屏宿主的全部后代——「未登记兄弟控件」(如向装配器塞一个挂在
# battle_root 内层根下的全幅 ColorRect)这一缺陷类不在本探针拦截面内,探针对此仍全绿。
# 要拦它得改为递归遍历全子树找重叠,那是另一套判据(且极易误报容器父子关系),
# 本探针不设此判据。
var bv: Control = main.board_view
if bv == null:
_problems.append("[%s] board_view = null" % label)
return
var br := Rect2(bv.global_position, bv.size)
if not vr.encloses(br):
_problems.append("[%s] board_view 越视口 %s ⊄ %s" % [label, br, vr])
if rects.has("board_zone") and not rects["board_zone"].encloses(br):
_problems.append("[%s] board_view 越出 board_zone(%s ⊄ %s)"
% [label, br, rects["board_zone"]])
var keys := rects.keys()
for i in range(keys.size()):
for j in range(i + 1, keys.size()):
if rects[keys[i]].intersects(rects[keys[j]]):
_problems.append("[%s] 顶层区重叠 %s×%s(%s ∩ %s)"
% [label, keys[i], keys[j], rects[keys[i]], rects[keys[j]]])
var cell: float = main.board_view.get("cell_size")
if cell < MIN_CELL:
_problems.append("[%s] 格子边长 %.1fpx < 可读门槛 %.0fpx" % [label, cell, MIN_CELL])