Files
erqiwang_youle/client/js/01_SubGame/codes/config/Layout_Result.js
T
joywayerandClaude Opus 5 8f36b61620 二七王:补齐三处配置缺口(扣底按钮 / 出牌提示按钮槽位 / 三个 View 的布局节点)
这三处都是「精灵或按钮已在清单里定案,但配置层缺东西」,不补的话 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) <noreply@anthropic.com>
2026-08-27 08:40:48 +08:00

249 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
///////////////////////////////////////////////////////////////
////////// EQW_Layout: 结算区配置(清单 §6.9 / §5.7a / §5.7b)///
///////////////////////////////////////////////////////////////
// 小局结算 + 冲关遮罩 + 大局总结算 + 出牌历史/亮牌 + 明牌,共五块。
// 【纯数据文件】无函数、无副作用;依赖 LayoutConstants.js 先加载
// (引用其 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 };
//底牌说明文字:贴面板底部,纯文字,清单未给宽高
EQW_Layout.RESULT_BOTTOM_TEXT = {
kind: 'attach', targetKind: 'layout', target: 'RESULT_BOTTOM_PANEL',
hAlign: 'center', vAlign: 'bottom', offsetY: -14,
runtime: ['w', 'h']
};
//三家分数光晕
EQW_Layout.RESULT_GLOW = {
kind: 'point', w: 225, h: 100,
bySeat: {
LEFT: { x: 175, y: 150 },
RIGHT: { x: 865, y: 150 },
SELF: { x: 490, y: 340 }
}
};
//三家总分大字(多帧图数字精灵,非文字精灵,2026-08-27):贴对应光晕居中。
//target 直接指向光晕精灵键(固定,非动态);高度恒为单字高,取 NUM_STYLE.RESULT_WIN.charHeight
//(与 NUM_STYLE.RESULT_LOSE 相同,SSOT);宽度随位数变化,留到运行时注入
//节点名去掉 _TEXT 后缀改为 _NUM:与 CALL_BTN_SCORE_NUM 同一理由,_TEXT 会让人误以为是文字精灵
EQW_Layout.RESULT_SCORE_NUM = {
kind: 'attach', targetKind: 'sprite', hAlign: 'center', vAlign: 'middle',
h: EQW_Layout.NUM_STYLE.RESULT_WIN.charHeight, runtime: ['w'],
bySeat: {
LEFT: { target: 'RESULT_GLOW_LEFT' },
RIGHT: { target: 'RESULT_GLOW_RIGHT' },
SELF: { target: 'RESULT_GLOW_SELF' }
}
};
//三家『牌局分』:贴对应光晕左下
EQW_Layout.RESULT_JF_TEXT = {
kind: 'attach', targetKind: 'sprite', hAlign: 'left', vAlign: 'bottom', offsetX: -15, offsetY: 24,
runtime: ['w', 'h'],
bySeat: {
LEFT: { target: 'RESULT_GLOW_LEFT' },
RIGHT: { target: 'RESULT_GLOW_RIGHT' },
SELF: { target: 'RESULT_GLOW_SELF' }
}
};
//三家『冲关分』:贴对应光晕右下
EQW_Layout.RESULT_AW_TEXT = {
kind: 'attach', targetKind: 'sprite', hAlign: 'right', vAlign: 'bottom', offsetX: 15, offsetY: 24,
runtime: ['w', 'h'],
bySeat: {
LEFT: { target: 'RESULT_GLOW_LEFT' },
RIGHT: { target: 'RESULT_GLOW_RIGHT' },
SELF: { target: 'RESULT_GLOW_SELF' }
}
};
EQW_Layout.RESULT_BTN_CG = { kind: 'point', x: 535, y: 515, w: 183, h: 63 };
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 }
}
};