iter9-T14: 卡⑭ 营地界面视觉终稿(对照方向稿 4-camp.png 重排)——石纹全屏底(浅 dim 透出)+顶栏铭牌(标题+副题)/钥石徽(暗底金文)+三柜台列(属性锻造/道具工坊/奖励格图鉴:头带深棕 122,82,50+米板身+内嵌行板,暗底暖白族→亮板深墨族双色墨制)+底栏关闭钮/操作注记+最近冒险收条带;行结构短格式(名 +N/级/Lv/价签 N 钥石——列宽收敛防溢出,行文=代拍板);信号面/投影契约零变化(buy_requested/closed、open_camp/refresh_camp、_forge_rows 行键——探针依赖面保持);闸=冒烟 596/0+click 问题=0(营地购买真实路径)+doc 三闸零新增+熵增 PASS
This commit is contained in:
1 parent
9ab540ee9a
commit
c7646c5489
1 file changed
+137
-79
@@ -1,15 +1,13 @@
|
||||
# VERTICAL SLICE - NOT FOR PRODUCTION
|
||||
# Date: 2026-09-21(元进度实现批——营地覆盖层呈现)
|
||||
# 营地覆盖层(模态):标题「营地 · 永久强化」+ 钥石余额 / 柜台一「属性锻造」(三行可购——显示名 ·
|
||||
# 当前 Lv · 每级 +flat · 下级价格 · 购买按钮余额不足禁用)/ 柜台二「道具工坊」(六行——显示名 ·
|
||||
# 解锁条件 · 进度 · 状态;局内效果排 Alpha 魔法道具重设计批——代拍板 3,注记一行)/ 柜台三
|
||||
# 「奖励格图鉴」(占位锁定行——内容排 Alpha 地图战斗资源差异化批——代拍板 4)/「最近冒险」列表
|
||||
# (recent_summaries 投影:结果/通关数/钥石合计/种子)/ 关闭按钮。
|
||||
# 挂接方式:仿 ShopOverlay(dim + CenterContainer + box);开合与开始层互斥仿 TunePanel 先例
|
||||
# (开始覆盖层非模态且树序在后——打开本层前由组合根隐藏开始层,规范 2.3 遮挡纪律)。
|
||||
# Date: 2026-09-21(元进度实现批——营地覆盖层呈现;2026-09-30 迭代 9 卡⑭ 视觉终稿——对照营地屏
|
||||
# 方向稿 artwork/mockups/v3-draft-2026-09-29/4-camp.png 重排:石纹全屏底 + 顶栏铭牌/钥石徽 +
|
||||
# 三柜台列(属性锻造/道具工坊/奖励格图鉴,头带深棕+米色板身+内嵌行板,暗底→亮板双色墨制)+
|
||||
# 底栏关闭钮/操作注记;最近冒险收底栏条带。信号面/投影契约零变化:buy_requested(attr)/closed、
|
||||
# open_camp(data)/refresh_camp(data)、_forge_rows 行结构 {attr,level_l,price_l,btn}(探针依赖)。
|
||||
# 挂接方式:开合与开始层互斥仿 TunePanel 先例(开始覆盖层非模态且树序在后——打开本层前由组合根
|
||||
# 隐藏开始层,规范 2.3 遮挡纪律)。
|
||||
# 高内聚边界:纯视图 setter 面——账本快照经组合根喂入(MetaProgression 只读投影),购买/关闭
|
||||
# 意图经信号外发——零核心写调用、零 MetaProgression 持有。视觉 = ui_kit 程序占位
|
||||
#(代拍板 8——视觉终稿以表现层样张过审为前置,归 HUD 协作批)。
|
||||
# 意图经信号外发——零核心写调用、零 MetaProgression 持有。
|
||||
class_name CampOverlay
|
||||
extends Control
|
||||
|
||||
@@ -17,6 +15,10 @@ signal buy_requested(attr: String)
|
||||
signal closed
|
||||
|
||||
const ATTR_LABELS := {"atk": "攻击", "max_hp": "生命上限", "armor_class": "护甲"} # 档位文案轴(数据契约 attr 词表,与 ShopOverlay 同款)
|
||||
# 方向稿取色(4-camp.png——柜台头带深棕/行板暖米;双色墨=亮板配深墨)
|
||||
const HEADER_BAND_COL := Color8(122, 82, 50)
|
||||
const ROW_PLATE_COL := Color8(240, 230, 206)
|
||||
const BADGE_PANEL_COL := Color8(40, 32, 24)
|
||||
|
||||
var _balance_label: Label
|
||||
var _forge_holder: VBoxContainer
|
||||
@@ -28,81 +30,132 @@ var _recent_list: Label # 最近冒险(逐行拼接 label——只读
|
||||
|
||||
func _init() -> void:
|
||||
var dim := ColorRect.new()
|
||||
dim.color = Color(0, 0, 0, 0.72)
|
||||
dim.color = Color(0, 0, 0, 0.45) # 方向稿=石纹底透出(浅 dim——石纹全屏底担当氛围)
|
||||
dim.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
add_child(dim)
|
||||
var center := CenterContainer.new()
|
||||
center.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
dim.add_child(center)
|
||||
var frame := PanelContainer.new()
|
||||
frame.add_theme_stylebox_override("panel", UiKit.frame_skinned(Vector4(26, 22, 26, 22))) # 仪式石框(T2;缺位回退暗面板)
|
||||
center.add_child(frame)
|
||||
var box := VBoxContainer.new()
|
||||
box.add_theme_constant_override("separation", 6)
|
||||
frame.add_child(box)
|
||||
var title := UiKit.label("营地 · 永久强化", 24, true)
|
||||
title.add_theme_color_override("font_color", UiKit.WARM)
|
||||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
box.add_child(title)
|
||||
# 石纹底噪(样张 v2 冻结件——start overlay 同款;缺位不挂即回退平 dim)
|
||||
var bd_tex := UiKit.load_tex(UiKit.TEX_BACKDROP_STONE)
|
||||
if bd_tex != null:
|
||||
var bd := TextureRect.new()
|
||||
bd.texture = bd_tex
|
||||
bd.stretch_mode = TextureRect.STRETCH_TILE
|
||||
bd.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
bd.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
bd.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
dim.add_child(bd)
|
||||
|
||||
var root := MarginContainer.new()
|
||||
root.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
root.add_theme_constant_override("margin_left", 16)
|
||||
root.add_theme_constant_override("margin_right", 16)
|
||||
root.add_theme_constant_override("margin_top", 12)
|
||||
root.add_theme_constant_override("margin_bottom", 12)
|
||||
dim.add_child(root)
|
||||
var col := VBoxContainer.new()
|
||||
col.add_theme_constant_override("separation", 8)
|
||||
root.add_child(col)
|
||||
|
||||
# ── 顶栏:左铭牌(标题+副题)/ 右钥石徽 ──
|
||||
var top := HBoxContainer.new()
|
||||
top.add_theme_constant_override("separation", 10)
|
||||
col.add_child(top)
|
||||
var plaque := PanelContainer.new()
|
||||
plaque.add_theme_stylebox_override("panel",
|
||||
UiKit.panel_flat(UiKit.PANEL_DATA, UiKit.PANEL_BORDER, 2, 1, Vector4(14, 8, 14, 8)))
|
||||
top.add_child(plaque)
|
||||
var plaque_col := VBoxContainer.new()
|
||||
plaque.add_child(plaque_col)
|
||||
var title := UiKit.label("营地 · 永久强化", 22, true)
|
||||
title.add_theme_color_override("font_color", UiKit.INK_TITLE)
|
||||
plaque_col.add_child(title)
|
||||
var sub := UiKit.label("跨局成长账本——钥石换永久属性", 13, false)
|
||||
sub.add_theme_color_override("font_color", UiKit.STONE)
|
||||
plaque_col.add_child(sub)
|
||||
var spacer := Control.new()
|
||||
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
top.add_child(spacer)
|
||||
var badge := PanelContainer.new()
|
||||
badge.add_theme_stylebox_override("panel",
|
||||
UiKit.panel_flat(BADGE_PANEL_COL, UiKit.PANEL_BORDER, 2, 1, Vector4(14, 8, 14, 8)))
|
||||
top.add_child(badge)
|
||||
var bal_row := HBoxContainer.new()
|
||||
bal_row.add_theme_constant_override("separation", 6)
|
||||
bal_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
badge.add_child(bal_row)
|
||||
var keystone_icon := UiKit.icon_rect(UiKit.TEX_ICON_KEYSTONE, 18) # 缺位 null → 纯文本回退
|
||||
if keystone_icon != null:
|
||||
bal_row.add_child(keystone_icon)
|
||||
_balance_label = UiKit.label("钥石 0", 18, true)
|
||||
_balance_label.add_theme_color_override("font_color", UiKit.GOLD)
|
||||
bal_row.add_child(_balance_label)
|
||||
box.add_child(bal_row)
|
||||
box.add_child(HSeparator.new())
|
||||
|
||||
box.add_child(_counter_header("属性锻造(钥石直购 · 每级 flat 整数 · 价格几何递增)", UiKit.TEX_ICON_FORGE))
|
||||
# ── 三柜台列(方向稿同构:头带深棕+米色板身)──
|
||||
var mid := HBoxContainer.new()
|
||||
mid.add_theme_constant_override("separation", 18)
|
||||
mid.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
mid.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
col.add_child(mid)
|
||||
_forge_holder = VBoxContainer.new()
|
||||
_forge_holder.add_theme_constant_override("separation", 4)
|
||||
box.add_child(_forge_holder)
|
||||
|
||||
box.add_child(_counter_header("道具工坊(累计通关次数解锁 · 局内效果排 Alpha 魔法道具重设计批)", UiKit.TEX_ICON_WORKSHOP))
|
||||
_forge_holder.add_theme_constant_override("separation", 6)
|
||||
mid.add_child(_counter_panel("属性锻造", UiKit.TEX_ICON_FORGE, _forge_holder, 356))
|
||||
_workshop_holder = VBoxContainer.new()
|
||||
_workshop_holder.add_theme_constant_override("separation", 4)
|
||||
box.add_child(_workshop_holder)
|
||||
|
||||
box.add_child(_counter_header("奖励格图鉴", UiKit.TEX_ICON_ATLAS))
|
||||
_workshop_holder.add_theme_constant_override("separation", 6)
|
||||
mid.add_child(_counter_panel("道具工坊", UiKit.TEX_ICON_WORKSHOP, _workshop_holder, 356))
|
||||
var atlas_holder := VBoxContainer.new()
|
||||
mid.add_child(_counter_panel("奖励格图鉴", UiKit.TEX_ICON_ATLAS, atlas_holder, 356))
|
||||
var lock_l := UiKit.label(" —— 柜台结构位预留:内容排 Alpha(地图战斗资源差异化批)", 13, false)
|
||||
lock_l.add_theme_color_override("font_color", UiKit.WARM_FAINT)
|
||||
box.add_child(lock_l)
|
||||
box.add_child(HSeparator.new())
|
||||
|
||||
box.add_child(_counter_header("最近冒险"))
|
||||
var scroll := ScrollContainer.new()
|
||||
scroll.custom_minimum_size = Vector2(560, 96)
|
||||
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
|
||||
box.add_child(scroll)
|
||||
_recent_list = UiKit.label("", 13, false)
|
||||
_recent_list.add_theme_color_override("font_color", UiKit.WARM_SOFT)
|
||||
_recent_list.custom_minimum_size = Vector2(544, 0)
|
||||
_recent_list.autowrap_mode = TextServer.AUTOWRAP_OFF
|
||||
scroll.add_child(_recent_list)
|
||||
lock_l.add_theme_color_override("font_color", UiKit.STONE)
|
||||
lock_l.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
lock_l.custom_minimum_size = Vector2(300, 0)
|
||||
atlas_holder.add_child(lock_l)
|
||||
|
||||
# ── 底栏:关闭钮(左)/ 操作注记(右)+ 最近冒险条带 ──
|
||||
var close_btn := UiKit.button("关闭营地(回开始界面)")
|
||||
close_btn.pressed.connect(_emit_closed)
|
||||
box.add_child(close_btn)
|
||||
var bottom := HBoxContainer.new()
|
||||
bottom.add_theme_constant_override("separation", 10)
|
||||
bottom.add_child(close_btn)
|
||||
var spacer2 := Control.new()
|
||||
spacer2.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
bottom.add_child(spacer2)
|
||||
var caption := UiKit.label("每购得一件永久强化,对应柜台亮起一格暖光 · 价格为钥石", 13, false)
|
||||
caption.add_theme_color_override("font_color", UiKit.WARM_SOFT)
|
||||
bottom.add_child(caption)
|
||||
col.add_child(bottom)
|
||||
_recent_list = UiKit.label("", 13, false)
|
||||
_recent_list.add_theme_color_override("font_color", UiKit.WARM_SOFT)
|
||||
_recent_list.clip_text = true
|
||||
_recent_list.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
|
||||
col.add_child(_recent_list)
|
||||
visible = false
|
||||
|
||||
|
||||
func _counter_header(text: String, icon_path := "") -> Control:
|
||||
var row := HBoxContainer.new()
|
||||
row.add_theme_constant_override("separation", 6)
|
||||
# 柜台列面板(方向稿同构):PanelContainer 米板身 + 头带深棕(图标+标题暖白)
|
||||
func _counter_panel(title_text: String, icon_path: String, holder: VBoxContainer, min_w: int) -> PanelContainer:
|
||||
var panel := PanelContainer.new()
|
||||
panel.custom_minimum_size = Vector2(min_w, 0)
|
||||
panel.add_theme_stylebox_override("panel",
|
||||
UiKit.panel_flat(UiKit.PANEL_DATA, UiKit.PANEL_BORDER, 3, 1, Vector4(10, 10, 10, 10)))
|
||||
var vbox := VBoxContainer.new()
|
||||
vbox.add_theme_constant_override("separation", 8)
|
||||
panel.add_child(vbox)
|
||||
var band := PanelContainer.new()
|
||||
band.add_theme_stylebox_override("panel", UiKit.panel_flat(HEADER_BAND_COL, UiKit.PANEL_BORDER, 2, 1, Vector4(10, 5, 10, 5)))
|
||||
vbox.add_child(band)
|
||||
var head := HBoxContainer.new()
|
||||
head.add_theme_constant_override("separation", 6)
|
||||
band.add_child(head)
|
||||
if icon_path != "":
|
||||
var ic := UiKit.icon_rect(icon_path, 16) # 缺位 null → 纯文本回退
|
||||
if ic != null:
|
||||
row.add_child(ic)
|
||||
var l := UiKit.label(text, 15, true)
|
||||
l.add_theme_color_override("font_color", UiKit.WARM_SOFT)
|
||||
row.add_child(l)
|
||||
return row
|
||||
head.add_child(ic)
|
||||
var l := UiKit.label(title_text, 16, true)
|
||||
l.add_theme_color_override("font_color", UiKit.WARM)
|
||||
head.add_child(l)
|
||||
vbox.add_child(holder)
|
||||
return panel
|
||||
|
||||
|
||||
# ---- 柜台行构建(open_camp 重建;行结构仿 ShopOverlay 商品卡)----
|
||||
# ---- 柜台行构建(open_camp 重建;行结构仿 ShopOverlay 商品卡——亮板双色墨制)----
|
||||
|
||||
# 打开营地(全量重建三柜台行 + 最近冒险——数据 = 组合根 _camp_data() 投影)
|
||||
func open_camp(data: Dictionary) -> void:
|
||||
@@ -125,7 +178,7 @@ func refresh_camp(data: Dictionary) -> void:
|
||||
if row.is_empty():
|
||||
continue
|
||||
card.level_l.text = "Lv %d" % int(row.get("level", 0))
|
||||
card.price_l.text = "下级价格 %d 钥石" % int(row.get("price", 0))
|
||||
card.price_l.text = "%d 钥石" % int(row.get("price", 0))
|
||||
card.btn.disabled = balance < int(row.get("price", 0)) # 余额不足禁用置灰
|
||||
var ws_by_id := {}
|
||||
for row in data.get("workshop", []):
|
||||
@@ -138,18 +191,19 @@ func refresh_camp(data: Dictionary) -> void:
|
||||
var prog := int(row.get("progress", 0))
|
||||
var unlocked := bool(row.get("unlocked", false))
|
||||
card.progress_l.text = "累计通关 %d / %d 次" % [prog, th]
|
||||
# 迭代 7 T5——失义件(显影尘/地穴全图卷 Alpha 重定)与退役件(探宝罗盘 2026-09-29 拍板①乙)的呈现口径
|
||||
# 迭代 7 T5——失义件(显影尘/地穴全图卷 Alpha 重定)与退役件(探宝罗盘 2026-09-29 拍板①乙)呈现口径;
|
||||
# 状态色随卡⑭ 亮板双色墨制(深墨族替代暖白族——亮板上暖白不可读)
|
||||
var st_text := "未解锁"
|
||||
var st_col: Color = UiKit.WARM_FAINT
|
||||
var st_col: Color = UiKit.STONE
|
||||
if bool(row.get("retired", false)):
|
||||
st_text = "已退役"
|
||||
st_col = UiKit.WARM_FAINT
|
||||
st_col = UiKit.STONE
|
||||
elif bool(row.get("deferred", false)) and unlocked:
|
||||
st_text = "已解锁 · 能力封存中"
|
||||
st_col = UiKit.GOLD
|
||||
st_col = UiKit.GOLD_DEEP
|
||||
elif unlocked:
|
||||
st_text = "已解锁"
|
||||
st_col = UiKit.GOLD
|
||||
st_col = UiKit.GOLD_DEEP
|
||||
card.status_l.text = st_text
|
||||
card.status_l.add_theme_color_override("font_color", st_col)
|
||||
|
||||
@@ -164,20 +218,22 @@ func _rebuild_forge(data: Dictionary) -> void:
|
||||
|
||||
func _build_forge_row(holder: VBoxContainer, row: Dictionary) -> Dictionary:
|
||||
var card := PanelContainer.new()
|
||||
card.add_theme_stylebox_override("panel", UiKit.panel_flat(UiKit.BG_OVERLAY, UiKit.GOLD_DIM, 4, 1, Vector4(12, 4, 12, 4)))
|
||||
card.add_theme_stylebox_override("panel", UiKit.panel_flat(ROW_PLATE_COL, UiKit.PANEL_BORDER, 2, 1, Vector4(10, 4, 10, 4)))
|
||||
var line := HBoxContainer.new()
|
||||
line.add_theme_constant_override("separation", 12)
|
||||
card.add_child(line)
|
||||
var attr := String(row.get("attr", ""))
|
||||
var name_l := UiKit.label("%s(每级 %+d flat)" % [String(row.get("display_name", "")), int(row.get("flat", 0))], 14, true)
|
||||
name_l.custom_minimum_size = Vector2(210, 0)
|
||||
var name_l := UiKit.label("%s %+d/级" % [String(row.get("display_name", "")), int(row.get("flat", 0))], 14, true)
|
||||
name_l.add_theme_color_override("font_color", UiKit.INK)
|
||||
name_l.custom_minimum_size = Vector2(132, 0)
|
||||
line.add_child(name_l)
|
||||
var level_l := UiKit.label("", 14, false)
|
||||
level_l.custom_minimum_size = Vector2(64, 0)
|
||||
level_l.add_theme_color_override("font_color", UiKit.INK)
|
||||
level_l.custom_minimum_size = Vector2(44, 0)
|
||||
line.add_child(level_l)
|
||||
var price_l := UiKit.label("", 14, false)
|
||||
price_l.add_theme_color_override("font_color", UiKit.WARM_SOFT)
|
||||
price_l.custom_minimum_size = Vector2(150, 0)
|
||||
price_l.add_theme_color_override("font_color", UiKit.STONE)
|
||||
price_l.custom_minimum_size = Vector2(64, 0)
|
||||
line.add_child(price_l)
|
||||
var btn := UiKit.button("锻造 +1 级")
|
||||
btn.pressed.connect(_emit_buy_requested.bind(attr))
|
||||
@@ -192,18 +248,20 @@ func _rebuild_workshop(data: Dictionary) -> void:
|
||||
child.queue_free()
|
||||
for row in data.get("workshop", []):
|
||||
var card := PanelContainer.new()
|
||||
card.add_theme_stylebox_override("panel", UiKit.panel_flat(UiKit.BG_OVERLAY, UiKit.WARM_FAINT, 4, 1, Vector4(12, 4, 12, 4)))
|
||||
card.add_theme_stylebox_override("panel", UiKit.panel_flat(ROW_PLATE_COL, UiKit.PANEL_BORDER, 2, 1, Vector4(10, 4, 10, 4)))
|
||||
var line := HBoxContainer.new()
|
||||
line.add_theme_constant_override("separation", 12)
|
||||
card.add_child(line)
|
||||
var name_l := UiKit.label(String(row.get("display_name", "")), 14, true)
|
||||
name_l.custom_minimum_size = Vector2(210, 0)
|
||||
name_l.add_theme_color_override("font_color", UiKit.INK)
|
||||
name_l.custom_minimum_size = Vector2(132, 0)
|
||||
line.add_child(name_l)
|
||||
var progress_l := UiKit.label("", 13, false)
|
||||
progress_l.add_theme_color_override("font_color", UiKit.WARM_SOFT)
|
||||
progress_l.custom_minimum_size = Vector2(150, 0)
|
||||
progress_l.add_theme_color_override("font_color", UiKit.STONE)
|
||||
progress_l.custom_minimum_size = Vector2(110, 0)
|
||||
line.add_child(progress_l)
|
||||
var status_l := UiKit.label("", 13, true)
|
||||
status_l.add_theme_color_override("font_color", UiKit.STONE)
|
||||
line.add_child(status_l)
|
||||
_workshop_holder.add_child(card)
|
||||
_workshop_rows.append({"item_id": String(row.get("item_id", "")), "progress_l": progress_l, "status_l": status_l})
|
||||
@@ -213,16 +271,16 @@ func _rebuild_recent(data: Dictionary) -> void:
|
||||
var lines: Array[String] = []
|
||||
var recent: Array = data.get("recent", [])
|
||||
if recent.is_empty():
|
||||
lines.append(" (暂无冒险记录——完成或结束一次冒险后入账)")
|
||||
lines.append(" 最近冒险:(暂无记录——完成或结束一次冒险后入账)")
|
||||
for s in recent:
|
||||
var verdict := "失败"
|
||||
if String(s.get("result", "")) == "completed":
|
||||
verdict = "完成"
|
||||
elif String(s.get("result", "")) == "abandoned":
|
||||
verdict = "放弃"
|
||||
lines.append("%s · 通关 %d 关 · 钥石 +%d · 种子 %d" % [verdict,
|
||||
lines.append("最近冒险:%s · 通关 %d 关 · 钥石 +%d · 种子 %d" % [verdict,
|
||||
int(s.get("levels_cleared", 0)), int(s.get("keystone_total", 0)), int(s.get("master_seed", 0))])
|
||||
_recent_list.text = "\n".join(lines)
|
||||
_recent_list.text = " | ".join(lines)
|
||||
|
||||
|
||||
func _emit_closed() -> void:
|
||||
|
||||
Reference in new issue
Block a user