diff --git a/design/art/art-bible.md b/design/art/art-bible.md index 8634a698..14b0bed9 100644 --- a/design/art/art-bible.md +++ b/design/art/art-bible.md @@ -407,6 +407,8 @@ **数据素面的墨来自世界的墨**:UI 数字、进度、准线一律主墨 `#33261B` 系——棋盘与面板读同一种墨;容器穿木石材质色,数据只穿墨。**营地与棋盘**:菜单容器背景用全作最暖的烛光黄 `#F6C667` 与木色 `#8A5A34`(§2.8;场景构成 §6.2);战斗容器转中性石色,防暖色渗入棋盘分走数字对比预算——氛围色向可读色让路。UI 不新增语义色,一切强调沿用 §4.2。**暗底呈现态双色墨制**(关卡画面样张 v1 冻结 2026-09-28):暗底系(已过/未来/候选/Boss 方块、暗数据框)图标与读数一律暖白 `#F0E2C8`(WARM)、亮底(当前金 `#F0A828`)转深墨 `#181410`(INK_ROUTE)——各态对比 ≥4.5:1;已过节点暗金冻结 `GOLD_DONE #68562C`(专用呈现态值,旧 GOLD_DIM `#8C743C` 对双色墨均不达标退役出该呈现位);Boss 描边 = 紫赤 2px + 外缘 1px 深墨环(灰度冗余通道——§4.2 色相独占本色不变,§4.5 灰度可分类承载)。 +- **琥珀双岗注记(2026-10-04 UI 落码批 M0)**:主操作色与收益金分轨——主按钮/候选节点/钥石徽章底用烛光黄 `#F6C667`(CANDLE,独立 token),奖励数字/钥石读数/地图「当前位置」仍独占 §4.1 奖励金 `#F0A828`。烛光黄族身兼「主操作 + 收益邻近氛围」双岗系主动取舍(原型评审 C 组留痕),非疏忽,防回改。底色三件套同步换代:BG_ROOT `#3A2E22`/BG_OVERLAY `#362B20`/新增 BG_BRIGHT `#453723`(配色总纲「提暖提亮禁近黑」);暖米族 WARM_SOFT `#E8D5A8`/WARM_FAINT `#CDB88C`(「米色去灰」)。 + ### 7.3 布局栅格 - **结构**:双舞台三区(B 战斗画面/C 数据框/D 棋盘;字母保持不重编)为结构冻结项,分区尺寸与像素级裁决归 battle.md(HUD框架承载 1280×800 基座锚点值,如扫雷图区 1036×504、结算明细带展开 84px)。 diff --git a/game/presentation/views/ui_kit.gd b/game/presentation/views/ui_kit.gd index 3af5fc6c..2c387f24 100644 --- a/game/presentation/views/ui_kit.gd +++ b/game/presentation/views/ui_kit.gd @@ -45,8 +45,8 @@ const DEBUFF_PURPLE := Color8(122, 66, 148) # 妨害紫(意图 ☠) const DUSK := Color8(90, 108, 140) # 暮蓝(全作唯一暮蓝档——失败终局) const WARM := Color8(240, 226, 200) # 暖白(暗底正文) -const WARM_SOFT := Color8(200, 188, 166) # 暖白次级(说明文) -const WARM_FAINT := Color8(178, 166, 146) # 暖白弱化(帮助文) +const WARM_SOFT := Color8(232, 213, 168) # 暖白次级(说明文)#E8D5A8(M0 换代——灰米 #C8BCA6 退役,配色总纲「米色去灰」) +const WARM_FAINT := Color8(205, 184, 140) # 暖白弱化(帮助文)#CDB88C(M0 换代,同上) const STONE := Color8(120, 110, 98) # 灰石(通道/箭头/失效) const STONE_FAINT := Color8(140, 124, 100) # 灰石弱化(占位提示文) @@ -62,8 +62,11 @@ const DIGIT_PLATE := Color8(245, 234, 211) # 数字色牌(素色暖纸白 const DIGIT_PLATE_EDGE := Color8(210, 198, 172) # 色牌牌缘线 const SLOT_BACKDROP := Color8(52, 44, 36) # B 区状态图标槽实底(深墨棕——白图标对比承载,2026-09-26 反馈④) -const BG_ROOT := Color8(30, 25, 20) # 屏幕根底 -const BG_OVERLAY := Color8(28, 22, 18) # 模态遮罩底 +const BG_ROOT := Color8(58, 46, 34) # 屏幕根底 #3A2E22(UI 落码批 M0 2026-10-04——配色总纲「提暖提亮禁近黑」,旧近黑 #1E1914 退役) +const BG_OVERLAY := Color8(54, 43, 32) # 模态遮罩底 #362B20(同批换代,旧 #1C1612 退役) +const BG_BRIGHT := Color8(69, 55, 35) # 暖亮档底 #453723(M0 新增——标题/营地/商店等暖亮屏根底) +const CANDLE := Color8(246, 198, 103) # 烛光黄 #F6C667(M0 新增——主操作色/候选节点/钥石徽章底; + # 与 §4.1 奖励金 #F0A828 分轨——圣经 §7.2 琥珀双岗注记) const DIM := Color(0.08, 0.06, 0.05) # 遮罩基色(用时乘 alpha) const TOAST_BG := Color(0.94, 0.91, 0.84, 0.95) # toast 面底 const TIP_BG := Color(0.16, 0.12, 0.09, 0.96) # tooltip 深底 @@ -149,6 +152,18 @@ const TEX_NODE_REWARD := "res://assets/art/ui/node_reward.png" # const TEX_NODE_REST := "res://assets/art/ui/node_rest.png" # 节点图标·恢复房 const TEX_NODE_BOSS := "res://assets/art/ui/node_boss.png" # 节点图标·Boss 房 const TEX_NODE_SHOP := "res://assets/art/ui/node_shop.png" # 节点图标·商店房 +# 手绘功能图标十键(UI 落码批 M1 2026-10-04——20×20 像素 1:1/整数倍消费〔§8.2 甲类纪律〕; +# 源=demo 原型 src 盘上件搬运;缺位 = load_tex null → 字形回退不炸) +const TEX_ICON_SWORD := "res://assets/art/ui/icon_sword.png" # 图标·攻击系(锻造行/攻击强化卡) +const TEX_ICON_SHIELD := "res://assets/art/ui/icon_shield.png" # 图标·护甲系 +const TEX_ICON_HEART := "res://assets/art/ui/icon_heart.png" # 图标·生命系 +const TEX_ICON_SHOVEL := "res://assets/art/ui/icon_shovel.png" # 图标·铲(挖掘系商品/锻造) +const TEX_ICON_MEDKIT := "res://assets/art/ui/icon_medkit.png" # 图标·医疗包 +const TEX_ICON_POUCH := "res://assets/art/ui/icon_pouch.png" # 图标·弹药袋/行动点 +const TEX_ICON_BLAST := "res://assets/art/ui/icon_blast.png" # 图标·工兵爆破(魔法道具) +const TEX_ICON_COINBAG := "res://assets/art/ui/icon_coinbag.png" # 图标·金币袋 +const TEX_ICON_KEYSHARD := "res://assets/art/ui/icon_keyshard.png" # 图标·钥石残片 +const TEX_ICON_REFRESH := "res://assets/art/ui/icon_refresh.png" # 图标·刷新(货架/候选) # 素材纹理守卫装载(exists 检查避开缺位树上 ResourceLoader 报错刷屏——冒烟/无素材检出静默回退) @@ -313,3 +328,173 @@ static func _apply_button_skin(b: Button) -> void: b.add_theme_color_override("font_pressed_color", INK) b.add_theme_color_override("font_focus_color", INK) b.add_theme_color_override("font_disabled_color", Color(INK, 0.45)) + + +# ── UI 落码批 M10 公共件(2026-10-04——bcard 竖卡工厂/拨杆开关/样式滑杆/动词按钮/tooltip 主题; +# 消费方 = M2 标题/M3 营地/M4 设置/M6 商店/M7 三选一。单点纪律同 §7.1:新件只加不改旧件)── + +# 动词按钮(图标+动词+悬停说明三件套——M2 标题屏按钮组/通用;icon 缺位=纯文字不炸) +static func verb_button(text: String, icon_path: String, tip := "") -> Button: + var b := button(text) + var tex := load_tex(icon_path) + if tex != null: + b.icon = tex + b.add_theme_constant_override("icon_max_width", 20) + b.expand_icon = false + if tip != "": + b.tooltip_text = tip + return b + + +# 主操作钮(烛光黄平涂+木描边——非奖励金;配色总纲「主按钮禁亮金」;缺 panel_stone 依赖=纯色可靠) +static func primary_button(text: String, tip := "") -> Button: + var b := button(text) + var sb := panel_flat(CANDLE, Color8(110, 69, 52), 5, 2, Vector4(10, 2, 10, 2)) + b.add_theme_stylebox_override("normal", sb) + b.add_theme_stylebox_override("hover", panel_flat(CANDLE.lightened(0.06), Color8(110, 69, 52), 5, 2, Vector4(10, 2, 10, 2))) + b.add_theme_stylebox_override("pressed", panel_flat(Color8(214, 172, 88), Color8(110, 69, 52), 5, 2, Vector4(10, 2, 10, 2))) + b.add_theme_color_override("font_color", Color8(58, 42, 8)) + b.add_theme_color_override("font_hover_color", Color8(58, 42, 8)) + b.add_theme_color_override("font_pressed_color", Color8(58, 42, 8)) + b.add_theme_color_override("font_focus_color", Color8(58, 42, 8)) + if tip != "": + b.tooltip_text = tip + return b + + +# 危险钮(深红平涂——放弃/删除类;破坏性确认位置纪律=不得与常规确认同位) +static func danger_button(text: String, tip := "") -> Button: + var b := button(text) + var sb := panel_flat(Color8(180, 78, 54), Color8(110, 42, 28), 5, 2, Vector4(10, 2, 10, 2)) + b.add_theme_stylebox_override("normal", sb) + b.add_theme_stylebox_override("hover", panel_flat(Color8(196, 90, 62), Color8(110, 42, 28), 5, 2, Vector4(10, 2, 10, 2))) + b.add_theme_color_override("font_color", Color8(255, 244, 224)) + b.add_theme_color_override("font_hover_color", Color8(255, 244, 224)) + b.add_theme_color_override("font_pressed_color", Color8(255, 244, 224)) + if tip != "": + b.tooltip_text = tip + return b + + +# bcard 竖卡工厂(商店/三选一同构卡——M6/M7 共用;M7.1 差异仅=价签 vs ✓选择章) +# 返回 {panel, mark, band, icon, name_l, desc_l, price_l, foot_l};set_selected 经 mark/样式换装 +class BCard: + extends PanelContainer + var mark: Label + var icon_tr: TextureRect + var name_l: Label + var desc_l: Label + var price_l: Label + var foot_l: Label + var _sb_normal: StyleBox + var _sb_sel: StyleBox + + func _init(title: String, desc: String, band: Color, icon_path: String, price := "", footnote := "") -> void: + var tex := UiKit.load_tex(UiKit.TEX_PANEL_STONE) + _sb_normal = UiKit.panel_skinned(Vector4(12, 10, 12, 10)) if tex != null else UiKit.panel_flat(Color8(233, 217, 184), UiKit.PANEL_BORDER, 5, 1, Vector4(12, 10, 12, 10)) + _sb_sel = UiKit.panel_flat(Color8(233, 217, 184), Color8(138, 90, 52), 5, 2, Vector4(12, 10, 12, 10)) + add_theme_stylebox_override("panel", _sb_normal) + custom_minimum_size = Vector2(216, 300) + var box := VBoxContainer.new() + box.add_theme_constant_override("separation", 8) + add_child(box) + var band_r := ColorRect.new() + band_r.color = band + band_r.custom_minimum_size = Vector2(0, 6) + box.add_child(band_r) + mark = UiKit.label("✓", 16, true, Color8(58, 42, 8)) + mark.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT + mark.visible = false + box.add_child(mark) + icon_tr = TextureRect.new() + var itex := UiKit.load_tex(icon_path) + if itex != null: + icon_tr.texture = itex + icon_tr.custom_minimum_size = Vector2(56, 56) + icon_tr.expand_mode = TextureRect.EXPAND_IGNORE_SIZE + icon_tr.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED + icon_tr.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST + icon_tr.size_flags_horizontal = Control.SIZE_SHRINK_CENTER + box.add_child(icon_tr) + name_l = UiKit.label(title, 18, true, INK_TITLE) + name_l.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + box.add_child(name_l) + desc_l = UiKit.label(desc, 14, false, Color8(74, 58, 40)) + desc_l.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + desc_l.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + box.add_child(desc_l) + var spacer := Control.new() + spacer.size_flags_vertical = Control.SIZE_EXPAND_FILL + box.add_child(spacer) + price_l = UiKit.label(price, 21, true, GOLD) + price_l.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + price_l.visible = price != "" + box.add_child(price_l) + foot_l = UiKit.label(footnote, 11, false, Color8(110, 69, 52)) + foot_l.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + foot_l.visible = footnote != "" + box.add_child(foot_l) + + func set_selected(v: bool) -> void: + add_theme_stylebox_override("panel", _sb_sel if v else _sb_normal) + mark.visible = v + + +static func bcard(title: String, desc: String, band: Color, icon_path: String, price := "", footnote := "") -> BCard: + return BCard.new(title, desc, band, icon_path, price, footnote) + + +# 拨杆开关(设置屏——46×22 滑柄形;状态字随行由消费方摆;会话级/持久由消费方接 SettingsStore) +class SwitchToggle: + extends Button + var _knob: ColorRect + + func _init(initial: bool) -> void: + toggle_mode = true + button_pressed = initial + custom_minimum_size = Vector2(46, 22) + var track := UiKit.panel_flat(Color8(184, 165, 130), Color8(120, 110, 88), 3, 2) + add_theme_stylebox_override("normal", track) + add_theme_stylebox_override("hover", track) + add_theme_stylebox_override("pressed", track) + _knob = ColorRect.new() + _knob.color = Color8(58, 42, 8) + _knob.mouse_filter = Control.MOUSE_FILTER_IGNORE + add_child(_knob) + toggled.connect(func(_p: bool) -> void: _place()) + _place() + + func _place() -> void: + _knob.position = Vector2(25, 3) if button_pressed else Vector2(3, 3) + _knob.size = Vector2(18, 16) + + +static func switch_toggle(initial: bool) -> SwitchToggle: + return SwitchToggle.new(initial) + + +# 样式滑杆(设置屏音量——轨道暖石+默认柄;范围/读数由消费方接) +static func styled_slider(value: float, minv := 0.0, maxv := 100.0) -> HSlider: + var s := HSlider.new() + s.min_value = minv + s.max_value = maxv + s.value = value + s.custom_minimum_size = Vector2(200, 20) + s.add_theme_stylebox_override("slider", panel_flat(Color8(184, 165, 130), PANEL_BORDER, 0, 1)) + s.add_theme_stylebox_override("grabber_area", panel_flat(Color8(122, 82, 50), Color8(0, 0, 0, 0), 0, 0)) + return s + + +# tooltip 全站主题(深底多行素牌——§7.2 文字可读硬指标;消费方=任一祖先 Control.theme 挂一次全树生效) +static var _tip_theme: Theme = null + +static func tooltip_theme() -> Theme: + if _tip_theme != null: + return _tip_theme + var th := Theme.new() + th.set_stylebox("panel", "TooltipPanel", + panel_flat(Color(0.09, 0.07, 0.05, 0.96), Color8(90, 80, 68), 0, 1, Vector4(8, 6, 8, 6))) + th.set_color("font_color", "TooltipLabel", WARM) + th.set_font_size("font_size", "TooltipLabel", 14) + _tip_theme = th + return _tip_theme