iter48-卡2:卡②(立绘显示档批): 九件素材原稿分辨率入包(紧裁零降采样,STANDEE_SRC_H九键+产物计数自证)+standee_motion显示档PORTRAIT_DISPLAY_H九键钉值(_place_portrait按档算倍率,缺键push_error按1×)+portrait_probe扩display_size/display_scale+闸件standee_asset_check换口径(源高==原稿表值/显示宽≤150酋长157例外逐字)+样张站桩段按显示档取数(A4解冻重校88×92,V10并排30/30)+V13–V18全绿(50checks)+三面对照图
This commit is contained in:
1 parent
1e35ab947b
commit
4c3f0f6082
9 files changed
+255
-119
No files matched your search
@@ -11,6 +11,9 @@
|
||||
# V10 名字行提档 FS_HINT 14(探针 name_font_size 实读 + 两绘制点源码锚 + FS_CAPTION 计数锚==1);
|
||||
# V11 退役常量不在册 + 掩尘 BRICK 逐位 + 顶缘线/口沿高光两绘制点改指源码锚;
|
||||
# V12 PLAZA_EDGE 逐位 #4C4038 + 回退描边改指源码锚。
|
||||
# V13–V18 立绘显示档(2026-11-01 迭代 48 卡②)——显示档 = 三档绝对高逐键钉值(96/144/188)+
|
||||
# 入包件 = 原稿紧裁零降采样(源高 == 原稿表值)+纵横倍率恒等+主角三态显示 144+
|
||||
# 跨语言显示档表逐键对账+键集恰九键(§8.2 显示档定值单点)。
|
||||
# headless 无渲染面:像素采样以常量单点 + 源码锚 + 探针几何承载(观测面注记,验收对照表 V5 行)。
|
||||
# 运行:godot --headless --path game --script res://tests/unit/presentation/standee_present_values_test.gd(expect 0)
|
||||
extends SceneTree
|
||||
@@ -110,4 +113,94 @@ func _init() -> void:
|
||||
else "护甲三枚入包(24×24)〔样张批 V9〕",
|
||||
tex9 != null and tex9.get_width() == 24 and tex9.get_height() == 24)
|
||||
|
||||
# ---- V13–V18 立绘显示档(迭代 48 卡②) ----
|
||||
_check_display_tier()
|
||||
|
||||
quit(Kit.finish("standee_present_values"))
|
||||
|
||||
|
||||
# ---- V13–V18 立绘显示档(迭代 48 卡②——显示档 = 三档绝对高,入包件 = 原稿紧裁零降采样) ----
|
||||
|
||||
# 规格钉值(显示档定值单点 = art-bible §8.2;源高 = 原稿表值——旧降采样稿必红;
|
||||
# 显示宽 = round(源宽×档高/源高),食人魔酋长 157 为已接受超宽项):
|
||||
# 键 → [源高, 显示档高, 显示宽]
|
||||
const _DISPLAY_SPEC := {
|
||||
"goblin": [90, 96, 95], "giant_spider": [81, 96, 121], "duergar": [126, 96, 71],
|
||||
"hook_horror": [94, 144, 113], "bugbear": [123, 144, 119], "hero": [92, 144, 138],
|
||||
"ogre_chief": [189, 188, 157], "drider": [189, 188, 139], "duergar_king": [189, 188, 132],
|
||||
}
|
||||
|
||||
|
||||
func _enemy_tex_path(key: String) -> String:
|
||||
return "res://assets/art/character/character_enemy_%s.png" % key
|
||||
|
||||
|
||||
func _check_display_tier() -> void:
|
||||
# V13/V15 九键逐一:真实入口 StandeeBody → set_data(enemy_id) → set_portrait_texture(真纹理) → portrait_probe
|
||||
for key: String in _DISPLAY_SPEC:
|
||||
var spec: Array = _DISPLAY_SPEC[key]
|
||||
var body: Node2D = StandeeBodyScript.new("hero" if key == "hero" else "enemy")
|
||||
root.add_child(body)
|
||||
var tex: Texture2D = UiKit.load_tex(UiKit.TEX_HERO_PORTRAIT if key == "hero" else _enemy_tex_path(key))
|
||||
if key == "hero":
|
||||
body.set_portrait_texture(tex, true)
|
||||
else:
|
||||
body.set_data({"display_name": key, "enemy_id": key, "hp": 3, "max_hp": 3,
|
||||
"order": 1, "armor_type": "light"})
|
||||
body.set_portrait_texture(tex, false)
|
||||
var pp: Dictionary = body.portrait_probe()
|
||||
Kit.check("显示档 %s:源高 %d(原稿表值——旧降采样稿必红)+显示高 %d 逐键钉值〔立绘显示档 V13〕"
|
||||
% [key, int(spec[0]), int(spec[1])],
|
||||
tex != null and int(tex.get_height()) == int(spec[0])
|
||||
and is_equal_approx(float(pp.display_size.y), float(spec[1]))
|
||||
and is_equal_approx(float(pp.display_scale) * float(tex.get_height()), float(spec[1])))
|
||||
Kit.check("显示档 %s:纵横倍率恒等(双轴同倍率)+显示宽随源比例(round 档 %d)〔立绘显示档 V15〕"
|
||||
% [key, int(spec[2])],
|
||||
is_equal_approx(float(pp.display_size.x), float(tex.get_width()) * float(pp.display_scale))
|
||||
and is_equal_approx(float(pp.display_size.y), float(tex.get_height()) * float(pp.display_scale))
|
||||
and absf(float(pp.display_size.x) - float(spec[2])) < 0.51)
|
||||
body.queue_free()
|
||||
# V14 静态源锚:显示档表读表单点 + 零硬编码 2× 倍率
|
||||
var motion_src := _read_source("res://presentation/views/standee_motion.gd")
|
||||
Kit.check("显示档表单点在位(_place_portrait 读 PORTRAIT_DISPLAY_H)且零 Vector2(2.0, 2.0) 字面倍率〔立绘显示档 V14〕",
|
||||
motion_src.contains("PORTRAIT_DISPLAY_H") and not motion_src.contains("Vector2(2.0, 2.0)"))
|
||||
# V16 主角三态:组合根装载(hero_tex 注册链)→ 逐态 apply_hero_state 复读探针
|
||||
var stage_view: Node = load("res://presentation/views/battle_stage_view.gd").new(null, load("res://data/tables/battle_layout.tres"))
|
||||
root.add_child(stage_view)
|
||||
var hs: Node2D = stage_view.hero_standee
|
||||
var pp0: Dictionary = hs.portrait_probe()
|
||||
Kit.check("主角 normal 态:源高 ≥92 且显示高 144(组合根真实装载链)〔立绘显示档 V16〕",
|
||||
bool(pp0.has_tex) and is_equal_approx(float(pp0.display_size.y), 144.0))
|
||||
for hstate: String in ["attack", "hit"]:
|
||||
hs.set_hero_state(hstate)
|
||||
var pph: Dictionary = hs.portrait_probe()
|
||||
Kit.check("主角 %s 态:源高 ≥92 且显示高 144(三态同档)〔立绘显示档 V16〕" % hstate,
|
||||
bool(pph.has_tex) and is_equal_approx(float(pph.display_size.y), 144.0))
|
||||
stage_view.queue_free()
|
||||
# V17 跨语言对账:Python 显示档表(STANDEE_DISPLAY_H 八敌 + STANDEE_SLOT_H 主角)逐键 == GDScript 表
|
||||
# (读不到工具源 = L2 记录退回双端字面钉值+独立审计对账——禁当红亦禁当绿)
|
||||
var py_src := ""
|
||||
for py_path: String in ["../tools/pixelize_candidates.py", "tools/pixelize_candidates.py"]:
|
||||
var pf := FileAccess.open(py_path, FileAccess.READ)
|
||||
if pf != null:
|
||||
py_src = pf.get_as_text()
|
||||
break
|
||||
if py_src.is_empty():
|
||||
print("[L2] V17 工具源不可读(../tools/ 路径不通)——退回双端字面钉值+独立审计对账(记录不判红)")
|
||||
else:
|
||||
var py_ok := true
|
||||
for key: String in _DISPLAY_SPEC:
|
||||
if key == "hero":
|
||||
py_ok = py_ok and py_src.contains("STANDEE_SLOT_H = %d" % int(_DISPLAY_SPEC[key][1]))
|
||||
else:
|
||||
py_ok = py_ok and py_src.contains("\"%s\": %d" % [key, int(_DISPLAY_SPEC[key][1])])
|
||||
Kit.check("Python 显示档表与 GDScript PORTRAIT_DISPLAY_H 九键逐键相等(源文本对账)〔立绘显示档 V17〕", py_ok)
|
||||
# V18 键集恰九键(八敌 ∪ hero,无多余键——防新敌种漏登记被 push_error 静默)
|
||||
var motion_script: Script = load("res://presentation/views/standee_motion.gd")
|
||||
var mcmap: Dictionary = motion_script.get_script_constant_map()
|
||||
var disp_tbl: Dictionary = mcmap.get("PORTRAIT_DISPLAY_H", {})
|
||||
var keys_ok: bool = disp_tbl.size() == 9
|
||||
for k: String in ["bugbear", "drider", "duergar", "duergar_king", "giant_spider",
|
||||
"goblin", "hook_horror", "ogre_chief", "hero"]:
|
||||
keys_ok = keys_ok and disp_tbl.has(k)
|
||||
Kit.check("显示档表键集 = 八敌 ∪ hero 恰九键(无多余键)〔立绘显示档 V18〕", keys_ok)
|
||||
Reference in new issue
Block a user