From 8f36b61620b9f8f0d6e5b17258747b10fb68efff Mon Sep 17 00:00:00 2001 From: Joywayer Date: Thu, 27 Aug 2026 08:40:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=8C=E4=B8=83=E7=8E=8B=EF=BC=9A=E8=A1=A5?= =?UTF-8?q?=E9=BD=90=E4=B8=89=E5=A4=84=E9=85=8D=E7=BD=AE=E7=BC=BA=E5=8F=A3?= =?UTF-8?q?=EF=BC=88=E6=89=A3=E5=BA=95=E6=8C=89=E9=92=AE=20/=20=E5=87=BA?= =?UTF-8?q?=E7=89=8C=E6=8F=90=E7=A4=BA=E6=8C=89=E9=92=AE=E6=A7=BD=E4=BD=8D?= =?UTF-8?q?=20/=20=E4=B8=89=E4=B8=AA=20View=20=E7=9A=84=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E8=8A=82=E7=82=B9=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 这三处都是「精灵或按钮已在清单里定案,但配置层缺东西」,不补的话 C/D/E 阶段 写渲染代码时会发现没有布局节点,极易就地硬编码坐标(违反零裸值红线)。 1) 底栏「扣底」按钮没有精灵(清单 §2.6 列了 5 个功能按钮,只登记了 4 个) - 新增 BTN_BURY_CARDS(1056) / BTN_BURY_CARDS_TEXT(1057),群组 205 号段内空闲号, 资源沿用 BTN_BOTTOM_FUNC,与其余四个按钮同构。 - FOOTER_FUNC_BUTTONS 的 items 由 4 项扩到 5 项,扣底紧邻底牌(照 §2.6 表序)。 扣底宽 78 是【估值】:清单未给,取同为两字按钮的「底牌」实测值,已在配置与清单里注明。 - 扣底看【埋牌底牌】(burycards)、底牌看【底牌】(bottomcards),两批不同的牌, JSDoc 里补了防写反的提示(对应验收清单第 13 条)。 2) 出牌阶段「提示」按钮有精灵、无布局槽位 - PLAY_OPERATION_BAR.items 补上 PLAY_BTN_TIP,顺序照清单 §1.7 行文:倒计时 / 出牌 / 提示。 - 宽 180 是【估值】:清单 §6.8 自身漏了该项;与埋牌条的提示按钮同资源 BTN_TIP (§3.3 实测 180×63),埋牌条 items 首项亦取 180,故沿用。 - 顺带记下一处待裁定项:本条 itemHeight 为 55(对齐 BTN_PLAY 157×55), 而 BTN_TIP 原生高 63,高度差待设计稿定。 3) AccountView / HistoryView / MingPaiView 一个布局节点都没有 - AccountView(§6.9a 新增):外壳 6 个节点 + 玩家栏「容器 ACC_ROW_CONTAINER + 行节点 ACC_ROW(itemHeight 即行高,行数由 ctx.count 给出)+ 行内模板贴附到行矩形」 + 面板外 4 按钮,共 14 个节点。行内节点求出的是相对容器的坐标,可直接喂 SpriteCopyUtils.create(与 §5.6a 冲关牌同一用法)。 - HistoryView / MingPaiView(§6.9c 新增):遮罩 + 容器 + 每家一排牌(fan) + 座位标签, 各 4 个节点。照 CHONGGUAN_FAN 同构、锚点沿用 §6.7 冲关牌的三家落点; 差别只在张数上限——出牌历史摊平后可达 28 张以上,故 maxWidth 放宽到 500、 spacingMin 收到 -96【估值】。MING_* 只有 LEFT/RIGHT 两个 bySeat 变体(明牌不看自己)。 - 坐标来源:大局结算.png / 冲关牌型显示.png 目视实测,w/h 取资源尺寸; 配置与清单里均已注明「目视实测估值,待设计稿复核」。 - 运行时才确定的字段(动态文字宽高、随行浮动的 anchorY、数字精灵宽)一律 runtime 显式声明。 钉死断言按实际重新数并更新:精灵总数 378 → 380,布局节点总数 61 → 83。 另把 ACC_TPL_SCORE_NUM 加进 NUM_STYLE 同源校验表(与 RESULT_SCORE_NUM 同一套资源)。 Co-Authored-By: Claude Opus 5 (1M context) --- .../01_SubGame/codes/config/Layout_Action.js | 12 +- .../01_SubGame/codes/config/Layout_Result.js | 184 +++++++++++++++++- .../01_SubGame/codes/config/Layout_Table.js | 7 +- .../01_SubGame/codes/config/Sprites_Action.js | 21 +- .../01_SubGame/codes/config/Sprites_Result.js | 26 ++- .../01_SubGame/codes/config/Sprites_Table.js | 36 ++-- client/tests/test_constants.js | 8 +- client/tests/test_spriteindex.js | 2 +- docs_dev/二七王-UI资源与精灵清单.md | 59 +++++- 9 files changed, 311 insertions(+), 44 deletions(-) diff --git a/client/js/01_SubGame/codes/config/Layout_Action.js b/client/js/01_SubGame/codes/config/Layout_Action.js index 000d95f..662ca6a 100644 --- a/client/js/01_SubGame/codes/config/Layout_Action.js +++ b/client/js/01_SubGame/codes/config/Layout_Action.js @@ -81,13 +81,21 @@ EQW_Layout.BURY_OPERATION_BAR = { ] }; -//出牌操作条:倒计时(CD_SELF) / 出牌 +//出牌操作条:倒计时(CD_SELF) / 出牌 / 提示,逐项不等宽(清单 §6.1)。 +//2026-08-27 补上「提示」项:清单 §1.7 明确「出牌操作条 = 倒计时 + 出牌 按钮 + 提示 按钮 +//(出牌阶段必须有)」,但 §6.8 给的 items 只有 [75,157](倒计时/出牌)——清单自身漏了提示; +//排序照 §1.7 的行文(倒计时 → 出牌 → 提示)。 +//【估值】提示 180:清单未给该项宽度;提示按钮与埋牌条的提示按钮同资源 BTN_TIP(§3.3 实测 180×63), +//埋牌条 items 首项(同一个提示按钮)也取 180,故沿用 180,待设计稿复核。 +//⚠ 本条 itemHeight 为 55(对齐出牌按钮 BTN_PLAY 157×55),而 BTN_TIP 原生高 63—— +// 求解结果里提示项的 height 会是 55,实际显示高度以精灵自身资源为准;此高度差同样待设计稿裁定 EQW_Layout.PLAY_OPERATION_BAR = { kind: 'line', direction: 'horizontal', anchorX: 640, anchorY: 345, itemHeight: 55, spacing: 35, anchor: 'center', items: [ { key: 'CD_SELF', width: 75 }, - { key: 'PLAY_BTN_SUBMIT', width: 157 } + { key: 'PLAY_BTN_SUBMIT', width: 157 }, + { key: 'PLAY_BTN_TIP', width: 180 } ] }; diff --git a/client/js/01_SubGame/codes/config/Layout_Result.js b/client/js/01_SubGame/codes/config/Layout_Result.js index 522aee3..46d91aa 100644 --- a/client/js/01_SubGame/codes/config/Layout_Result.js +++ b/client/js/01_SubGame/codes/config/Layout_Result.js @@ -1,8 +1,9 @@ /////////////////////////////////////////////////////////////// -////////// EQW_Layout: 结算区配置(清单 §6.9)////////////////// +////////// EQW_Layout: 结算区配置(清单 §6.9 / §5.7a / §5.7b)/// /////////////////////////////////////////////////////////////// +// 小局结算 + 冲关遮罩 + 大局总结算 + 出牌历史/亮牌 + 明牌,共五块。 // 【纯数据文件】无函数、无副作用;依赖 LayoutConstants.js 先加载 -// (引用其 EQW_Layout.TEXT_STYLE.*,属 EQW_Layout 内部自引用)。 +// (引用其 EQW_Layout.NUM_STYLE.* / CARD_SIZE.*,属 EQW_Layout 内部自引用)。 var EQW_Layout = EQW_Layout || {}; EQW_Layout.RESULT_BOTTOM_PANEL = { kind: 'point', x: 430, y: 140, w: 420, h: 148 }; @@ -66,3 +67,182 @@ EQW_Layout.RESULT_BTN_NEXT = { kind: 'point', x: 835, y: 518, w: 180, h: 65 }; //冲关遮罩:透明度也是配置项 EQW_Layout.CG_MASK = { kind: 'point', x: 0, y: 0, w: 1280, h: 720, opacity: 0.72 }; + +//===== 大局总结算 / 解散结算(AccountView,群组 241)===== +// +// 【坐标来源 · 2026-08-27 补齐】清单 §6.9 没有本面板的配置表,以下数值全部是 +// docs_dev/uiref/大局结算.png 的【目视实测估值】(±5px),面板/标题栏/规则栏/按钮的 w/h +// 取清单 §3.5 / §3.3 的资源尺寸(那是权威值)。设计稿到位后只改本节。 +// 之所以现在就落成配置:不补的话 C/D/E 阶段写渲染代码时会就地硬编码坐标(零裸值红线)。 +// +// 【玩家栏是精灵复制】三条栏结构相同、条数随人数变,故不逐行写死,而是给 +//「容器 ACC_ROW_CONTAINER + 行节点 ACC_ROW(行高即 itemHeight)+ 行内各模板贴附到行矩形」。 +// 约定:ACC_ROW 及贴附到它的 ACC_TPL_* / ACC_ROW_TEXT_GRID 求解出的坐标都是 +//【相对 ACC_ROW_CONTAINER 的】——SpriteCopyUtils 复制出的精灵是容器的子精灵, +// x/y 本就相对容器,求解结果可直接喂给 SpriteCopyUtils.create(与 §5.6a 冲关牌同一用法)。 +// 行数由数据给出(ctx.count),不进配置(清单 §6.1)。 + +//面板底(1100×540,资源 PANEL_ACCOUNT) +EQW_Layout.ACC_PANEL_BG = { kind: 'point', x: 80, y: 88, w: 1100, h: 540 }; + +//标题栏:封住面板上沿(1100×56,资源 BAR_ACCOUNT_TITLE) +EQW_Layout.ACC_TITLE_BAR = { + kind: 'attach', targetKind: 'layout', target: 'ACC_PANEL_BG', + corner: 'topLeft', offsetX: 0, offsetY: 0, w: 1100, h: 56 +}; + +//标题文字「二七王-3人 房号… 共…局 …」:贴标题栏内部左侧居中。 +//文案随房间信息变长变短,真实宽高要等文案渲染出来才知道 → 留到运行时注入 +EQW_Layout.ACC_TITLE_TEXT = { + kind: 'attach', targetKind: 'layout', target: 'ACC_TITLE_BAR', + hAlign: 'left', vAlign: 'middle', offsetX: 30, + runtime: ['w', 'h'] +}; + +//关闭按钮:贴标题栏右上角(36×36,资源 BTN_ACC_CLOSE) +EQW_Layout.ACC_BTN_CLOSE = { + kind: 'attach', targetKind: 'layout', target: 'ACC_TITLE_BAR', + corner: 'topRight', offsetX: -20, offsetY: 10, w: 36, h: 36 +}; + +//规则栏:封住面板下沿(1100×62,资源 BAR_ACCOUNT_RULE) +EQW_Layout.ACC_RULE_BAR = { + kind: 'attach', targetKind: 'layout', target: 'ACC_PANEL_BG', + corner: 'bottomLeft', offsetX: 0, offsetY: 0, w: 1100, h: 62 +}; + +//规则文字「规则:可查牌、傍王、爬坡算子」:贴规则栏内部左侧居中,文案据 roomtype 拼出、长度不定 +EQW_Layout.ACC_RULE_TEXT = { + kind: 'attach', targetKind: 'layout', target: 'ACC_RULE_BAR', + hAlign: 'left', vAlign: 'middle', offsetX: 30, + runtime: ['w', 'h'] +}; + +//玩家栏容器(ACC_ROW_CONTAINER 精灵的位置):标题栏下沿 144 到规则栏上沿 566 之间 +EQW_Layout.ACC_ROW_CONTAINER = { kind: 'point', x: 80, y: 144, w: 1100, h: 422 }; + +//玩家栏(行):竖排等距,itemHeight 即【行高/行距】。坐标相对容器,行数由 ctx.count 给出 +EQW_Layout.ACC_ROW = { + kind: 'line', direction: 'vertical', anchorX: 0, anchorY: 14, + itemWidth: 1100, itemHeight: 132, spacing: 0, anchor: 'top' +}; + +//行内 · 名次徽章:贴该行内部左侧居中(44×44,资源 BADGE_RANK,帧=名次1–3) +EQW_Layout.ACC_TPL_RANK = { + kind: 'attach', targetKind: 'layout', target: 'ACC_ROW', + hAlign: 'left', vAlign: 'middle', offsetX: 28, w: 44, h: 44 +}; + +//行内 · 头像:贴该行内部左侧居中,名次徽章右侧 +EQW_Layout.ACC_TPL_AVATAR = { + kind: 'attach', targetKind: 'layout', target: 'ACC_ROW', + hAlign: 'left', vAlign: 'middle', offsetX: 92, w: 80, h: 80 +}; + +//行内 · 文字栅格(ACC_TPL_TEXT 复制出的 6 条文字的槽位):4 列 × 2 行,行优先—— +// 列1: 昵称 / ID:{playerid} 列2: 基础分{n} / 总得分{n} +// 列3: 冲关分{n}(参考图小字写「算奖分」,清单 §1.9 定案字段为 grade_cg_total) +// 列4: 傍王分{n} +// 第 2 行只有前两列有文字,第 3/4 列留空(求解仍返回 8 个槽位,调用方按数据取前 6 个)。 +// anchorX 相对容器(= 参考图列1 绝对 x272 − 容器 x80);anchorY 随所在行浮动 → 运行时注入 +EQW_Layout.ACC_ROW_TEXT_GRID = { + kind: 'grid', anchorX: 192, cols: 4, rows: 2, + itemWidth: 176, itemHeight: 34, spacingX: 0, spacingY: 10, + anchor: 'left', fillOrder: 'row', + runtime: ['anchorY'] +}; + +//行内 · 右侧总分大字(多帧图数字精灵):贴该行内部右侧居中。 +//高度恒为单字高,取 NUM_STYLE.RESULT_WIN.charHeight(与 RESULT_LOSE 相同,SSOT); +//宽度随位数变化(setNumberImage 按【字符数 × charWidth】自动改精灵宽),留到运行时注入 +EQW_Layout.ACC_TPL_SCORE_NUM = { + kind: 'attach', targetKind: 'layout', target: 'ACC_ROW', + hAlign: 'right', vAlign: 'middle', offsetX: -25, + h: EQW_Layout.NUM_STYLE.RESULT_WIN.charHeight, runtime: ['w'] +}; + +//行内 · 行间分隔线:贴该行【下沿】(vAlign bottom 的语义是"目标底边之下",见 AlignmentUtils)。 +//1060×2,资源 LINE_DIVIDER;水平居中于 1100 宽的行,左右各留 20 +EQW_Layout.ACC_TPL_DIVIDER = { + kind: 'attach', targetKind: 'layout', target: 'ACC_ROW', + hAlign: 'center', vAlign: 'bottom', offsetX: 0, offsetY: 0, w: 1060, h: 2 +}; + +//面板【外】底部 4 个功能按钮(再来一局/分享好友/复制战绩/退出房间,各 190×60): +//绝对坐标(不在玩家栏容器内)。参考图里这排不是居中于屏幕、而是整体偏右,故用 anchor:left 定起点 +EQW_Layout.ACC_FUNC_BUTTONS = { + kind: 'line', direction: 'horizontal', anchorX: 345, anchorY: 640, + itemWidth: 190, itemHeight: 60, spacing: 25, anchor: 'left' +}; + +//===== 出牌历史 / 上一轮 / 亮牌(HistoryView,群组 242)===== +// +// 【坐标来源 · 2026-08-27 补齐】清单 §5.7b 说本 View 与 MingPaiView、ChongGuanOverlayView +// 三者【同一种版式】(半透黑遮罩 + 每家一排重叠大牌),参考图同为 +// docs_dev/uiref/冲关牌型显示.png;故以下节点照 CHONGGUAN_FAN / CG_MASK 同构给出, +// 三家落点沿用清单 §6.7 的冲关牌锚点(LEFT 260,120 / RIGHT 1035,120 / SELF 640,400)。 +// 与冲关牌的唯一差别是【张数上限】:出牌历史摊平后可达 28 张以上,420 的 maxWidth 装不下, +// 故放宽到 500、spacingMin 收到 -96(每张露 14px,28 张总宽 110+27×14=488 ≤ 500)。 +// 这两个数是【估值,待设计稿复核】——清单未给本 View 的排布参数。 +// +// 【牌用精灵复制】求解结果直接作为 SpriteCopyUtils.create 的 x/y(相对容器), +// 与 §5.6a 冲关牌同一用法:三个容器精灵摆在原点、尺寸铺满屏,故容器内坐标 = 屏幕坐标。 + +//出牌历史 · 遮罩(兼点击关闭热区;【亮牌】用途下不注册点击,见 Sprites_Result.js 说明) +EQW_Layout.HIST_MASK = { kind: 'point', x: 0, y: 0, w: 1280, h: 720, opacity: 0.72 }; + +//出牌历史 · 三个牌容器(HIST_BOX_LEFT/RIGHT/SELF):同摆在原点、铺满屏, +//使 HIST_FAN 求出的屏幕坐标可直接当作容器内坐标使用 +EQW_Layout.HIST_BOX = { kind: 'point', x: 0, y: 0, w: 1280, h: 720 }; + +//出牌历史 · 每家一排牌(张数不定,重叠压缩) +EQW_Layout.HIST_FAN = { + kind: 'fan', direction: 'horizontal', anchor: 'center', + itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h, + maxWidth: 500, spacingMax: -40, spacingMin: -96, + bySeat: { + LEFT: { anchorX: 260, anchorY: 120 }, + RIGHT: { anchorX: 1035, anchorY: 120 }, + SELF: { anchorX: 640, anchorY: 400 } + } +}; + +//出牌历史 · 三家座位标签(昵称/张数):各排牌下方;文案长度不定,w/h 运行时注入 +EQW_Layout.HIST_LABEL = { + kind: 'point', + runtime: ['w', 'h'], + bySeat: { + LEFT: { x: 200, y: 318 }, + RIGHT: { x: 975, y: 318 }, + SELF: { x: 580, y: 598 } + } +}; + +//===== 明牌面板(MingPaiView,群组 243)===== +// +// 版式与 HistoryView 完全相同,差别只在【家数】:明牌只看另两家,没有自己那排, +// 故 bySeat 只有 LEFT / RIGHT 两个变体(精灵键为 MING_BOX_A / _B,A 落 LEFT 位、B 落 RIGHT 位)。 +// 坐标来源同上:冲关牌型显示.png 目视实测 + §6.7 冲关牌锚点,【估值,待设计稿复核】。 + +EQW_Layout.MING_MASK = { kind: 'point', x: 0, y: 0, w: 1280, h: 720, opacity: 0.72 }; + +EQW_Layout.MING_BOX = { kind: 'point', x: 0, y: 0, w: 1280, h: 720 }; + +EQW_Layout.MING_FAN = { + kind: 'fan', direction: 'horizontal', anchor: 'center', + itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h, + maxWidth: 500, spacingMax: -40, spacingMin: -96, + bySeat: { + LEFT: { anchorX: 260, anchorY: 120 }, + RIGHT: { anchorX: 1035, anchorY: 120 } + } +}; + +EQW_Layout.MING_LABEL = { + kind: 'point', + runtime: ['w', 'h'], + bySeat: { + LEFT: { x: 200, y: 318 }, + RIGHT: { x: 975, y: 318 } + } +}; diff --git a/client/js/01_SubGame/codes/config/Layout_Table.js b/client/js/01_SubGame/codes/config/Layout_Table.js index 7f0c3a0..07c5195 100644 --- a/client/js/01_SubGame/codes/config/Layout_Table.js +++ b/client/js/01_SubGame/codes/config/Layout_Table.js @@ -48,7 +48,11 @@ EQW_Layout.FOOTER_ASET_TEXT = { kind: 'point', x: 635, y: 672, w: 65, h: 26, textStyle: EQW_Layout.TEXT_STYLE.ASET_COUNT }; -//底栏 · 功能钮组(明牌/已出牌/上一轮/底牌):逐项不等宽(清单 §6.1 T-25) +//底栏 · 功能钮组(明牌/已出牌/上一轮/扣底/底牌):逐项不等宽(清单 §6.1 T-25)。 +//2026-08-27 补上「扣底」项(清单 §2.6 列的是 5 个按钮,此处原只排了 4 个)—— +//排序按 §2.6 表:扣底紧邻底牌(两者分别看埋牌底牌 / 底牌,成对但不同批,勿写反)。 +//【估值】扣底 78:清单未给该项宽度;同为两字按钮的「底牌」实测 78、「明牌」74, +//故取同类两字按钮的 78,待设计稿复核(其余四项 74/87/93/78 为清单 §6.5 实测值) EQW_Layout.FOOTER_FUNC_BUTTONS = { kind: 'line', direction: 'horizontal', anchorX: 1250, anchorY: 672, itemHeight: 30, spacing: 15, anchor: 'right', @@ -56,6 +60,7 @@ EQW_Layout.FOOTER_FUNC_BUTTONS = { { key: 'BTN_MINGPAI', width: 74 }, { key: 'BTN_HISTORY', width: 87 }, { key: 'BTN_LAST_ROUND', width: 93 }, + { key: 'BTN_BURY_CARDS', width: 78 }, { key: 'BTN_BOTTOM_CARDS', width: 78 } ] }; diff --git a/client/js/01_SubGame/codes/config/Sprites_Action.js b/client/js/01_SubGame/codes/config/Sprites_Action.js index 7c00c37..361186c 100644 --- a/client/js/01_SubGame/codes/config/Sprites_Action.js +++ b/client/js/01_SubGame/codes/config/Sprites_Action.js @@ -289,13 +289,13 @@ EQW_Sprites.ChooseMainView = { * * 出牌操作条(群组 223,EQW_Layout.PLAY_OPERATION_BAR) * line/horizontal, anchor center, anchorX=640 anchorY=345, itemHeight=55, spacing=35 - * items:CD_SELF 75 / PLAY_BTN_SUBMIT 157 + * items:CD_SELF 75 / PLAY_BTN_SUBMIT 157 / PLAY_BTN_TIP 180【估值】 * - * 20 ┌──────────────┐ y=345 - * ↑ │ 出 牌 │ - * CD_SELF └──────────────┘ y=400 - * ↑ PLAY_BTN_SUBMIT(1710)+_TEXT(1711) - * 帧1=可出 / 帧2=灰(选中牌数为 0 时) + * 20 ┌──────────────┐ ┌────────────────┐ y=345 + * ↑ │ 出 牌 │ │ 提示 │ + * CD_SELF └──────────────┘ └────────────────┘ y=400 + * ↑ PLAY_BTN_SUBMIT(1710)+_TEXT(1711) ↑ PLAY_BTN_TIP(1712) + * 帧1=可出 / 帧2=灰(选中牌数为 0 时) +_TEXT(1713) * * ┌── 手牌【单排】(Layer 102)──┐ y=455 起 * @@ -307,10 +307,11 @@ EQW_Sprites.ChooseMainView = { * 预校验与提示,结果不回传。 * - 【自动选中】服务端会在下发包里带「应当选中的牌」(mustcard, S-2),前端收到后自动把这些 * 牌选中上浮,玩家确认后点「出牌」即可——方向是服务端→前端的建议,不违反红线。 - * - 【缺口】出牌阶段的「提示」按钮 PLAY_BTN_TIP(1712)/PLAY_BTN_TIP_TEXT(1713) 已登记精灵 - * (清单 §1.7 明确「出牌阶段必须有」),但参考图 出牌.png 里未画出, - * EQW_Layout.PLAY_OPERATION_BAR 的 items 也只排了倒计时与出牌两项—— - * 该按钮的位置【待设计稿】,补稿后在 items 里加一项即可,本文件不预设坐标。 + * - 【2026-08-27 补齐】出牌阶段的「提示」按钮 PLAY_BTN_TIP(1712)/PLAY_BTN_TIP_TEXT(1713) + * (清单 §1.7 明确「出牌阶段必须有」)此前只登记了精灵、没有布局槽位—— + * EQW_Layout.PLAY_OPERATION_BAR 的 items 只排了倒计时与出牌两项(清单 §6.8 自身也漏了它)。 + * 现已按 §1.7 的行文顺序补为第 3 项,宽度取 BTN_TIP 资源原生宽 180【估值,待设计稿复核】: + * 参考图 出牌.png 里未画出该按钮,位置仍属目视推定。 * * 资源说明: * - 提示按钮: EQW_Images.BTN_TIP (535), 1 帧, 180×63, 蓝色渐变(埋牌/出牌两条共用同一资源) diff --git a/client/js/01_SubGame/codes/config/Sprites_Result.js b/client/js/01_SubGame/codes/config/Sprites_Result.js index 4523d30..3c0e628 100644 --- a/client/js/01_SubGame/codes/config/Sprites_Result.js +++ b/client/js/01_SubGame/codes/config/Sprites_Result.js @@ -278,9 +278,16 @@ EQW_Sprites.ChongGuanOverlayView = { * route 是 room,真实取值路径是 data.deskfree.data.aset / .account(多一层 data 包装), * 且 data.deskfree 可能缺失(开战后、首局发牌前解散)→ 前端必须容忍。 * 解散的申请/投票/同意拒绝界面【由平台全包】(Layer 420),子游戏不做投票界面。 - * - 【无布局节点·待补】Layout_Result.js 目前只配了小局结算与冲关遮罩,本 View 的 - * ACC_* 一个布局节点都没有——上图坐标是参考图目视实测,尚未落进 EQW_Layout。 - * 实现前须先补齐布局配置,不得在渲染代码里就地硬编码坐标(零裸值红线)。 + * - 【布局节点已补齐 · 2026-08-27】见 Layout_Result.js「大局总结算」一节: + * 外壳 —— ACC_PANEL_BG / ACC_TITLE_BAR / ACC_TITLE_TEXT / ACC_BTN_CLOSE / + * ACC_RULE_BAR / ACC_RULE_TEXT + * 玩家栏(精灵复制)—— ACC_ROW_CONTAINER(容器)+ ACC_ROW(行模板,itemHeight 即行高, + * 行数由 ctx.count 给出)+ ACC_TPL_RANK / ACC_TPL_AVATAR / ACC_ROW_TEXT_GRID / + * ACC_TPL_SCORE_NUM / ACC_TPL_DIVIDER(都 attach 到 ACC_ROW 的行矩形上) + * 按钮 —— ACC_FUNC_BUTTONS(面板外底部 4 个) + * ⚠ 行内各节点求出的是【相对 ACC_ROW_CONTAINER 的】坐标,可直接喂 SpriteCopyUtils.create。 + * ⚠ 这些坐标是参考图【目视实测估值】(w/h 取资源尺寸),待设计稿复核; + * 但配置已成型,渲染代码一律引用节点,不得就地硬编码坐标(零裸值红线)。 * * 资源说明: * - 面板底: EQW_Images.PANEL_ACCOUNT (610), 1 帧, 1100×540, 圆角浅灰绿 @@ -390,8 +397,12 @@ EQW_Sprites.AccountView = { * 一次性弹出、不是常驻入口;不阻塞出牌,若面板还开着就收到出牌推送,直接收起即可。 * - 【与 MingPaiView 的关系】版式相同、渲染逻辑可共用,但数据独立、图层不同 * (304 vs 305),故拆成两个 View——一个 View 恰好一个图层。 - * - 【无布局节点·待补】Layout_*.js 里没有 HIST_* 布局节点;牌排可参照 - * EQW_Layout.CHONGGUAN_FAN 的同构参数,实现前须补齐配置,不在渲染代码里硬编码坐标。 + * - 【布局节点已补齐 · 2026-08-27】见 Layout_Result.js「出牌历史 / 上一轮 / 亮牌」一节: + * HIST_MASK(遮罩)/ HIST_BOX(三个容器同摆原点、铺满屏)/ HIST_FAN(每家一排牌, + * bySeat 三变体,锚点沿用 §6.7 冲关牌的 LEFT 260,120 · RIGHT 1035,120 · SELF 640,400)/ + * HIST_LABEL(三家座位标签,w/h 运行时注入)。 + * 与 CHONGGUAN_FAN 的差别只有张数上限:出牌历史摊平后可达 28 张以上, + * 故 maxWidth 放宽到 500、spacingMin 收到 -96【估值,待设计稿复核】。 * * 资源说明: * - 遮罩: EQW_Images.MASK_DIM (609), 1 帧, 纯色可拉伸(与冲关/明牌共用) @@ -463,7 +474,10 @@ EQW_Sprites.HistoryView = { * 关闭 / onDestroy 时必须 removeRange 清理。 * - 【为什么与 HistoryView 拆成两个 View】版式相同、渲染逻辑可共用,但两者数据独立、 * 图层不同(304 vs 305);本项目约定「一个 View 恰好一个图层」,故各自成 View。 - * - 【无布局节点·待补】Layout_*.js 里没有 MING_* 布局节点,同 HistoryView 的说明。 + * - 【布局节点已补齐 · 2026-08-27】见 Layout_Result.js「明牌面板」一节: + * MING_MASK / MING_BOX / MING_FAN / MING_LABEL,与 HIST_* 同构,差别只在【家数】—— + * bySeat 只有 LEFT / RIGHT 两个变体(MING_BOX_A 落 LEFT 位、MING_BOX_B 落 RIGHT 位), + * 没有 SELF 那排。坐标同为目视实测估值,待设计稿复核。 * * 资源说明: * - 遮罩: EQW_Images.MASK_DIM (609), 1 帧, 纯色可拉伸(与冲关/出牌历史共用同一资源) diff --git a/client/js/01_SubGame/codes/config/Sprites_Table.js b/client/js/01_SubGame/codes/config/Sprites_Table.js index 7e15f5b..47420f2 100644 --- a/client/js/01_SubGame/codes/config/Sprites_Table.js +++ b/client/js/01_SubGame/codes/config/Sprites_Table.js @@ -246,13 +246,13 @@ EQW_Sprites.ZhuStatView = { * docs_dev/uiref/自己是闲家时,底下的踩有分没分按钮.png; * 条底见 EQW_Layout.FOOTER_BG = point(0, 648, 1280×72)): * - * y=648 ┌──────────────────────────────────────────────────────────────────┐ - * │ ┌────┐ │ - * │ │头像│ 玩家昵称 10 [庄] 1/4 局 [明牌][已出牌][上一轮][底牌] │ - * │ └────┘ │ - * y=720 └──────────────────────────────────────────────────────────────────┘ + * y=648 ┌──────────────────────────────────────────────────────────────────────┐ + * │ ┌────┐ │ + * │ │头像│ 玩家昵称 10 [庄] 1/4 局 [明牌][已出牌][上一轮][扣底][底牌] │ + * │ └────┘ │ + * y=720 └──────────────────────────────────────────────────────────────────────┘ * └── 平台渲染,子游戏不碰 ──┘ - * (A) (B) (C) + * (A) (B) (C) * * (A) x≈335–573:庄印章与三个提示按钮【互斥】共用同一块区域(清单 §1.7)—— * 自己是庄 → P_SELF_BANKER(1120)(属 PlayerMarkView),point(338,668) 32×34 @@ -271,8 +271,8 @@ EQW_Sprites.ZhuStatView = { * (C) 右侧功能钮组 EQW_Layout.FOOTER_FUNC_BUTTONS:line/horizontal,右对齐到 x=1250, * anchorY=672,itemHeight=30,spacing=15,【逐项不等宽】(T-25): * BTN_MINGPAI(1042) 74 / BTN_HISTORY(1044) 87 / BTN_LAST_ROUND(1046) 93 / - * BTN_BOTTOM_CARDS(1048) 78 - * 四个按钮各按条件显隐、不全常驻(清单 §2.6);参考图里同时画出属叠画示意。 + * BTN_BURY_CARDS(1056) 78【估值】/ BTN_BOTTOM_CARDS(1048) 78 + * 五个按钮各按条件显隐、不全常驻(清单 §2.6);参考图里同时画出属叠画示意。 * * 元素说明: * - 每个按钮 = 一个图片精灵(按钮底)+ 一个文字精灵(按钮文案),成对出现。 @@ -280,23 +280,26 @@ EQW_Sprites.ZhuStatView = { * 明牌 —— 可查牌 + 出牌阶段 + 场上已有人报无主(baozhu==1),三家都显示 * 已出牌 —— 可查牌 + 出牌阶段 * 上一轮 —— 可查牌 + 出牌阶段 + 已打过至少一轮 + * 扣底 —— 仅庄家 + 已埋牌之后 * 底牌 —— 庄家全程;闲家仅开底过的局(70 分坐庄),见 S-3 * 踩/有分/没分 —— 自己是闲家 + 出牌阶段 - * - 【缺口】清单 §2.6 列的右侧功能按钮共 5 个(多一个「扣底」= 看庄家埋的 8 张), - * §5.1 精灵表与本文件只登记了 4 个,「扣底」按钮尚未分配精灵,号段 1056–1069 留有空位。 + * - 【扣底 ≠ 底牌,别写反】(清单 §0.0 / §2.6,验收清单第 13 条): + * 扣底 → 看【埋牌底牌】:庄家埋牌时从手里扣下的 8 张,字段 burycards(结算包为 bottom.cards) + * 底牌 → 看【底牌】 :发牌时没发给玩家、留在桌面的 8 张,字段 bottomcards + * 两批牌完全不同;内部变量建议按 buryCards / bottomCards 与字段名一一对应。 * * 资源说明: * - 底栏条: EQW_Images.BAR_FOOTER (608), 1 帧, 1280×72 - * - 功能钮底: EQW_Images.BTN_BOTTOM_FUNC (538), 1 帧, 88×30, 深色圆角(4 个按钮共用) + * - 功能钮底: EQW_Images.BTN_BOTTOM_FUNC (538), 1 帧, 88×30, 深色圆角(5 个按钮共用) * - 提示钮底: EQW_Images.BTN_TISHI (540), 1 帧, 52×30, 同风格但更窄(3 个按钮共用) * - * 精灵ID分配: 1040–1055(群组 205 号段 1040–1069) + * 精灵ID分配: 1040–1057(群组 205 号段 1040–1069) * * @see docs_dev/二七王-UI资源与精灵清单.md §2.6 底栏 / §1.7 闲家提示 / §5.1 / §6.5 * @see docs_dev/uiref/等待叫分.png * @see docs_dev/uiref/自己是闲家时,底下的踩有分没分按钮.png */ -//底栏:局数 + 功能按钮(明牌/已出牌/上一轮/底牌)+ 提示按钮(清单 §5.1 群组 205) +//底栏:局数 + 功能按钮(明牌/已出牌/上一轮/扣底/底牌)+ 提示按钮(清单 §5.1 群组 205) EQW_Sprites.FooterView = { Layer: EQW_Layers.TABLE_STATIC, //101 @@ -318,7 +321,12 @@ EQW_Sprites.FooterView = { BTN_TISHI_HAS: 1052, //图片:「有分」按钮,资源 EQW_Images.BTN_TISHI BTN_TISHI_HAS_TEXT: 1053, //文字:「有分」 BTN_TISHI_NONE: 1054, //图片:「没分」按钮,资源 EQW_Images.BTN_TISHI - BTN_TISHI_NONE_TEXT: 1055 //文字:「没分」 + BTN_TISHI_NONE_TEXT: 1055, //文字:「没分」 + + //——「扣底」按钮(2026-08-27 补齐):看【埋牌底牌】= 庄家埋下的 8 张(字段 burycards), + // 与上面的「底牌」按钮(看发牌留桌的 8 张,字段 bottomcards)是两批不同的牌,勿写反 —— + BTN_BURY_CARDS: 1056, //图片:「扣底」按钮,资源 EQW_Images.BTN_BOTTOM_FUNC + BTN_BURY_CARDS_TEXT: 1057 //文字:按钮文案「扣底」 } }; diff --git a/client/tests/test_constants.js b/client/tests/test_constants.js index 37a36aa..8aa8f16 100644 --- a/client/tests/test_constants.js +++ b/client/tests/test_constants.js @@ -43,7 +43,7 @@ const index = EQW_SpriteIndex.build(EQW_Sprites); const spriteVals = Object.keys(index).map(k => index[k]); // 钉住精确数量:松下界(如 >200)删掉整个 View 都还能通过。 // 增删精灵时连同本数字一起改——有意的顺手更新,不是有意的就红给你看 -t.eq('精灵总数', spriteVals.length, 378); +t.eq('精灵总数', spriteVals.length, 380); const spriteOk = spriteVals.every(v => v >= 1001 && v <= 2999); if (!spriteOk) { console.log('越界精灵: ' + JSON.stringify(spriteVals.filter(v => v < 1001 || v > 2999))); } t.eq('精灵落在 1001-2999', spriteOk, true); @@ -238,7 +238,7 @@ t.eq('全部布局节点可求解、矩形数与坐标都对', solveFailures, [] // 钉住节点总数:松下界(如 >40)删掉整个 View 都还能通过,任何意外的增删都要在这里可见。 // 增删布局节点时,连同本数字一起改——改动是有意的就顺手更新,不是有意的就红给你看 -t.eq('布局节点总数', allNodes.length, 61); +t.eq('布局节点总数', allNodes.length, 83); // ---- 布局文件是纯数据:不含函数 ---- const funcs = []; @@ -347,7 +347,9 @@ t.eq('NUM_STYLE 资源键存在且字段合法', numStyleProblems, []); ['MAIN_SUIT_COUNT', 'MAIN_SUIT_COUNT'], ['P_COUNTDOWN', 'COUNTDOWN'], ['RESULT_SCORE_NUM', 'RESULT_WIN'], - ['RESULT_SCORE_NUM', 'RESULT_LOSE'] + ['RESULT_SCORE_NUM', 'RESULT_LOSE'], + ['ACC_TPL_SCORE_NUM', 'RESULT_WIN'], + ['ACC_TPL_SCORE_NUM', 'RESULT_LOSE'] ].forEach(pair => { const node = EQW_Layout[pair[0]]; const st = EQW_Layout.NUM_STYLE[pair[1]]; diff --git a/client/tests/test_spriteindex.js b/client/tests/test_spriteindex.js index d803d27..9609b78 100644 --- a/client/tests/test_spriteindex.js +++ b/client/tests/test_spriteindex.js @@ -83,6 +83,6 @@ let realIndex = {}; try { realIndex = EQW_SpriteIndex.build(EQW_Sprites); } catch (e) { realOk = false; console.log('建索引失败: ' + e.message); } t.eq('真实精灵常量无重复键', realOk, true); // 钉住精确数量(与 test_constants.js 同一个数):松下界删掉整个 View 都还能通过 -t.eq('真实精灵数量', Object.keys(realIndex).length, 378); +t.eq('真实精灵数量', Object.keys(realIndex).length, 380); process.exit(t.done('spriteindex') ? 0 : 1); diff --git a/docs_dev/二七王-UI资源与精灵清单.md b/docs_dev/二七王-UI资源与精灵清单.md index 5eef11f..777fdbb 100644 --- a/docs_dev/二七王-UI资源与精灵清单.md +++ b/docs_dev/二七王-UI资源与精灵清单.md @@ -198,7 +198,7 @@ get_nextseat: function(seat){ return (seat + 1) % 3; } | --- | --- | | 201 | 顶部信息条(主 / 叫分 / 抓分) | | 202 / 203 / 204 | 左上家 / 右上家 / 自己 的附加标记(庄印章、主N对N、状态文字) | -| 205 | 底栏功能按钮组(明牌 / 已出牌 / 上一轮 / 底牌) | +| 205 | 底栏功能按钮组(明牌 / 已出牌 / 上一轮 / 扣底 / 底牌) | | 206 | **主牌统计条**(自己的 `x对 x主`,§2.5)—— 常量名 `ZHU_STAT_BAR` | | 210 | 自己手牌 | | 211 | 底牌区(发牌留桌 8 张) | @@ -214,6 +214,7 @@ get_nextseat: function(seat){ return (seat + 1) % 3; } | 241 | 大局总结算 | | 242 | 出牌历史 | | 243 | 明牌面板 | +| 244 | 冲关牌型叠加层(§5.6a) | | 250 | 建房规则选项 | > **2026-08-27 修订 · 群组 206 改名**:原名「亮牌信息条 / `LIANGPAI_BAR`」,实为 §2.5 的**自己的主牌统计条**(手牌上方 `x对 x主`,本地统计、有手牌时常显),与 design §8.2 的「**亮牌**」(庄家埋牌后向两个闲家亮出自己全部固定主牌的**具体牌面**,走遮罩面板、群组 242)**同名异实**——§0.0 已专门花一节区分「亮牌 / 余主公示 / 明牌 / 开底」四类公开信息,名字撞车极易把渲染写到错误的界面上。 @@ -623,7 +624,7 @@ EQW_RoomOptions = { **收到 `maipai` 推送后**(字段 `cards`、`bottomcards`、`seat`、`countdown`、`liangpai`): - 庄家手牌回到单排 28 张; -- **闲家**若收到 `liangpai`(仅可查牌模式 + 庄家达标),弹出下方「亮牌」**遮罩面板**(群组 242,精灵 `HIST_*`,见 §5.7b)——**不是** §2.5 那条主牌统计条(原表述「渲染 §2.5 亮牌信息条」是同名异实造成的笔误,2026-08-27 订正); +- **闲家**若收到 `liangpai`(仅可查牌模式 + 庄家达标),弹出下方「亮牌」**遮罩面板**(群组 242,精灵 `HIST_*`,见 §5.7b / §6.9c)——**不是** §2.5 那条主牌统计条(原表述「渲染 §2.5 亮牌信息条」是同名异实造成的笔误,2026-08-27 订正); - 进入出牌,`seat` = 首出者(必为庄家)。 **亮牌**(design §8.2,协议 `liangpai`): @@ -1048,7 +1049,7 @@ y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2) > > **实现要求**:前端内部变量仍建议用 `bottomCards` / `buryCards` 区分,与字段名一一对应。已列入验收清单(§7.3)。 -- 精灵:群组 205,号段 1040–1069(5 个按钮 × 2 精灵 = 10)。 +- 精灵:群组 205,号段 1040–1069(5 个功能按钮 × 2 精灵 = 10,`扣底` 为 1056/1057,2026-08-27 补齐;另有 3 个提示按钮 × 2 精灵)。 ### 2.7 手牌区 【图:全部】 @@ -1293,6 +1294,8 @@ design 与协议均**未定义任何音效**。以下是按牌类游戏常规推 | | 1053 | `BTN_TISHI_HAS_TEXT` | 文字 | `有分` | —— | | | 1054 | `BTN_TISHI_NONE` | 图片 | `没分` | `BTN_TISHI` | | | 1055 | `BTN_TISHI_NONE_TEXT` | 文字 | `没分` | —— | +| | **1056** | `BTN_BURY_CARDS` | 图片 | **`扣底`**(看**埋牌底牌**,2026-08-27 补齐) | `BTN_BOTTOM_FUNC` | +| | **1057** | `BTN_BURY_CARDS_TEXT` | 文字 | 按钮文案 `扣底` | —— | | **202** 左上家标记 | 1100 | `P_LEFT_BANKER` | 图片 | `庄` 印章 | `MARK_BANKER` | | | 1101 | `P_LEFT_ZHU_BG` | 图片 | `主N` 角标底 | `BADGE_ZHU_PAIR` 帧1 | | | 1102 | `P_LEFT_ZHU_TEXT` | 文字 | 剩余主牌数 | —— | @@ -1464,6 +1467,8 @@ for (var i = 0; i < cards.length; i++) { **清理**:关闭面板时 `removeRange` 清掉各段。 > 解散结算复用本面板(协议 §14.1,解散包也带 `account`),只是 `aset` 各项为 0。 +> +> **布局配置见 §6.9a**(2026-08-27 补齐;此前本 View 没有任何布局节点)。 ### 5.7b Layer 304 / 305 · 出牌历史与明牌(群组 242 / 243,**牌用精灵复制**) @@ -1486,6 +1491,8 @@ for (var i = 0; i < cards.length; i++) { - **亮牌**:只显示一排(庄家的固定主牌),数据 = `liangpai.cards`(§1.6)。复用同一套遮罩 + 容器 + 牌模板,仅数据源与排数不同。 ⚠ 这里的「亮牌」是 design §8.2 那件事,**与 §2.5 手牌上方的主牌统计条(群组 206 `ZHU_STAT_*`)无关**——后者 2026-08-27 前也叫「亮牌条」,已改名以消歧义。 +> **布局配置见 §6.9c**(2026-08-27 补齐;此前 `HIST_*` / `MING_*` 都没有布局节点)。 +> > 解散投票由平台提供(Layer 420),子游戏无需精灵。 ### 5.8 建房规则选项(群组 250,2050–2099,预置) @@ -1681,7 +1688,7 @@ CARD_SIZE: { | 主牌统计条(节点 `ZHU_STAT_BG`) | `point` | `x:35 y:400 w:210 h:35` | | 底栏条 | `point` | `x:0 y:648 w:1280 h:72` | | 底栏 · 局数文字 | `point` | `x:635 y:672 w:65 h:26`,`textStyle{fontSize:20, align:center}` | -| 底栏 · 功能钮组(明牌/已出牌/上一轮/底牌) | `line` + `items` | `direction:horizontal, anchorX:1250, anchorY:672, itemHeight:30, spacing:15, anchor:right`,`items:[74,87,93,78]`(逐项不等宽,见 §6.1) | +| 底栏 · 功能钮组(明牌/已出牌/上一轮/**扣底**/底牌) | `line` + `items` | `direction:horizontal, anchorX:1250, anchorY:672, itemHeight:30, spacing:15, anchor:right`,`items:[74,87,93,**78***,78]`(逐项不等宽,见 §6.1)。**\*`扣底` 的 78 是估值**(2026-08-27 补项,本表原只列 4 项)——同为两字按钮的 `底牌` 实测 78、`明牌` 74,故取 78,待设计稿复核 | | 底栏 · 庄标 | `point` | `x:338 y:668 w:32 h:34` | | 底栏 · 提示按钮组(踩/有分/没分) | `line` | `direction:horizontal, anchorX:335, anchorY:672, itemWidth:52, itemHeight:30, spacing:26, anchor:left` | | 右侧语音钮(平台) | `point` | `x:1210 y:310 w:56 h:56` | @@ -1747,7 +1754,7 @@ CARD_SIZE: { | 选主 · 张数 | `attach` | `target:对应花色按钮, hAlign:center, vAlign:bottom, offsetY:-6, h:NUM_STYLE.MAIN_SUIT_COUNT.charHeight(32)`;`w` 运行时注入(`9张`=2 字符、`26张`=3 字符,宽度随之变)。一个花色一个精灵 | | 选主 · 对数角标文字 | `attach` | `target:对应花色按钮, corner:topRight, offsetX:-36, offsetY:2`(按钮帧内已含角标底,本节点只定位叠加文字) | | 埋牌 · 操作条 | `line` + `items` | `direction:horizontal anchorX:640 anchorY:165 itemHeight:63 spacing:45 anchor:center`,`items:[180,60,180]`(提示 / 倒计时 / 埋牌) | -| 出牌 · 操作条 | `line` + `items` | `direction:horizontal anchorX:640 anchorY:345 itemHeight:55 spacing:35 anchor:center`,`items:[75,157]`(倒计时 / 出牌) | +| 出牌 · 操作条 | `line` + `items` | `direction:horizontal anchorX:640 anchorY:345 itemHeight:55 spacing:35 anchor:center`,`items:[75,157,**180***]`(倒计时 / 出牌 / **提示**)。**\*`提示` 的 180 是估值**(2026-08-27 补项,本表原漏了 §1.7 明确要求的 `提示` 按钮)——与埋牌条的 `提示` 同资源 `BTN_TIP`(§3.3 实测 180×63),埋牌条 `items` 首项亦取 180,故沿用;顺序照 §1.7 行文。⚠ 本条 `itemHeight:55` 对齐的是 `BTN_PLAY`(157×55),而 `BTN_TIP` 原生高 63,高度差待设计稿裁定 | | 捡分飘字 | `point` | `x:570 y:180 w:170 h:55`;另配 `floatRise:-60`、`floatDuration:800`(动画参数也进配置) | | 状态提示条 · 等待类 | `point` | `x:500 y:373 w:320 h:47`(§2.8) | | 状态提示条 · 即时反馈类 | `point` | `x:462 y:172 w:363 h:50`;另配 `toastDuration:1500` | @@ -1781,6 +1788,48 @@ CARD_SIZE: { | `下一局` 按钮 | `point` | `x:835 y:518 w:180 h:65` | | 冲关遮罩 | `point` | `x:0 y:0 w:1280 h:720`,`opacity:0.72`(透明度也是配置项) | +#### 6.9a 大局总结算配置(§1.9 / §5.7a,2026-08-27 补齐) + +> 本表原先**整块缺失**——`Layout_Result.js` 里一个 `ACC_*` 节点都没有,实现时极易在渲染代码里就地硬编码坐标(违反 §6 零裸值)。 +> **坐标全部是 `uiref/大局结算.png` 的目视实测估值(±5px)**,`w`/`h` 取 §3.5 / §3.3 的资源尺寸(那是权威值)。**待设计稿复核**。 +> **玩家栏是精灵复制**(§5.7a),故不逐行写死,而是给「容器 + 行节点(行高即 `itemHeight`)+ 行内模板贴附到行矩形」;行数由数据给出(`ctx.count`),不进配置。 +> ⚠ `ACC_ROW` 及贴附其上的节点求出的坐标都是**相对 `ACC_ROW_CONTAINER` 的**——复制精灵是容器的子精灵,`x/y` 本就相对容器,求解结果可直接喂 `SpriteCopyUtils.create`(与 §5.6a 冲关牌同一用法)。 + +| 部件 | 节点名 | kind | 参数(目视实测估值) | +| --- | --- | --- | --- | +| 面板底 | `ACC_PANEL_BG` | `point` | `x:80 y:88 w:1100 h:540` | +| 标题栏 | `ACC_TITLE_BAR` | `attach` | `target:ACC_PANEL_BG, corner:topLeft, offset(0,0), w:1100 h:56` | +| 标题文字 | `ACC_TITLE_TEXT` | `attach` | `target:ACC_TITLE_BAR, hAlign:left, vAlign:middle, offsetX:30`;`w/h` 运行时注入(文案长度不定) | +| 关闭按钮 | `ACC_BTN_CLOSE` | `attach` | `target:ACC_TITLE_BAR, corner:topRight, offset(-20,10), w:36 h:36` | +| 规则栏 | `ACC_RULE_BAR` | `attach` | `target:ACC_PANEL_BG, corner:bottomLeft, offset(0,0), w:1100 h:62` | +| 规则文字 | `ACC_RULE_TEXT` | `attach` | `target:ACC_RULE_BAR, hAlign:left, vAlign:middle, offsetX:30`;`w/h` 运行时注入 | +| 玩家栏**容器** | `ACC_ROW_CONTAINER` | `point` | `x:80 y:144 w:1100 h:422`(标题栏下沿 → 规则栏上沿) | +| 玩家栏**行** | `ACC_ROW` | `line` | `direction:vertical, anchorX:0, anchorY:14, itemWidth:1100, **itemHeight:132(行高)**, spacing:0, anchor:top`(相对容器;行数 = `ctx.count`) | +| 行内 · 名次徽章 | `ACC_TPL_RANK` | `attach` | `target:ACC_ROW, hAlign:left, vAlign:middle, offsetX:28, w:44 h:44` | +| 行内 · 头像 | `ACC_TPL_AVATAR` | `attach` | `target:ACC_ROW, hAlign:left, vAlign:middle, offsetX:92, w:80 h:80` | +| 行内 · 文字栅格(6 条文字的槽位) | `ACC_ROW_TEXT_GRID` | `grid` | `anchorX:192, cols:4, rows:2, itemWidth:176, itemHeight:34, spacingX:0, spacingY:10, anchor:left, fillOrder:row`;`anchorY` 运行时注入(随所在行浮动)。列序:昵称/`ID:` · 基础分/总得分 · 冲关分 · 傍王分(第 2 行仅前两列有文字) | +| 行内 · 右侧总分大字 | `ACC_TPL_SCORE_NUM` | `attach` | `target:ACC_ROW, hAlign:right, vAlign:middle, offsetX:-25, h:NUM_STYLE.RESULT_WIN.charHeight(62)`;`w` 运行时注入 | +| 行内 · 分隔线 | `ACC_TPL_DIVIDER` | `attach` | `target:ACC_ROW, hAlign:center, vAlign:bottom, offset(0,0), w:1060 h:2`(`vAlign:bottom` 的语义是"目标底边之下",见 §6.0) | +| 面板**外**底部 4 按钮 | `ACC_FUNC_BUTTONS` | `line` | `direction:horizontal, anchorX:345, anchorY:640, itemWidth:190, itemHeight:60, spacing:25, anchor:left`(参考图里这排不居中于屏幕、整体偏右,故用 `anchor:left` 定起点) | + +#### 6.9c 出牌历史 / 亮牌 · 明牌配置(§5.7b,2026-08-27 补齐) + +> 本表同样原先**整块缺失**(`HIST_*` / `MING_*` 一个节点都没有)。 +> 两者与冲关牌型叠加层是**同一种版式**(半透黑遮罩 + 每家一排重叠大牌,参考图同为 `uiref/冲关牌型显示.png`),故照 §6.7 的 `CHONGGUAN_FAN` 同构给出,三家锚点沿用冲关牌的 `LEFT 260,120 / RIGHT 1035,120 / SELF 640,400`。 +> **与冲关牌的唯一差别是张数上限**:出牌历史摊平后可达 28 张以上,`maxWidth:420` 装不下,故放宽到 **500**、`spacingMin` 收到 **-96**(每张露 14px,28 张总宽 `110+27×14=488 ≤ 500`)。这两个数是**估值,待设计稿复核**。 +> 牌用精灵复制:三个容器精灵摆在原点、尺寸铺满屏,故 `fan` 求出的屏幕坐标可直接当容器内坐标用。 + +| 部件 | 节点名 | kind | 参数 | +| --- | --- | --- | --- | +| 出牌历史 · 遮罩 | `HIST_MASK` | `point` | `x:0 y:0 w:1280 h:720, opacity:0.72`(【亮牌】用途下**不注册点击**,见 §1.6) | +| 出牌历史 · 三个牌容器 | `HIST_BOX` | `point` | `x:0 y:0 w:1280 h:720`(同摆原点、铺满屏) | +| 出牌历史 · 每家一排牌 | `HIST_FAN` | `fan` | `size:L, anchor:center, maxWidth:500, spacingMax:-40, spacingMin:-96`;`bySeat{ LEFT:{260,120}, RIGHT:{1035,120}, SELF:{640,400} }` | +| 出牌历史 · 座位标签 | `HIST_LABEL` | `point` | `bySeat{ LEFT:{200,318}, RIGHT:{975,318}, SELF:{580,598} }`;`w/h` 运行时注入 | +| 明牌 · 遮罩 | `MING_MASK` | `point` | 同 `HIST_MASK` | +| 明牌 · 两个牌容器 | `MING_BOX` | `point` | 同 `HIST_BOX` | +| 明牌 · 每家一排牌 | `MING_FAN` | `fan` | 同 `HIST_FAN`,但 **`bySeat` 只有 LEFT / RIGHT**(明牌只看他家,没有自己那排;精灵 `MING_BOX_A` 落 LEFT 位、`MING_BOX_B` 落 RIGHT 位) | +| 明牌 · 座位标签 | `MING_LABEL` | `point` | `bySeat{ LEFT:{200,318}, RIGHT:{975,318} }`;`w/h` 运行时注入 | + ### 6.9b 建房规则选项配置(§1.1) 布局是**两层嵌套**:类别竖排,类别内的选项组横排。