merge: 状态图标接入批——定稿九枚入 HUD 状态槽(2026-09-24,台账 156)
No files matched your search
|
After Width: | Height: | Size: 297 B |
|
After Width: | Height: | Size: 207 B |
|
After Width: | Height: | Size: 264 B |
|
After Width: | Height: | Size: 260 B |
|
After Width: | Height: | Size: 264 B |
|
After Width: | Height: | Size: 297 B |
|
After Width: | Height: | Size: 303 B |
|
After Width: | Height: | Size: 252 B |
|
After Width: | Height: | Size: 252 B |
@@ -2,7 +2,8 @@
|
||||
# 实现 GDD:design/ux/battle.md(B 区全站桩形态——2026-09-20 用户看对照样张拍板,台账 99:
|
||||
# 主角与敌人均为无框立绘+底座,英雄卡/敌人卡卡片式整体退役禁再提)。
|
||||
# 形态契约:无框立绘(程序占位字形;set_portrait_texture = 资产挂点,战斗表现样张批落位零代码换装)
|
||||
# + 底座;血条悬浮头顶;状态小图标一排挂血条正下方(形状+色相双通道、层数角标同 C 区状态槽键——
|
||||
# + 底座;血条悬浮头顶;状态小图标一排挂血条正下方(2026-09-24 状态图标接入批:定稿 PNG 纹理
|
||||
# 取代程序化占位字形,极性染色退役——绿↑红↓极性语言内化于图标本体;层数 ×N 角标保留;
|
||||
# 词汇单点复用 StatusSlotRow.EFFECT_ICON,未知键同款 fail-fast + ? 占位)。
|
||||
# 敌方专属:顺位徽标悬浮头顶;意图三档动作动画占位(表现层升级批拍板:不显示技能名——普攻零表示 /
|
||||
# 攻击系 ⚔ / 增益系 ✦ / 妨害系 ☠ / 蓄力 = ⚔ 金档;开轮摇定播一次性短动画后静帧保持,
|
||||
@@ -151,18 +152,32 @@ func set_idle() -> void:
|
||||
set_effects([])
|
||||
|
||||
|
||||
# 主角/敌方共用——状态小图标行重建(B 区迷你版:icon + 层数角标;完整 tooltip 义务归 C 区状态槽)
|
||||
# 主角/敌方共用——状态小图标行重建(B 区迷你版:定稿纹理 16px + 层数 ×N 角标;
|
||||
# 完整 tooltip 义务归 C 区状态槽。2026-09-24 状态图标接入批:占位字形+极性染色退役)
|
||||
func set_effects(effects: Array) -> void:
|
||||
for c in _status_row.get_children():
|
||||
_status_row.remove_child(c)
|
||||
c.queue_free()
|
||||
for eff in effects:
|
||||
var cfg: Array = _icon_cfg(String(eff.get("effect_id", "")))
|
||||
var tex := _icon_tex(String(eff.get("effect_id", "")))
|
||||
var layers := maxi(1, int(eff.get("layers", 1)))
|
||||
var lab := UiKit.label(String(cfg[0]) + ("×%d" % layers if layers > 1 else ""), 12, true)
|
||||
lab.add_theme_color_override("font_color", cfg[1])
|
||||
lab.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_status_row.add_child(lab)
|
||||
if tex != null:
|
||||
var icon := TextureRect.new()
|
||||
icon.texture = tex
|
||||
icon.custom_minimum_size = Vector2(16, 16) # 32px 源 ÷2 整数档缩放
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR
|
||||
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_status_row.add_child(icon)
|
||||
else:
|
||||
var ph := UiKit.label(StatusSlotRow.ICON_PLACEHOLDER, 12, true) # release 回退占位(debug 已断言)
|
||||
ph.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_status_row.add_child(ph)
|
||||
if layers > 1:
|
||||
var lab := UiKit.label("×%d" % layers, 12, true)
|
||||
lab.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_status_row.add_child(lab)
|
||||
|
||||
|
||||
func set_order(i: int) -> void:
|
||||
@@ -283,10 +298,10 @@ func _refresh_portrait_glyph() -> void:
|
||||
|
||||
|
||||
# 状态图标键解析(词汇单点复用 C 区 StatusSlotRow——HUD框架:查不到的键按错误处理,
|
||||
# 立即断言 + ? 占位纹样 + 诊断,禁止静默显示空图标)
|
||||
func _icon_cfg(effect_id: String) -> Array:
|
||||
# 立即断言 + ? 占位 + 诊断,禁止静默显示空图标)
|
||||
func _icon_tex(effect_id: String) -> Texture2D:
|
||||
if StatusSlotRow.EFFECT_ICON.has(effect_id):
|
||||
return StatusSlotRow.EFFECT_ICON[effect_id]
|
||||
push_error("[站桩] 未知状态图标键(映射表外键——立即断言): %s" % effect_id)
|
||||
assert(false, "未知状态图标键: " + effect_id)
|
||||
return ["?", UiKit.PANEL_BORDER, "?"]
|
||||
return null
|
||||
@@ -1,7 +1,9 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# 实现 GDD:design/ux/battle.md(C 区状态效果槽 ×4〔增益状态 D1×①〕——effect_id→icon 形状+色相双通道、
|
||||
# 实现 GDD:design/ux/battle.md(C 区状态效果槽 ×4〔增益状态 D1×①〕——effect_id→定稿 PNG 纹理图标、
|
||||
# 层数角标、剩余结算次数点、悬停 tooltip(来源+语义+剩余);空态 = 槽隐藏(数据框上移补位,
|
||||
# EC12 空态裁决);极性映射 = 战斗结算 SettlementTable 效果语义而非 magnitude 符号〔增益状态 D1×③〕)。
|
||||
# 2026-09-24 状态图标接入批:程序化占位字形(▲◇▼◎⚔✕☾⇧▣)+ 按极性染色退役——定稿九枚 PNG
|
||||
# (白剑/白盾/白眼+绿↑红↓箭头语言,用户逐键验收,圣经 §4.6.1 v2.2 纹样系统)自带极性,裸图标呈现。
|
||||
# Date: 2026-09-12
|
||||
# 高内聚边界:纯视图——效果投影装配归 hud_presenter.gd;增益状态 纯被动容器零信号——刷新绑 战斗结算
|
||||
# 结算编排完成时点(battle.md 更新触发注记)。
|
||||
@@ -9,22 +11,28 @@ class_name StatusSlotRow
|
||||
extends HBoxContainer
|
||||
|
||||
const MAX_SLOTS := 4
|
||||
# 极性/语义映射(数据源 = SettlementTable.effect_pool_map 效果语义 + StatusEffectTable display_name):
|
||||
# 益 = ▲/◆/▼/◇(金/蓝族);害 = ⚡/⚔/✕/☾/⇧/▣(旗朱族;⇧/▣ = 敌方增益威胁纹样)——形状+色相双通道,
|
||||
# 文字名常驻第三通道。状态表九行全映射(attack_up/ac_up/weaken/alert/enrage/off_guard/sapped/empower/fortify)
|
||||
# ——HUD框架 图标键契约"一键一枚专属纹样,查不到的键立即断言 + ? 占位 + 诊断"
|
||||
# 纹理映射(2026-09-24 状态图标接入批):effect_id→定稿纹理,全局恒定禁换图(图标键契约 §4.6 的
|
||||
# 文件侧延伸——文件键 = status_<effect_id>.png,命名规范圣经 §8.3「对象键 = 数据表主键」)。
|
||||
# 状态表九行全映射(attack_up/ac_up/weaken/alert/enrage/off_guard/sapped/empower/fortify)
|
||||
# ——HUD框架 图标键契约"一键一枚专属纹样,查不到的键立即断言 + 占位 + 诊断"
|
||||
# (2026-09-15 格面资源批补 sapped;2026-09-16 护甲等级掷点批 defense_up → ac_up 换装;
|
||||
# 同日 敌人技能池批补 empower/fortify 敌方增益两键——敌方增益显示 = 敌卡状态行文本 + 本图标键词汇)。
|
||||
const EFFECT_ICON := {
|
||||
"attack_up": ["▲", UiKit.GOLD_DEEP, "益"],
|
||||
"ac_up": ["◇", UiKit.HERO_BLUE, "益"],
|
||||
"weaken": ["▼", UiKit.HERO_BLUE, "益"],
|
||||
"alert": ["◎", UiKit.FLAG_RED, "害"],
|
||||
"enrage": ["⚔", UiKit.FLAG_RED, "害"],
|
||||
"off_guard": ["✕", UiKit.FLAG_RED, "害"],
|
||||
"sapped": ["☾", UiKit.FLAG_RED, "害"],
|
||||
"empower": ["⇧", UiKit.FLAG_RED, "害"],
|
||||
"fortify": ["▣", UiKit.PANEL_BORDER, "害"],
|
||||
"attack_up": preload("res://assets/ui/icons/status_attack_up.png"),
|
||||
"ac_up": preload("res://assets/ui/icons/status_ac_up.png"),
|
||||
"weaken": preload("res://assets/ui/icons/status_weaken.png"),
|
||||
"alert": preload("res://assets/ui/icons/status_alert.png"),
|
||||
"enrage": preload("res://assets/ui/icons/status_enrage.png"),
|
||||
"off_guard": preload("res://assets/ui/icons/status_off_guard.png"),
|
||||
"sapped": preload("res://assets/ui/icons/status_sapped.png"),
|
||||
"empower": preload("res://assets/ui/icons/status_empower.png"),
|
||||
"fortify": preload("res://assets/ui/icons/status_fortify.png"),
|
||||
}
|
||||
# 极性词(tooltip 第三通道;运行时不再按极性染色/画框——绿↑红↓极性语言已内化于定稿图标本体)
|
||||
const EFFECT_POLARITY := {
|
||||
"attack_up": "益", "ac_up": "益", "weaken": "益",
|
||||
"alert": "害", "enrage": "害", "off_guard": "害",
|
||||
"sapped": "害", "empower": "害", "fortify": "害",
|
||||
}
|
||||
const EFFECT_SEMANTIC := {
|
||||
"attack_up": "主角攻击加成(hero_offense 池加算)",
|
||||
@@ -38,8 +46,8 @@ const EFFECT_SEMANTIC := {
|
||||
"fortify": "敌方防御 −50(enemy_defense 池——硬化技施放,主角攻击 ×0.5;持续 1 个有效结算)",
|
||||
}
|
||||
const SOURCE_NAMES := {"safe_cell": "安全格", "flag_hit": "标中旗", "mine_hit": "踩雷", "clear_reward": "清图奖励"}
|
||||
# 未知图标键的占位纹样(HUD框架:占位也要可见,禁静默空图标)
|
||||
const ICON_PLACEHOLDER := ["?", UiKit.PANEL_BORDER, "?"]
|
||||
# 未知图标键的占位(HUD框架:占位也要可见,禁静默空图标——debug 断言先行,release 回退槽内 ? 文本)
|
||||
const ICON_PLACEHOLDER := "?"
|
||||
|
||||
var _tip: PanelContainer
|
||||
var _tip_label: Label
|
||||
@@ -71,15 +79,13 @@ func set_effects(effects: Array) -> void:
|
||||
_slots[i].visible = true
|
||||
|
||||
|
||||
# battle_over 反馈(增益状态×4④):逐槽化光收回 + 微文案(下次 set_effects 恢复常态)
|
||||
# battle_over 反馈(增益状态×4④):逐槽化光收回 + 微灰化(下次 set_effects 恢复常态;
|
||||
# 2026-09-24 状态图标接入批:原字形 "✕ " 前缀随占位字形退役,灰化即清场反馈)
|
||||
func set_cleared_feedback() -> void:
|
||||
_cleared_feedback = true
|
||||
for slot in _slots:
|
||||
slot.visible = true
|
||||
slot.modulate = Color(0.7, 0.7, 0.7, 0.5)
|
||||
var col := slot.get_child(0) as VBoxContainer
|
||||
var icon := col.get_child(0) as Label
|
||||
icon.text = "✕ " + icon.text
|
||||
|
||||
|
||||
func _sync_slots(n: int) -> void:
|
||||
@@ -105,8 +111,13 @@ func _make_slot() -> PanelContainer:
|
||||
var col := VBoxContainer.new()
|
||||
col.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
slot.add_child(col)
|
||||
var icon := UiKit.label("", 16, true)
|
||||
icon.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
# 定稿纹理图标(32px 源 → 24px 槽内呈现;线性过滤匹配抗锯齿矢量风源图)
|
||||
var icon := TextureRect.new()
|
||||
icon.custom_minimum_size = Vector2(24, 24)
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
icon.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR
|
||||
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
col.add_child(icon)
|
||||
var meta := UiKit.label("", 11, false)
|
||||
meta.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
@@ -118,17 +129,19 @@ func _fill_slot(slot: PanelContainer, eff: Dictionary) -> void:
|
||||
slot.modulate = Color(1, 1, 1)
|
||||
slot.set_meta("eff", eff)
|
||||
var col := slot.get_child(0) as VBoxContainer
|
||||
var icon := col.get_child(0) as Label
|
||||
var icon := col.get_child(0) as TextureRect
|
||||
var meta := col.get_child(1) as Label
|
||||
var icon_cfg: Array = _icon_cfg(String(eff.effect_id))
|
||||
icon.text = String(icon_cfg[0])
|
||||
icon.add_theme_color_override("font_color", icon_cfg[1])
|
||||
# 层数角标 + 剩余结算次数点(● 未耗余量)
|
||||
# 层数角标 + 剩余结算次数点(● 未耗余量)——叠层数字呈现逻辑保持不动
|
||||
var dots := ""
|
||||
var left: int = int(eff.get("remaining_settlements", 0))
|
||||
for i in maxi(left, 1):
|
||||
dots += "●" if i < left else "○"
|
||||
meta.text = "×%d %s" % [int(eff.get("layers", 1)), dots]
|
||||
var tex := _icon_tex(String(eff.effect_id))
|
||||
icon.visible = tex != null
|
||||
icon.texture = tex
|
||||
if tex == null:
|
||||
meta.text = ICON_PLACEHOLDER + " " + meta.text # release 回退占位(debug 已断言)
|
||||
|
||||
|
||||
func _on_slot_hover(slot: Control) -> void:
|
||||
@@ -136,11 +149,11 @@ func _on_slot_hover(slot: Control) -> void:
|
||||
if not slot.has_meta("eff"):
|
||||
return
|
||||
var eff: Dictionary = slot.get_meta("eff")
|
||||
var icon_cfg: Array = _icon_cfg(String(eff.effect_id))
|
||||
var eid := String(eff.effect_id)
|
||||
var src: String = String(SOURCE_NAMES.get(String(eff.get("source_class", "")), String(eff.get("source_class", ""))))
|
||||
var semantic: String = String(EFFECT_SEMANTIC.get(String(eff.effect_id), String(eff.get("display_name", ""))))
|
||||
var semantic: String = String(EFFECT_SEMANTIC.get(eid, String(eff.get("display_name", ""))))
|
||||
_tip_label.text = "%s〔%s〕\n%s\n剩余结算 %d 次\n来源:%s(第 %d 轮)" % [
|
||||
String(eff.get("display_name", "")), String(icon_cfg[2]), semantic,
|
||||
String(eff.get("display_name", "")), String(EFFECT_POLARITY.get(eid, ICON_PLACEHOLDER)), semantic,
|
||||
int(eff.get("remaining_settlements", 0)), src, int(eff.get("round_index", 0))]
|
||||
if not _tip.is_inside_tree():
|
||||
add_child(_tip)
|
||||
@@ -159,10 +172,10 @@ func _on_slot_hover(slot: Control) -> void:
|
||||
_tip.visible = true
|
||||
|
||||
|
||||
# 图标键解析(HUD框架:查不到的键按错误处理——立即断言 + ? 占位纹样 + 诊断,禁止静默显示空图标)
|
||||
func _icon_cfg(effect_id: String) -> Array:
|
||||
# 图标键解析(HUD框架:查不到的键按错误处理——立即断言 + 占位 + 诊断,禁止静默显示空图标)
|
||||
func _icon_tex(effect_id: String) -> Texture2D:
|
||||
if EFFECT_ICON.has(effect_id):
|
||||
return EFFECT_ICON[effect_id]
|
||||
push_error("[状态槽] 未知图标键(映射表外键——立即断言): %s" % effect_id)
|
||||
assert(false, "未知图标键: " + effect_id)
|
||||
return ICON_PLACEHOLDER
|
||||
return null
|
||||
@@ -137,20 +137,21 @@ func _ready() -> void:
|
||||
elif slots_row._slots.size() != 1 or slots_row._slots[0] == slots_row._tip:
|
||||
problems.append("BUG-0001 回归:tooltip 入树后槽引用错位")
|
||||
else:
|
||||
var icon_lab: Label = slots_row._slots[0].get_child(0).get_child(0)
|
||||
if icon_lab.text != "▲":
|
||||
problems.append("BUG-0001 回归:悬停后重刷槽未填充(icon=%s)" % icon_lab.text)
|
||||
var icon_rect: TextureRect = slots_row._slots[0].get_child(0).get_child(0)
|
||||
if icon_rect.texture == null:
|
||||
problems.append("BUG-0001 回归:悬停后重刷槽未填充(texture=null)")
|
||||
slots_row.set_effects([probe_eff[0], probe_eff[0], probe_eff[0], probe_eff[0], probe_eff[0], probe_eff[0]])
|
||||
if slots_row._slots.size() != 4:
|
||||
problems.append("BUG-0001 回归:超上限效果未截断至 4 槽(%d)" % slots_row._slots.size())
|
||||
slots_row.set_effects([])
|
||||
if not slots_row._slots.is_empty():
|
||||
problems.append("BUG-0001 回归:空态未清槽(%d)" % slots_row._slots.size())
|
||||
# ---- 图标键回归(HUD框架 图标键契约:状态表七行全映射、格面资源 cell_type 九型全映射〔gp 键 = 九型批 2026-09-20〕;
|
||||
# 查不到的键 fail-fast + ? 占位——此处钉死映射不残缺,未知键断言由 _icon_cfg/_badge_glyph 承担)----
|
||||
if not StatusSlotRow.EFFECT_ICON.has("enrage") or not StatusSlotRow.EFFECT_ICON.has("off_guard") \
|
||||
or not StatusSlotRow.EFFECT_ICON.has("sapped"):
|
||||
problems.append("状态图标表缺暴走/失衡/乏力键(states 表七行须全映射)")
|
||||
# ---- 图标键回归(HUD框架 图标键契约:状态表九行全映射〔定稿 PNG 纹理,2026-09-24 状态图标接入批〕、
|
||||
# 格面资源 cell_type 九型全映射〔gp 键 = 九型批 2026-09-20〕;查不到的键 fail-fast + ? 占位
|
||||
# ——此处钉死映射不残缺,未知键断言由 _icon_tex/_badge_glyph 承担)----
|
||||
for eid in ["attack_up", "ac_up", "alert", "weaken", "enrage", "off_guard", "sapped", "empower", "fortify"]:
|
||||
if not StatusSlotRow.EFFECT_ICON.has(eid) or StatusSlotRow.EFFECT_ICON[eid] == null:
|
||||
problems.append("状态图标九键纹理映射缺失(%s)" % eid)
|
||||
for cat in ["attack", "defense", "heal", "blast", "weaken", "pierce", "magic", "action", "gp"]:
|
||||
if not BoardView.REWARD_BADGE.has(cat):
|
||||
problems.append("奖励图标表缺键(%s)" % cat)
|
||||
@@ -162,12 +163,12 @@ func _ready() -> void:
|
||||
if slots_row._slots.size() != 2:
|
||||
problems.append("图标键回归:enrage/off_guard 未建槽(%d)" % slots_row._slots.size())
|
||||
else:
|
||||
var ic_enrage: Label = slots_row._slots[0].get_child(0).get_child(0)
|
||||
var ic_off: Label = slots_row._slots[1].get_child(0).get_child(0)
|
||||
if ic_enrage.text == "?" or ic_enrage.text == "":
|
||||
problems.append("暴走图标键未映射(icon=%s)" % ic_enrage.text)
|
||||
if ic_off.text == "?" or ic_off.text == "":
|
||||
problems.append("失衡图标键未映射(icon=%s)" % ic_off.text)
|
||||
var ic_enrage: TextureRect = slots_row._slots[0].get_child(0).get_child(0)
|
||||
var ic_off: TextureRect = slots_row._slots[1].get_child(0).get_child(0)
|
||||
if ic_enrage.texture == null:
|
||||
problems.append("暴走图标键未映射(texture=null)")
|
||||
if ic_off.texture == null:
|
||||
problems.append("失衡图标键未映射(texture=null)")
|
||||
slots_row.set_effects([])
|
||||
# ---- L2 单场段(debug_session 单场原语 + 去饱和接口可用性;雾格机制已整体移除,不再断言变体呈现)----
|
||||
# 2026-09-13 单场用户入口已删——探针直调 debug_session 原语(battle_created/ready 仍经组合根接线;
|
||||
|
||||