上一版把 maxWidth 收窄到 490 只是让 RIGHT 座位恰好贴住画布边界(零余量),且 spacingMin:-96 在 28 张时永远不触底、成了死参数。裁定改为 480: (480-110)/27-110≈-96.30 超过 spacingMin,spacing 被截断为 -96,总宽变为 28×110+27×(-96)=488,与清单原注释「每张露14px、总宽488」精确对齐——500 是笔误, 488 才是当初想要的值。 求解器验证(count=28):LEFT 16→504、RIGHT 791→1279、SELF 396→884,三座位均落在 0-1280 内且有余量。同步订正 Layout_Result.js 注释与清单 §6.9c 文字/数值。 client/tests/run.js 与 server/games/erqiwang/test/run.js 均全绿,精灵总数(380)/ 布局节点数(83) 未变。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
157 KiB
二七王 · 前端 UI 资源与精灵清单
本文用途:把二七王的完整游戏流程翻译成「前端需要哪些图片资源、声音、精灵、图层、群组、坐标」的可执行规格书,供美术出图与 gameabc 编辑器建资源使用。
本文不是代码。文中给出的 ID 是规划建议值(相应号段已核实为空闲,见 §0.3),用途是指导在编辑器里按此建立;代码里引用的 ID 必须与编辑器中实际建成的完全一致,若编辑器实际取值与本文不同,以编辑器为准并回头修订本文。前端红线明令「绝不编造 ID」,指的就是代码侧。
权威源:玩法规则以
server/games/erqiwang/docs/design/design.md为准;下发字段以server/games/erqiwang/docs/protocol/packet_protocol.md为准;前端规范以docs/client/development-guide/为准。本文只做「规则/协议 → 界面资源」的映射,不重新定义规则。参考图:
./uiref/*.png,共 16 张,设计分辨率 1280×720。
目录
0. 总则
0.0 术语(本项目修订版,优先于 design.md)
2026-08-25 修订:原 design.md 里「暗牌 / 底牌」的命名与界面按钮倒挂,现统一为:
| 术语 | 指哪 8 张 | design.md 原称 | 当前协议字段 |
|---|---|---|---|
| 底牌 | 发牌时没有发给玩家、留在桌面的 8 张 | bottomcards |
|
| 埋牌底牌 | 庄家埋牌时从手里扣下的 8 张 | burycards(结算包为 bottom.cards) |
其余术语(埋牌、扣底、甩牌、毙牌、垫牌、捡分、子、奖…)沿用 design.md §1 不变。注意「扣底」仍指 design §6.3 那条规则——闲家用主牌赢下最后一轮后翻开埋牌底牌计分;底栏那个 扣底 按钮是「查看埋牌底牌」的入口,两者同名但不同义。
✅
design.md与packet_protocol.md已同步此变更(S-5 完成),协议字段名也已拆分为bottomcards/burycards(S-4 完成)。
算奖 = 冲关 + 傍王
| 术语 | 范围 | 界面 | 字段 |
|---|---|---|---|
| 冲关 | design §8.1,只计庄家(旧称「常规算奖」) | 小局结算「冲关分」、「冲关牌型」按钮 | chongguan、cards |
| 傍王 | design §8.3,可选规则,勾选后庄闲都算,每张王 1 奖 | 大局结算「傍王分」 | wang、bangwang |
| 算奖 | 上位概念 = 冲关 + 傍王 | —— | naward(总奖数 N)、grade_aw(算奖得分) |
说「冲关」指庄家那一份,说「算奖」指两者合计。
小局结算的「冲关分」取
grade_cg(S-6 已把算奖得分拆成冲关 / 傍王两个分量),开傍王时也不会把傍王的贡献算进来。
四类「公开信息」——名字像、含义差很远
| 术语 | 谁公开给谁 | 给的是什么 | 触发 | 界面位置 | 字段 |
|---|---|---|---|---|---|
| 亮牌 | 庄家 → 两个闲家 | 具体牌面(庄家全部固定主牌) | 庄家埋牌后固定主牌达门槛(design §8.2) | 遮罩面板,同明牌版式(§1.6) | liangpai.cards |
| 余主公示 | 全体 → 全体 | 只有数量(剩余主牌数、主对数) | 任一玩家报无主(design §9) | 他家头像下 主N 对N 角标(§2.5) |
seatlist[seat][4]、baozhu |
| 明牌 | 他家 → 请求者 | 具体牌面 | 可查牌 + 场上有人报无主,三家均可点、随时可查(design §9) | 遮罩面板(§1.7 D-6) | mingpai.others[].zhucards |
| 开底 | 桌面 → 所有玩家 | 具体牌面(8 张底牌) | 70 分坐庄,摸底之前 3 秒(design §4) | 复用底牌区翻牌(§1.4 D-2) | ancard3s + bottomcards |
一句话记:只有「余主公示」是统计类(给数字),「亮牌」「明牌」「开底」都给具体牌面——区别在给谁的牌:亮牌给庄家自己的、明牌给他家的、开底给桌上那 8 张。
另有一组「底」字族专管发牌留桌的那 8 张牌:
| 术语 | 含义 | 前端对应 |
|---|---|---|
| 摸底 | 庄家坐定后把 8 张底牌摸起查看并入手牌 | 底牌区翻正面(非 70 分只有庄家看得到) |
| 开底 | 70 分坐庄,摸底之前向全场翻开 3 秒 | 同上,但闲家侧也翻开 |
| 查底牌 | 对局中随时回看这 8 张 | 底栏 底牌 按钮(§2.6) |
| 扣底 | 末轮闲家用主牌赢下,翻开埋牌底牌计分 | 底栏 扣底 按钮看的是埋牌底牌 |
「亮主」不是术语——它是选主界面的标题文案(庄家选主牌花色那一步,见
亮主.png),与上表四项都无关。文档与代码里不要拿它指代任何规则。另:自己的主牌统计条(手牌上方
x对 x主,§2.5)不属于上表任何一项——那是本地统计、始终显示,不涉及"公开"。它在代码里叫ZHU_STAT_*(群组 206);2026-08-27 前叫LIANGPAI_*,因与上表第一项「亮牌」同名异实而改名,见 §0.3 群组表下的修订说明。
0.1 设计基准与座位映射
| 项 | 值 | 来源 |
|---|---|---|
| 设计分辨率 | 1280 × 720 | client/output/gameabc_Project.json ScreenWidth/ScreenHeight;11 张牌桌参考图均为 1280×720;叫分按钮面板与建房参考图为局部截图 |
| 适配模式 | ScreenFitMode: 1 |
同上 |
| 帧率 | 30 fps | 同上 |
| 玩家数 | 3 人 | design §2(三家各摸 28 张) |
座位映射:服务端座位是绝对序号 0/1/2;前端一律把自己放在底部,另两家按 design §4 的逆时针顺序分居左上、右上。
右上 = (mySeat + 1) % 3 左上 = (mySeat + 2) % 3
┌───────────┐
[左上玩家] │ 桌面中央 │ [右上玩家]
└───────────┘
[ 自己 · 底部 ]
方向已定论(server/games/erqiwang/class.paiju.js:264):
get_nextseat: function(seat){ return (seat + 1) % 3; }
即下家 = (seat + 1) % 3。逆时针出牌在屏幕视觉上「下家在右手边」(时钟 6 点逆时针走向 3 点),与中式牌桌「下家 = 右手边」的惯例一致。因此:
| 显示位 | 座位 |
|---|---|
| 底部(自己) | mySeat |
| 右上(下家) | (mySeat + 1) % 3 |
| 左上(上家) | (mySeat + 2) % 3 |
本文各表均按此书写。轮庄「顺延到其下家」(design §4.6)走的也是同一个 get_nextseat。
0.2 平台已提供、子游戏不重建的部分
参考图里有若干元素来自平台框架,美术不必重复出图、编辑器不必重复建精灵:
| 元素 | 平台提供方式 | 精灵/资源 | 子游戏要做的 |
|---|---|---|---|
| 头像框 / 头像 / 昵称 / 分数 | 02_SubGame_Input.js 转发壳 updatePlayerInfoUI 的 D 类默认渲染 |
底框 346+ind、头像框 376+ind、昵称 406+ind、分数 436+ind、头像图 116+ind、群组 43+ind |
只在 01_SubGame_modify.js 配置区调 Game_Modify.PLAYER_INFO_LAYOUT 的坐标(三人局用 ind0 南 / ind1 东 / ind3 西) |
| 桌面聊天气泡 / 语音气泡 | 同上,ShowChat / gameui_play_voice / gameui_stop_voice |
聊天 背景 552+ind 文字 582+ind;语音 背景 612+ind 内容 642+ind |
只调 Game_Modify.BUBBLE_LAYOUT 坐标 |
| 右侧语音圆钮 / 聊天圆钮 | 平台外壳 | 参考图右侧 (1210,310)/(1210,385) 两枚圆钮 | 无(仅坐标核对) |
| Loading / Message / Confirm 全局弹窗 | 框架 UIManager 全局 UI |
由子游戏在 UIManager.init 注入精灵常量 |
若要用,需另建这三套弹窗精灵并注入;不用则跳过 |
| 战绩列表 | 框架 RecordView 组件 + 平台入口精灵 13 |
gameabc-framework/ui/RecordView.js |
提供 RecordView 配置;战绩数据结构见协议「gameinfo1 / gameinfo2」 |
| 帮助界面 | 平台 GameUI.OpenHelp(),入口精灵 150 |
—— | 提供二七王玩法说明文案 |
| 创建房间界面骨架 | 平台界面 Layer 27 CreateRoom_Layer + 约定精灵 25(确认/提交按钮) |
见 01_SubGame_modify.js 顶部注释 |
规则选项区要子游戏自建(§1.1):渲染选项、拼 roomtype 串、注册 25 号点击后 Net.Send_create_room |
| 解散申请 / 投票 / 同意拒绝 | 平台全包:Layer 420 CheckFree_Layer + GameUI.openCheck/closeCheck + Desk.self_apply_free_room / other_apply_free_room / self_agree_free_room / self_refuse_free_room / agreefree / free_room |
—— | 无。子游戏只需处理解散结算包(§1.10),投票界面不用做 |
| 高级选项 / 代开房 | Layer 28 SeniorOptions_Layer + GameUI.openSeniorOptions |
—— | 无。它管短号 / 抽水 / 房间列表,与玩法规则选项无关,二七王的规则选项不走这里 |
平台已占用的图层一览(读 gameabc_Layer.json,凡此列出者子游戏都不必重建):
| 图层 | 名称 | 用途 |
|---|---|---|
| 27 / 28 | CreateRoom_Layer / SeniorOptions_Layer |
创建房间 / 高级选项 |
| 50 | MainScene_Layer |
牌桌主场景 |
| 202 / 416 | Player_Head_Score_Layer / MainScene_PlayerInfo_Layer |
玩家头像与分数 |
| 409 / 410 / 418 | Chat_Voice_Layer / Chat_Text_Layer / ChatPannel_Layer |
聊天与语音 |
| 420 | CheckFree_Layer |
解散投票 |
| 608 / 609 | Help_Layer / Setting_Layer |
帮助 / 设置 |
| 612 | Tips_Layer |
通用提示 |
| 613 | updateRoomCard_Layer |
房卡更新 |
| 614 / 615 | Loading_Layer / Reconnect_Layer |
加载 / 断线重连 |
| 616 / 619 | Kick_Layer / BackHall_Layer |
踢人 / 返回大厅 |
| 620 | recordLayer |
战绩 |
这些都落在框架保留段(1–100 / 201–300 / 401–500 / 601–700),与子游戏段 101–200 / 301–400 不冲突。
⚠️ 参考图底栏左侧的「头像 + 玩家昵称 + 10 + 庄」一行里,头像/昵称/分数是平台的,只有
庄印章是二七王专属、需子游戏新建。左上/右上玩家位同理:头像框是平台的,庄印章、主N、对N角标、状态文字是子游戏的。
0.3 ID 号段规划
占用现状核实(读 client/output/gameabc_*.json,日期 2026-08-24):
| 类别 | 已占用 | 子游戏合法段 | 段内空闲情况 |
|---|---|---|---|
| 精灵 ObjectID | 1–3292 中 991 个 | 1001–3000 | 段内仅 3000 被占(Spirit3000,Layer 602 inputPannel,群组 87)→ 实际可用 1001–2999 |
| 图层 LayerID | 1–29, 50, 202, 402–420, 601–620 | 101–200 / 301–400 / 501–600 / 701+ | 全部空闲 |
| 群组 GroupID | 0–79 | ≥ 201 | 全部空闲 |
| 图片资源 ID | 1–439 | ≥ 501 | 全部空闲 |
| 声音资源 ID | 1–5 | ≥ 101 | 全部空闲 |
二七王的分段规划:
图层(Layer)
| 图层 | 名称 | 用途 |
|---|---|---|
| 101 | EQW_Table_Static |
牌桌常驻:顶部信息条、玩家位附加标记、主牌统计条、底栏(局数 + 功能钮) |
| 102 | EQW_Hand |
自己手牌区(单排 / 埋牌双排) |
| 103 | EQW_TableCards |
桌面牌:底牌区、三家已出牌区、埋牌底牌展示区 |
| 104 | EQW_Action |
阶段操作区:叫分面板、选主/投降面板、埋牌/出牌操作条、倒计时 |
| 105 | EQW_Overlay |
桌面浮层:提示气泡、报无主、甩错、捡分飘字、70 分底牌亮 3 秒 |
| 302 | EQW_Popup_AsetResult |
小局结算 |
| 303 | EQW_Popup_Account |
大局总结算 / 解散结算 |
| 304 | EQW_Popup_History |
出牌历史面板 |
| 305 | EQW_Popup_MingPai |
明牌面板 |
| 306 | EQW_Popup_Disband |
解散投票面板 —— T-2:是否由平台提供待确认 |
建房规则选项区(§1.1)的精灵挂在平台创建房间界面所在的图层上,不新开图层;具体图层号需在编辑器里查证后回填(T-3)。
群组(Group)
| 群组 | 用途 |
|---|---|
| 201 | 顶部信息条(主 / 叫分 / 抓分) |
| 202 / 203 / 204 | 左上家 / 右上家 / 自己 的附加标记(庄印章、主N对N、状态文字) |
| 205 | 底栏功能按钮组(明牌 / 已出牌 / 上一轮 / 扣底 / 底牌) |
| 206 | 主牌统计条(自己的 x对 x主,§2.5)—— 常量名 ZHU_STAT_BAR |
| 210 | 自己手牌 |
| 211 | 底牌区(发牌留桌 8 张) |
| 212 / 213 / 214 | 自己 / 左上家 / 右上家 的已出牌区 |
| 215 | 埋牌底牌展示区(结算时 8 张) |
| 220 | 叫分面板 |
| 221 | 选主 / 投降面板 |
| 222 | 埋牌操作条 |
| 223 | 出牌操作条 |
| 224 | 倒计时(三位置) |
| 230 | 桌面浮层(气泡 / 飘字 / 报无主 / 甩错) |
| 240 | 小局结算 |
| 241 | 大局总结算 |
| 242 | 出牌历史 |
| 243 | 明牌面板 |
| 244 | 冲关牌型叠加层(§5.6a) |
| 250 | 建房规则选项 |
2026-08-27 修订 · 群组 206 改名:原名「亮牌信息条 /
LIANGPAI_BAR」,实为 §2.5 的自己的主牌统计条(手牌上方x对 x主,本地统计、有手牌时常显),与 design §8.2 的「亮牌」(庄家埋牌后向两个闲家亮出自己全部固定主牌的具体牌面,走遮罩面板、群组 242)同名异实——§0.0 已专门花一节区分「亮牌 / 余主公示 / 明牌 / 开底」四类公开信息,名字撞车极易把渲染写到错误的界面上。 故统一改名为主牌统计条:群组ZHU_STAT_BAR、精灵ZHU_STAT_BG/ZHU_STAT_TEXT、布局节点ZHU_STAT_BG、图片资源BAR_ZHU_STAT(605,ID 不变)。 「亮牌」一词自此只指 design §8.2 的那件事(协议字段liangpai、群组 242、EQW_Anim.LIANGPAI_AUTO_CLOSE),不再指本条。
精灵(Sprite,1001–2999)
| 号段 | 用途 | 预估用量 |
|---|---|---|
| 1001–1099 | 顶部信息条 + 主牌统计条 + 底栏(局数、功能钮) | ~30 |
| 1100–1199 | 三家玩家位附加标记 + 三处倒计时 | ~24 |
| 1200–1249 | 自己手牌 36 张 + 牌上标记 | ~45 |
| 1250–1299 | 底牌 8 张 + 埋牌底牌 8 张 | 16 |
| 1300–1399 | 自己已出牌区(28 张 + 牌型标签) | ~30 |
| 1400–1499 | 左上家已出牌区(28 张 + 牌型标签) | ~30 |
| 1500–1599 | 右上家已出牌区(28 张 + 牌型标签) | ~30 |
| 1600–1649 | 叫分面板 | ~46 |
| 1650–1699 | 选主 / 投降面板 | ~21 |
| 1700–1749 | 埋牌 / 出牌操作条 | ~8 |
| 1750–1799 | 桌面浮层(气泡 / 飘字 / 报无主 / 甩错) | ~15 |
| 1800–1819 | 小局结算面板 | ~20 |
| 1820–1829 | 冲关牌型叠加层(精灵复制:遮罩 1 + 容器 3 + 模板 1 + 奖数 3) | 8 |
| 1900–1949 | 大局总结算 / 解散结算 | 待设计 |
| 1950–1999 | 出牌历史面板 | 待设计 |
| 2000–2049 | 明牌面板 | 待设计 |
| 2050–2099 | 建房规则选项(3 类别标题 + 8 选项 × 2 + 房卡附注) | 20 |
| 2100–2999 | 预留 | —— |
图片资源(Image,≥501)
| 号段 | 用途 |
|---|---|
| 501–510 | 牌面(3 套尺寸,见 §0.4) |
| 511–530 | 花色图标(小 / 大两种尺寸) |
| 531–570 | 按钮类 |
| 571–600 | 标记类(庄印章、角标底、牌型标签、选中标记等) |
| 601–630 | 面板底图 / 光晕 |
| 631–650 | 数字与符号图 |
| 651–680 | 提示气泡 / 报无主 / 甩错 |
| 681–700 | 建房选项控件 |
| 701+ | 预留 |
声音(Voice,≥101)
见 §4,整节标【待确认】。
0.4 牌面资源与 cardId → 帧号映射(唯一权威转换)
帧排列(通用规范,跨游戏统一)
牌面资源统一按 10 列 × 6 行 = 60 帧排版,行优先编号:
| 帧 | 内容 |
|---|---|
| 1–13 | 黑桃 A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K |
| 14–26 | 红桃 A – K |
| 27–39 | 梅花 A – K |
| 40–52 | 方块 A – K |
| 53 | 小王 |
| 54 | 大王 |
| 55–60 | 牌背 1 – 6(预留多套牌背,二七王使用帧 55) |
二七王规则去掉了 3 和 4(design §2),因此不引用帧 3, 4, 16, 17, 29, 30, 42, 43;但资源仍按 60 帧通用排版照常出图,不留空、不重排——这套排版是所有牌类游戏共用的。
cardId → 帧号(前端只此一处实现)
服务端牌 id 的编码(server/games/erqiwang/class.paiju.js:57):
id = (deck - 1) * 54 + (flower - 1) * 13 + (number - 1) // deck 1..2, flower 1..4, number 1..13(1=A)
小王 id = (deck - 1) * 54 + 52
大王 id = (deck - 1) * 54 + 53
服务端 flower 编号是 1 = 方块、2 = 梅花、3 = 红心、4 = 黑桃(class.pai.js:16、协议 §6),因此 id 的花色段序为 方块 → 梅花 → 红心 → 黑桃,与美术帧的花色顺序(黑桃 → 红桃 → 梅花 → 方块)正好相反。点数在段内是一致的(都 A → K)。转换必须把花色段反过来数:
// 唯一权威转换:cardId → 牌面资源帧号。全前端只此一处实现,其余模块调用它。
function cardIdToFrame(cardId) {
var n = cardId % 54; // 去掉副数,deck1 / deck2 共用同一帧
if (n === 52) { return 53; } // 小王
if (n === 53) { return 54; } // 大王
return (3 - Math.floor(n / 13)) * 13 + (n % 13) + 1;
}
var CARD_BACK_FRAME = 55; // 牌背(二七王固定用牌背 1)
校验样例(建资源后必须逐条对上):
| cardId (deck1) | 牌 | n = id % 54 |
期望帧 |
|---|---|---|---|
| 0 | 方块 A | 0 | 40 |
| 4 | 方块 5 | 4 | 44 |
| 12 | 方块 K | 12 | 52 |
| 13 | 梅花 A | 13 | 27 |
| 26 | 红桃 A | 26 | 14 |
| 39 | 黑桃 A | 39 | 1 |
| 51 | 黑桃 K | 51 | 13 |
| 52 | 小王 | 52 | 53 |
| 53 | 大王 | 53 | 54 |
| 106 | 小王(deck2) | 52 | 53 |
deck1 与 deck2 的同一张牌共用同一帧(牌面完全相同)。区分两副牌靠
cardId本身,不靠帧。
三套尺寸
按 client 02 §2「不同显示区域尺寸不同,各自用一个独立资源 ID」的要求,开 3 套:
| 资源 ID | 键名 | 用途 | 单帧尺寸 | 整图尺寸 (10×6) |
|---|---|---|---|---|
| 501 | CARD_FACE_L |
自己手牌、底牌区 | 110 × 190 | 1100 × 1140 |
| 502 | CARD_FACE_M |
三家已出牌区 | 90 × 155 | 900 × 930 |
| 503 | CARD_FACE_S |
结算埋牌底牌区 | 50 × 70 | 500 × 420 |
单帧尺寸为参考图实测估值(§6),出图前请与最终设计稿核对。三套的帧排列完全一致,只有尺寸不同,
cardIdToFrame对三套通用。
0.5 标注约定
| 标记 | 含义 |
|---|---|
| 【图】 | 该界面/元素在 ./uiref/ 有参考图,规格按图写 |
| 【待设计】 | 流程/协议要求存在,但尚无设计稿,本文只列出「必须有什么」,具体视觉待美术出稿后补 |
| 【待确认】 | 规格本身尚未定论,需与规则设计者/美术确认,编号见 §7 |
怎么读参考图(重要)
参考图是界面设计示意,只看版式、位置、样式,不看数值与状态组合:
| 图上的东西 | 是否可信 |
|---|---|
| 元素的位置、尺寸、层级、配色、字体样式 | ✅ 按图做 |
| 元素长什么样(按钮形态、角标形状、牌面排布方式) | ✅ 按图做 |
| 具体数值(分数、张数、倍数、局数、ID…) | ❌ 一律是填充用的假数据,不要据此反推规则或校验自洽性 |
| 同时出现的互斥元素 | ❌ 是为了在一张图里把各种情况都标出来。典型:多个玩家位同时挂庄标——那是在告诉你「庄标在每个位置分别摆哪儿」,不是真会同时出现三个庄 |
| 同一张图里跨阶段并置的状态 | ❌ 同上,属于叠画示意 |
| 底栏右侧那排功能按钮 | ❌ 只是示意,不代表该阶段的实际显隐;显隐规则以 §2.6 为准 |
所以:发现图上数值算不通、或两个不该同时出现的东西同时出现,不要当成待确认项——那是示意画法。真正需要确认的是「规则本身没定」的地方。
1. 按阶段的界面清单
本节按 design §12.3 的阶段顺序走,每节说明该阶段收哪些包、渲染什么、哪些 UI 显隐。资源与精灵的完整表在 §3 / §5,本节只引用不重复。
建房(§1.1) → 发牌(§1.2) → 叫分坐庄(§1.3) → 看底牌·上庄(§1.4) → 选主/投降(§1.5) → 埋牌(§1.6)
→ 出牌对局(§1.7) → 末轮扣底 + 小局结算(§1.8) → 大局结算(§1.9) → 解散(§1.10) → 重连(§1.11)
1.1 建房 / 房间设置 【图:创建房间选项的UI参考内容根据实际二七王游戏改动.png(样式范式,非内容)】
平台提供界面骨架 + 确认按钮(精灵 25);子游戏提供规则选项区。
⚠️ 参考图是另一个游戏的建房选项(局数 8/16/24、人数 2/3/4、霸王 ×2/×4 等,二七王都没有)。 如文件名所示:只照搬视觉范式与控件样式,内容一律按二七王的
roomtype重写。
结构模型:类别标题 + 选项组
界面由类别纵向堆叠而成,每个类别是「类别标题 + 若干选项组」:
[类别标题] 选项组1 选项组2 …
牌局 ◉6局 ◯12局 ◉房主扣卡 ◯AA每人 【2张】
模式 ◉可查牌 ◯不查牌
规则 ▣傍王 ▣爬坡
选项组有三种类型(这是通用控件规格,不只为二七王):
| 类型 | 语义 | 用的选择框图 |
|---|---|---|
| 单选 | 组内必选其一,互斥 | 单选(圆钮) |
| 多选 | 组内各项独立开关,可全不选、可全选 | 复选(方框) |
| 单选(可不选) | 组内至多选一,也可一个都不选 | 复选(方框)——因为它需要能表达「全不选」,视觉上不适合用单选圆钮 |
每个选项 = 选择框(图片精灵)+ 文字精灵,两者成对出现。
选择框图片资源为 2 × 2 = 4 帧:
| 帧 | 内容 |
|---|---|
| 1 | 单选 · 未选中 |
| 2 | 单选 · 已选中 |
| 3 | 复选 · 未选中 |
| 4 | 复选 · 已选中 |
帧号计算:frame = (useCheckbox ? 3 : 1) + (selected ? 1 : 0),其中 useCheckbox = (类型 === 多选 || 类型 === 单选可不选)。
类别标题放在一张图上多帧,一个标题一帧:
| 帧 | 内容 |
|---|---|
| 1 | 牌局 |
| 2 | 模式 |
| 3 | 规则 |
其余视觉细节照搬参考图:标题青绿粗体、选中项文字变橙、灰色小字附注(参考图的 【3张/人】,二七王用来显示房卡消耗)、选项多时可折行。
内容(二七王实际,对应 roomtype 5 位,协议 §0.5)
| 类别(帧) | 选项组 | 类型 | 选项 | roomtype 位 |
design |
|---|---|---|---|---|---|
| 牌局(帧1) | 局数 | 单选 | 6 局 / 12 局 | 位 0 | §10.1 |
| 牌局(帧1) | 扣卡 | 单选 | 房主扣卡 / AA 每人扣卡 + 附注房卡数 | 位 1 | §10.1 |
| 模式(帧2) | 查牌 | 单选 | 可查牌 / 不查牌 | 位 4 | §9 / §10.2 |
| 规则(帧3) | 附加规则 | 多选 | 傍王、爬坡(可同时勾选,互不冲突) | 位 2、位 3 | §8.3 / §7.3 / §10.3 |
(加粗为缺省值,即 roomtype = "00000"。三个类别正好对应 design §10.1 / §10.2 / §10.3 三个小节。)
二七王当前用不到「单选(可不选)」——四个选项组里三个是单选、一个是多选。该类型仍须在控件层实现,供后续玩法与模板克隆使用。
没有「人数」行——二七王固定 3 人(design §2),不给玩家选。参考图里的「人数」「霸王」两行不要照抄。
房卡消耗联动(协议 §0.5,随「局数 + 扣卡」两行实时变化):
| 扣卡方式 | 6 局 | 12 局 |
|---|---|---|
| 房主扣卡 | 房主 2 张 | 房主 4 张 |
| AA 每人扣卡 | 每人 1 张 | 每人 2 张 |
职责边界(D-1 已定)
子游戏只管「类别标签 + 选项」这一块内容区。弹窗背景、标题、关闭按钮、确认按钮都由平台提供——所以 §5.8 只列内容区的精灵,不要重复建弹窗外壳。
实现要点
- 交互:点击平台约定的 25 号精灵 → 拼
roomtype串 →Net.Send_create_room({agentid, playerid, gameid, roomtype})。 - 精灵:群组 250,号段 2050–2099,预置 20 个(见 §5.8);挂在平台创建房间界面所在图层(T-3)。
- 资源:选择框(4 帧)、类别标题(3 帧)。
- 整个界面由一份「类别 → 选项组 → 选项」的配置数据驱动渲染,不为每个选项写死代码。加一个选项 = 配置里加一条,不改渲染逻辑(工程总则 §5 OCP、§6 配置优先)。
roomtype的拼串必须只在一处实现——与服务端class.config.jsparse()对称的 SSOT 要求,不得在多处按下标硬拼。每个选项在配置里自带bit与value,拼串就是遍历配置,无需按下标硬编码。- 房卡数不要硬编码在 UI 代码里,做成「局数 × 扣卡方式 → 房卡数」的配置表(工程总则 §6)。
配置数据形态(示意,落地位置见 §6.10):
EQW_RoomOptions = {
categories: [
{ titleFrame: 1, /* 牌局 */ groups: [
{ key: 'aset', type: 'radio', bit: 0,
items: [ {label:'6局', value:'0'}, {label:'12局', value:'1'} ] },
{ key: 'card', type: 'radio', bit: 1, note: 'cardCost',
items: [ {label:'房主扣卡', value:'0'}, {label:'AA每人扣卡', value:'1'} ] }
]},
{ titleFrame: 2, /* 模式 */ groups: [
{ key: 'peek', type: 'radio', bit: 4,
items: [ {label:'可查牌', value:'0'}, {label:'不查牌', value:'1'} ] }
]},
{ titleFrame: 3, /* 规则 */ groups: [
{ key: 'rules', type: 'checkbox',
items: [ {label:'傍王', bit:2}, {label:'爬坡', bit:3} ] } // 多选:bit 落在每一项上
]}
]
};
type取'radio'/'checkbox'/'radioOptional'(单选可不选)。选择框帧号由type推出,见上文公式——渲染代码不认识「傍王」「爬坡」这些具体玩法,只认识三种控件类型,这样框架侧保持游戏中立、子游戏只提供配置。
1.2 发牌 fapai 【图:等待叫分.png】
收包字段:asetidx(当前局数)、asetcount(总局数)、cards(自己 28 张)、seat(当前等待叫分者)、countdown。
渲染:
| 要做的事 | 涉及 UI |
|---|---|
底栏局数显示 1/4 局 |
§2.6 底栏 · 局数文字 |
| 自己手牌 28 张,按主牌顺序排序后铺开 | §2.7 手牌区(群组 210) |
| 桌面中央 8 张底牌背面 | 底牌区(群组 211,帧 = 牌背 55) |
| 顶部信息条清零:主 = 无、叫分 = 0、抓分 = 0 | §2.1 顶部信息条 |
三家玩家位状态文字清空,主N/对N 角标隐藏 |
§2.2 玩家位附加标记 |
倒计时显示在 seat 对应的位置 |
§2.4 倒计时 |
- 发牌动画(需要做):从右往左铺开。须遵守 client 02 §3「数据优先、表现延后」——先
setHandCards()把 28 张写进this.data,再播铺开动画;动画的开始/结束/出错回调里只刷界面、不写核心数据。动画缺失或卡住时,数据与界面仍须正确。动画时长、每张延迟进配置(§6.7)。 - 排序:手牌排序规则(主牌在左还是在右、副牌花色顺序)由前端自行决定,但选主前后主牌集合会变,选主后必须重排。见 §7 T-5。
1.3 叫分坐庄 jiaofen 【图:等待叫分.png / 自己叫分.png / 自己已经叫分轮到下家叫分.png】
收包字段:seat(叫分者)、call(0 = 不叫)、currcall(当前叫到的分)、multiple(该叫分对应基础子数)、nextseat、countdown。
三种界面状态:
| 状态 | 参考图 | 表现 |
|---|---|---|
| 等待他家叫分 | 等待叫分.png |
中央保持 8 张底牌背面;倒计时数字显示在当前叫分者的位置旁;已叫分的玩家位显示金色 60分 大字,未叫的为空 |
| 轮到自己叫分 | 自己叫分.png |
中央弹出叫分面板(14 档按钮,两行 × 7)+ 不叫 按钮;顶部一条提示 70分坐庄才可投降;倒计时移到自己操作区 |
| 自己已叫、轮到下家 | 自己已经叫分轮到下家叫分.png |
叫分面板收起,中央显示自己刚叫的 50分 金色大字;已表态的玩家位显示 不叫 白色大字 |
叫分面板规格(群组 220,号段 1600–1649):
- 14 档:
70 65 60 55 50 45 40 35 30 25 20 15 10 5,两行 × 7(行1 = 70…40,行2 = 35…5)。 - 每档 3 个精灵:按钮底(含角标底,同一张图)+ 分数数字精灵 + 角标子数文字精灵。
- 角标显示该档的
multiple,随房间「爬坡」开关取值(协议 §3):- 常规算子:65→2、60→3、55→4、50 及以下统一 →6、70→2
- 爬坡:65→2、60→3、55→4、50→6、45→7、40→8、35→9、30→10、25→11、20→12、15→13、10→14、5→15、70→2
按钮配色:按档位位置固定,不随状态或数据变 【图:叫分按钮面板.png】
| 位置 | 档位 | 按钮底 | 角标底 |
|---|---|---|---|
| 1–4 | 70 / 65 / 60 / 55 | 浅黄 | 蓝 |
| 5–7 | 50 / 45 / 40 | 金黄 | 绿 |
| 8–14 | 35 / 30 / 25 / 20 / 15 / 10 / 5 | 橙 | 深橙 |
⚠️ 参考图里角标写的
1子/2子/4子是填充假数据(§0.5),恰好与三组配色一一对应,不要据此以为「颜色随子数变」——颜色按档位位置写死,角标数值才随爬坡开关变。叫分越低(承诺越苛刻、子数越高)颜色越热。反证:常规算子下 50/45/40 与 35…5 的
multiple同为 6 子,但参考图里它们是两种颜色。
灰色 = 已经叫过的分数(不可再叫)。颜色只因「不可叫」变灰,不随子数档位变化。
按钮底与右上角角标(不含文字)画在同一张图上,即一个精灵一帧就同时包含按钮底色和角标底色。共 4 帧:
| 帧 | 内容 |
|---|---|
| 1 | 浅黄按钮底 + 蓝角标底(高分档 70/65/60/55) |
| 2 | 金黄按钮底 + 绿角标底(中分档 50/45/40) |
| 3 | 橙按钮底 + 深橙角标底(低分档 35…5) |
| 4 | 灰按钮底 + 灰角标底(已叫过 / 不可选) |
两种数字,两种精灵:
| 元素 | 精灵类型 | 说明 |
|---|---|---|
| 叫分的分数(70/65/…/5) | 多帧图数字精灵(资源 NUM_CALL_SCORE,SpriteManager.setNumberImage) |
带描边、需与图一致的美术字;一个精灵显示整串(两位数不拆精灵) |
角标的子数(2子/7子…) |
文字精灵(SpriteManager.setText) |
随爬坡开关动态变,值域 2–15,用文字精灵最省 |
故每档 3 个精灵:按钮底(含角标底)+ 分数数字精灵 + 角标文字精灵。
2026-08-26 补充(档位分数的实现方式,务必照做):14 档里 13 档是两位数(70…10),而每档只有一个分数精灵——这是对的,不要拆成十位/个位两个精灵。 显示走平台既有接口
SpriteManager.setNumberImage(spriteId, '70', charWidth):整串文本交给一个多帧图片精灵,引擎按字符逐帧渲染,精灵宽度按字符数 ×charWidth自动调整。 不要用setFrame逐位切——setFrame是"整个精灵显示第 N 帧",一次只能显示一位,用它做多位数必然要拆精灵。 资源NUM_CALL_SCORE须按 §3.6 的 16 帧固定帧序出图;charWidth取EQW_Layout.NUM_STYLE.CALL_SCORE.charWidth(§6.8,业务代码不写裸值)。
- 可选性规则(design §4.2,由服务端权威
currcall决定,前端只据其置灰、不自行推导规则):- 暂定庄家首叫:5–70 全部可选,无
不叫; - 其后:只有严格低于
currcall的档位可选,不叫可选。
- 暂定庄家首叫:5–70 全部可选,无
- 交互:点击某档 → 发
jiaofen { seat, call };点不叫→ 发jiaofen { seat, call: 0 }。 - 悲观 UI:点击后只发包,面板的收起与状态文字的出现一律等
jiaofen推送包到达再做(前端 05 §6)。唯一允许的乐观处理是按钮本身的防连点禁用。
上方提示条 70分坐庄才可投降:静态文字条,仅在叫分面板展开时显示。
1.4 看底牌 / 上庄 shangzhuang 【部分待设计】
收包字段:seat、call、banker、grade(庄家叫分)、multiple、bottomcards、ancard3s、cards、countdown、touxiang。
| 分支 | 条件 | 表现 |
|---|---|---|
| 常规坐庄 | 无 ancard3s |
庄家收到 bottomcards(8 张)与 cards(36 张)→ 底牌翻正面短暂展示后并入手牌;闲家收不到 bottomcards,底牌区直接收起 |
| 70 分坐庄 | ancard3s === 1 |
全场三家都收到 bottomcards → 8 张底牌翻正面向所有玩家亮 3 秒(design §4/§7.1),3 秒后庄家摸入手牌、闲家侧收起 |
-
开底(D-2 已定):复用「庄家摸底时翻开底牌」那套 UI(见
叫分确定庄.png——中央 8 张牌由背面翻正面),不要倒计时。 两种情形用的是同一套界面,唯一差别是谁能看到:情形 谁能看到这 3 秒 非 70 分坐庄(只有摸底) 只有庄家自己(闲家侧那 8 张保持背面 / 直接收起) 70 分坐庄(开底 → 摸底) 全场三人都能看到 3 秒 因此不需要单独的「公示」面板,只是同一套翻牌表现的可见范围不同——精灵复用 §5.3 群组 211(底牌区),无需新增。
【图:等待庄家选主.png】即闲家视角下的开底:中央 8 张底牌翻正面摊开,下方一条
等待庄家选主状态提示条(见 §2.8)。该图把「开底摊牌」与「等待庄家选主」两个状态画在了一起,属叠画示意(见 §0.5「怎么读参考图」)。实际先后仍按 design §4:开底 3 秒 → 庄家摸底入手 → 选主,摸底后底牌区即收起。
-
上庄后统一更新:顶部信息条
叫分列 =grade、角标 =multiple;banker对应玩家位显示庄印章(含底栏自己位)。 -
三处
庄印章是三个独立精灵(左上 / 右上 / 底栏),按banker显隐其一。 -
重连不重放:协议明确 70 分的 3 秒亮牌是上庄时的一次性事件,
deskinfo重连不重放——前端不得在重连时补播。
1.5 选主 / 投降 xuanzhu · touxiang 【图:亮主.png】
同一决策点、二选一、互斥(design §4.4)。
选主面板规格(群组 221,号段 1650–1699):
2026-08-26 修订(其一):美术侧实际出图方式与原规格不符——花色按钮改为一张图 5 帧(帧1–4=四花色按钮,每帧已含按钮底+花色图标+右上角蓝色角标底;帧5=投降按钮,已含按钮底+「投降」字),花色图标、角标底、投降文字不再单独出精灵。按此改写以下条目,代码同步见
ImageResources.js/Sprites_Action.js/Layout_Action.js。2026-08-26 修订(其二):张数数字用平台既有的
SpriteManager.setNumberImage(§3.6)——一个精灵就能显示整串26张,故每花色一个数字精灵(MAIN_SUIT_COUNT_1..4= 1674–1677);当日早前定的「十位/个位各一个精灵」(8 个)作废,空出的 1678–1681 不复用。
- 标题斜角条:
亮主金色字 + 倒计时数字。 - 4 个花色按钮:每个按钮由一个精灵呈现,帧 = 花色序号 1–4(服务端 flower 编号),该帧已含「按钮底 + 花色图标 + 右上角蓝色角标底」;角标底之上叠加一个对数文字精灵(
N对)。- 按钮下方叠加张数数字精灵:该花色在庄家手中的总张数——两副牌单花色最多 26 张(两位数),用
SpriteManager.setNumberImage(spriteId, '26张', charWidth)在一个精灵上显示整串(无需拆十位/个位),资源见 §3.6 的NUM_MAIN_SUIT_COUNT(第16帧=张)、charWidth见 §6.8 的NUM_STYLE.MAIN_SUIT_COUNT - 右上角标文字 = 该花色的对子数(design §4/§11 明确要求)
- 张数与对子数都由前端据
MyCards/cards自行统计,协议 §「ChooseMain」明确「服务端不额外下发」。
- 按钮下方叠加张数数字精灵:该花色在庄家手中的总张数——两副牌单花色最多 26 张(两位数),用
- 投降按钮:仅
touxiang === 1(即叫分 70)时显示,与 4 个花色按钮并列;按钮为一个精灵(BTN_SUIT_CHOOSE帧5,已含底与「投降」字),不再单独出文字精灵。 - 交互:点花色 →
xuanzhu { seat, flower }(flower:1方块 2梅花 3红心 4黑桃);点投降 →touxiang { seat }。 - 投降的后果:直接跳到结算(§1.8),不选主、不埋牌、不出牌。
收到 xuanzhu 推送后(字段 banker、flower、countdown、cards):
- 顶部信息条
主列显示flower对应的花色图标; - 手牌必须按新的主牌集合重排(正2/正7 升格为主牌,见 design §3);
- 选主面板收起,进入埋牌。
1.6 埋牌 maipai 【图:庄家埋牌.png】
仅庄家,闲家此阶段等待。
界面变化:
-
手牌从单排 36 张改为双排(上排 17 + 下排 19,实测估值)。
-
操作条(群组 222):
提示按钮 + 倒计时 +埋牌 (N/8)按钮,N 为已选张数,N < 8时按钮置灰不可提交。 -
选中的牌上浮表示待埋。
-
牌面上的三种标记(资源
MARK_CARD_GROUP3 帧):拖红色圆标 = 该牌属于一组拖拉机- 橙色五角星 = 正 2 / 正 7(选定花色的 2 和 7,design §3 里大小仅次于双王)
- 蓝色五角星 = 除正2正7外的其他主牌(双王、副2、副7、主花色普通牌)
三种标记互斥、每张牌至多一个;由前端据
flower(主牌花色)在本地标注,不需要服务端下发。
收到 maipai 推送后(字段 cards、bottomcards、seat、countdown、liangpai):
- 庄家手牌回到单排 28 张;
- 闲家若收到
liangpai(仅可查牌模式 + 庄家达标),弹出下方「亮牌」遮罩面板(群组 242,精灵HIST_*,见 §5.7b / §6.9c)——不是 §2.5 那条主牌统计条(原表述「渲染 §2.5 亮牌信息条」是同名异实造成的笔误,2026-08-27 订正); - 进入出牌,
seat= 首出者(必为庄家)。
亮牌(design §8.2,协议 liangpai):
庄家埋牌后、出牌开始前,若手中固定主牌达门槛,就向两个闲家亮出自己全部固定主牌的具体牌面。
| 项 | 说明 |
|---|---|
| 触发门槛(任一) | 固定主牌总数 ≥10 / 王 ≥3 / 7 ≥6 / 2 ≥6 |
| 固定主牌 | 双王 + 全部花色的 2 + 全部花色的 7;不含主花色普通牌 A/K/Q/J/10/9/8/6/5 |
| 亮出内容 | liangpai.cards,已按主牌序排好。固定的一份,不随被哪条门槛触发而增减 |
| 叫分限制 | 无,任何叫分档位都适用 |
| 查牌模式 | 仅可查牌模式下发;不查牌时闲家收不到该字段 |
| 谁能看 | 只有两个闲家收到(庄家自己的牌自己本来就看得见) |
展示形式:与明牌同一套版式(半透黑遮罩 + 一排牌,照 冲关牌型显示.png),只是这里只有一排(庄家的)。可与 §5.7b 的明牌面板复用同一套精灵与渲染,仅数据源不同。
三个遮罩面板的关闭方式各不相同,别写混:
面板 关闭方式 遮罩是否可点 亮牌(本节) 仅自动时长,到点自动收起 ❌ 不注册点击 冲关牌型(§1.8) 点遮罩关闭 ✅ 是关闭热区 明牌 / 出牌历史(§1.7) 点遮罩关闭;明牌另可再点按钮切换 ✅ 是关闭热区
数量前端自己数——协议不再下发 zhu/zhupair/wang/qi/er 等统计,需要显示「x 张王」之类就从 cards 里算。
展示时机(T-34 已定):埋牌后、出牌前——庄家埋牌完成、服务端下发 maipai 包(其中带 liangpai)时弹出,出牌开始前收起。
- 与 design §8.2「庄家埋牌后……出牌开始前」的规则时点一致。
- 这是一次性弹出,不是常驻入口。关闭方式:只按自动时长关闭,不做点击关闭——遮罩不注册点击事件。时长进配置(
liangpaiAutoClose,默认值待定)。 - 只有闲家会收到
liangpai并弹出;庄家自己不弹(自己的牌自己看得见)。 - 不阻塞出牌:面板关闭与否不影响服务端推进,出牌包照常到达;若面板还开着就收到了出牌推送,直接收起面板即可。
1.7 出牌对局 chupai1 / chupai2 / chupai3 【图:出牌.png / 出牌2.png】
这是最复杂的阶段。
出牌操作条(群组 223):倒计时 + 出牌 按钮(选中牌数为 0 时置灰)+ 提示 按钮(出牌阶段必须有)。
自动选中:某些情况下(如跟牌时存在必出牌、或整手只有唯一合法出法),服务端会在下发包里带上应当选中的牌,前端收到后自动把这些牌选中(上浮),玩家确认后点 出牌 即可。
⚠️ 该字段目前协议里没有,需服务端补——见 §7.5 S-2。好消息是服务端已经算过了:
class.arith.js:737get_followcard()返回{ mustcard, cancard, cantype },其中mustcard就是「必出的牌列表」,现在只用于内部校验(class.arith.js:1055)、未下发。补一个下发字段即可,无需新增算法。这条不违反「请求包只带意图」红线——方向是服务端 → 前端的建议选中,前端仍只回传
cards;且合法性最终仍由服务端校验。
自己出牌:点手牌选中(上浮)→ 点 出牌 → 发 chupai { seat, cards }。
cards必须是非空、元素为 0–107 整数、互不重复的数组(协议 §0.2),否则服务端按PARAM拒绝。- 只发意图,不发结论:不回传牌型、不回传「我最大」之类判定。
- 前端可用
shared/做本地预校验与提示,结果不回传。
收 chupai1(首家出牌),字段最丰富:
| 字段 | 渲染用途 |
|---|---|
seat / cards |
在该家已出牌区摆牌(资源 CARD_FACE_M) |
cardtype |
牌型标签(>100 单张 / >200 对子 / >300 拖拉机) |
shuai |
甩牌分量构成 {tractors:[], pairs, singles}——甩牌的真实结构只能读它,不得据 cardtype 反推(协议 §11 明确警告) |
shuaicuo |
甩错标志(= 1):整套甩牌收回,本轮只强制打出最小一张(design §5.4.5)。表现见下方「甩错提示」 |
flower / count |
本轮首出花色与张数,供本地跟牌提示 |
nextseat / countdown |
倒计时移到下一家 |
seatlist |
仅可查牌模式:三家牌况,用于 §2.2 的 主N / 对N 角标 |
baozhu |
是否已有任一玩家报无主:= 1 时触发余主公示(各家主牌数/对数),并让三家的底栏 明牌 按钮可用 |
cardsinhand |
仅出牌者本人有:出牌后剩余手牌,据此重画手牌区 |
收 chupai2 / chupai3:字段类似,chupai3 额外带 maxseat(本轮谁最大)与 grade(本轮闲家得分,仅闲家有得分时才有)。
一轮结束的表现:
maxseat高亮,随后三家出牌区收牌;- 若有
grade,播捡分飘字(+20分金色,参考图出牌2.png中央20分)→ 同时更新顶部信息条抓分列累计值; - 下一轮由
maxseat先出。
牌型标签(参考图 出牌2.png 左下角橙色 拖拉机):需要一套标签资源,至少含 单张 / 对子 / 拖拉机 / 甩牌 / 毙 / 垫【待确认 T-11:标签种类以美术稿为准;「毙/垫/混合出牌」是否也要标】。
闲家提示 tishi 【图:自己是闲家时,底下的踩有分没分按钮.png】(design §11):
-
闲家在出牌阶段可向对家(另一闲家)发三种提示:
1 = 踩(我能大过庄家)、2 = 没分、3 = 有分。 -
发送方收不到成功回执(协议 §13.7),只有失败才回包。
-
接收方(对家)收到
tishi { seat, tip }→ 在发送者的玩家位弹出气泡。 -
庄家无对家,不提供此功能。
-
自己发的提示需要本地回显:服务端只把提示转发给对家、不回执给发送者,所以发送者自己的气泡由前端在点击时本地弹出。
这是「悲观 UI」红线的一处受控例外,成立的理由是:提示不含任何对局状态,服务端明确「不校验提示真实性」(协议 §13.7、design §11),它既不改阶段、不改控制权、不改分数,纯属玩家间的主观喊话。因此本地回显不会造成与服务端状态不一致。仍须遵守:失败回包(
RULE/STEP/PARAM)到达时要把本地回显撤掉。
发起入口:底栏三个按钮 踩 有分 没分,位置就是庄标的位置——自己是闲家时没有 庄 印章,这块区域正好空出来给这三个按钮。
| 自己的身份 | 底栏该区域显示 |
|---|---|
| 庄家 | 庄 印章(1 个精灵) |
| 闲家 | 踩 有分 没分(3 个按钮) |
两者互斥,同一块区域二选一。注意按钮顺序是 踩 → 有分 → 没分,与协议 tip 编号(1踩 / 2没分 / 3有分)不同,映射不要按位置下标推。
气泡资源:3 × 2 = 6 帧。
| 箭头向左 | 箭头向右 | |
|---|---|---|
| 踩 | 帧 1 | 帧 4 |
| 没分 | 帧 2 | 帧 5 |
| 有分 | 帧 3 | 帧 6 |
箭头朝向按头像相对气泡的位置选:头像在气泡左侧 → 用箭头向左的帧;头像在气泡右侧 → 用箭头向右的帧。三个座位的取用见 §6.5。
甩错提示(D-3 已定) 【图:强甩失败.png】:
- 收到
shuaicuo === 1时,用通用状态提示条(§2.8)显示强甩失败,取「即时反馈类」位置预设。 - 不做收回动画——甩出的牌不演"飞回手里",直接按服务端下发的
cards(那张被强制打出的最小主牌单张)落牌即可。 - 提示条自动淡出,时长进配置。
报无主 → 余主公示(D-4 已定):
- 不做全场提示。报无主本身没有独立的提示表现。
- 唯一的界面变化是余主公示生效:他家的
主N/对N角标出现(服务端baozhu=1并整表刷新seatlist,仅可查牌模式)。详见 §2.5。 - 自己的主牌统计条本来就一直显示,不因报无主而变化。
明牌(design §9.3):
- 按钮显示条件(D-6 已定,按 design 手册):可查牌模式 + 出牌阶段 + 已有任一玩家报无主(
baozhu == 1)→ 三家都显示明牌按钮,且可随时查看、不限次数。判定的是「场上有人报无主」,不是「自己报无主」——报无主的那位自己也能看。与 design §9.3「一旦有玩家的主牌全部打空……为全体三人(含刚刚报无主的这位玩家自己)显示……同时界面上会出现一个『明牌』按钮」一致,也与服务端
mingpai的受理条件have_baofu()一致。 - 点击 → 发
mingpai { seat }→ 收mingpai { seat, others: [{seat, zhucards}] }→ 弹出面板展示另两家全部未出主牌的具体牌面。 - 再点一次取消是纯前端开关,不再请求服务端(协议 §13.6)。
- 展示形式(D-6 已定):照
冲关牌型显示.png那一套——半透黑遮罩 + 两家各一排牌(CARD_FACE_L、fan重叠排列),点遮罩关闭。与冲关牌型叠加层是同一种版式,可复用同一套渲染逻辑,仅数据源与座位数不同(明牌是另两家,冲关牌型是三家)。 - 面板:图层 305,群组 243;牌用精灵复制(张数不定,同 §5.6a 的判据)。
出牌历史(design §9.1):
- 仅可查牌模式;底栏
出牌历史/上一轮两个按钮(§2.6)。 - 数据来自重连包
pushlist(按轮次 × 3 家),出牌过程中前端需自行累积(chupai1/2/3逐包记录)。 - 展示形式(D-7 已定):不按轮次分组。把每家出过的牌全部摊平聚合到该玩家名下,再按手牌那套主牌序排序(同 §7.2 T-5 的
order_cards顺序),三家各显示一排——版式照冲关牌型显示.png(遮罩 + 三家各一排牌)。前端自行摊平 + 排序即可,不需要改服务端:
pushlist已含全部轮次数据,且各轮内部已按本局主牌花色排好。 上一轮按钮则只取最近一轮的三家出牌(pushlist末尾一项),版式同上。- 面板:图层 304,群组 242;牌用精灵复制(张数不定)。
- 不可查牌模式下这两个按钮整体不出现(design §9)。
失败回包(协议 §0.2):任何请求被拒都会回同名 rpc 的 { success: false, errcode }。前端一律 if (!data.success) 判断,据 errcode 提示:
| errcode | 含义 | 建议提示 |
|---|---|---|
| 1 PLAYER | 玩家/房间/座位校验不过 | 「身份校验失败」 |
| 2 NODESK | 牌桌或牌局不存在 | 「牌局不存在」 |
| 3 STEP | 当前阶段不允许 | 「当前阶段不能这样操作」 |
| 4 SEAT | 位置不符 / 还没轮到 | 「还没轮到你」 |
| 5 PARAM | 参数非法 | 「出牌数据有误」 |
| 6 RULE | 规则不允许 | 「这样出不符合规则」 |
复用框架 UIManager.showMessage,无需专门资源。
1.8 末轮扣底 + 小局结算 jiesuan 【图:小局结算.png】
结算包三种来源(协议 §14):正常出牌结算(chupai + bottom + aset)、投降结算(只 aset)、解散结算(见 §1.10,投递方式完全不同)。
扣底表现(bottom 分组,design §6.3):
cards(8 张埋牌底牌)恒有 → 埋牌底牌区(群组 215,资源CARD_FACE_S)翻开展示,design §11 明确「牌局结束需要亮出底牌」;multiple/grade1/grade2仅闲家扣底时才有 → 展示底牌 20 × 4之类的翻倍算式。- 文案格式:
叫分{aset.multiple}子 底牌 {bottom.grade1}x{bottom.multiple}——x后面是扣底倍数(design §6.3:单张 ×1、主对 ×2、N 连对 ×2N)。参考图底牌 20x0即底牌有 20 分、扣底倍数 0(本局闲家未扣底)。 - 闲家未扣底时
bottom只有cards,multiple/grade1/grade2都不下发 → 倍数位显示 0。
三家结算数字(aset.seatlist,每家两行):
| 行 | 内容 | 字段 | 样式 |
|---|---|---|---|
| 大字 | 本局总分 | grade |
+20 橙色(赢)/ -10 蓝色(输),底带光晕 |
| 小字左 | 牌局分 N |
grade_jf(捡分子数得分) |
白标签 + 数值 |
| 小字右 | 冲关分 N |
grade_cg(算奖得分里的冲关分量,S-6 新增;开傍王时不含傍王那部分) |
白标签 + 数值 |
两个标签的文案已由更新后的
小局结算.png确定(原图两个都写「牌局分」是 mock 重复,现已修正为牌局分/冲关分)。
两个按钮:
| 按钮 | 位置 | 作用 |
|---|---|---|
冲关牌型(蓝色) |
中央偏左 | 打开冲关牌型叠加层(见下) |
下一局(金黄) |
中央偏右 | 发 zhunbei { seat } 进入下一局(§1.12) |
「冲关」是什么(chongguan 字段的准确定义)
服务端 class.arith.js:1277 get_chongguan(mainflower, cards)。chongguan 即 design §8.1 冲关的奖数(该规则旧称「常规算奖」,现统一叫冲关)。函数返回三项:
| 返回字段 | 含义 | 去向 |
|---|---|---|
count |
关数 = 冲关奖数 | aset.seatlist[i].chongguan |
wang |
手牌中的王数 | aset.seatlist[i].wang(傍王按此计奖) |
cards |
王牌 + 所有参与冲关的牌,已按主牌序从大到小排好 | aset.seatlist[i].cards → 冲关牌型叠加层要显示的就是它 |
计数规则(与 design §8.1 逐条对应):
- 前置:
cards.length < 28直接返回 0 —— 手牌不足 28 张不参与冲关。 - 三王 / 四王:≥3 王 →
count = 1;= 4 王 →count = 3。 - 连对链续奖:必须先满足 ≥3 王(整段逻辑在
if (_wlist.length >= 3)内)。从小王编码9553起,沿主牌序往下逐对扫描,每遇到一个与上一节位置相邻的对子就count + 1,链条为正7 → 副7 → 正2 → 副2 → 主A → 主K → …,断则止。没有三王就没有连对链奖。 - 六/七/八个 7:
count += 张数 − 5(6→1、7→2、8→3 奖)。 - 六/七/八个 2:同上。
- 固定主牌 ≥10 张不产生冲关奖——它只触发 design §8.2 的「亮牌」,代码里有明确注释。§1.6 的亮牌与这里的冲关是两回事。
前端不重算冲关,
chongguan/wang/naward/cards一律直接取服务端下发值(服务端权威,红线)。上面的规则只用于理解要显示什么。
冲关牌型叠加层 【图:冲关牌型显示.png】:
点 冲关牌型 后,在结算面板之上盖一层半透黑遮罩,三家各展示自己的 aset.seatlist[i].cards,资源用 CARD_FACE_L、重叠排列。下一局 按钮在遮罩层上继续可见可点,冲关牌型 按钮本身被遮住。
关闭方式:整块全屏半透明黑遮罩本身就是关闭热区,点击遮罩即关闭。 不另设关闭按钮。因此 CG_MASK 必须注册点击事件,且 下一局 的层级要高于它、点它不被遮罩吃掉。
- 三家牌位:左上家、右上家在各自头像内侧;自己在中央偏下。
- 布局配置见 §6.7。
牌用精灵复制生成,不预置固定数量(见 §5.6a):cards 的张数没有小上限——四王 + 一条长连对链 + 八个 7 + 八个 2 叠加时可达 20 余张。预置精灵既会不够用,又在绝大多数局里白占 ID。
aset 其余字段的用途:
| 字段 | 用途 |
|---|---|
banker / call / flower |
顶部信息条最终态 |
multiple |
基础子数 |
grade |
闲家最终捡分(含扣底)→ 顶部 抓分 列 |
upgrade |
判定倍率(带符号):3 大光 / 2 小光 / 1 过庄 / -N 升 N 级(倒庄)/ -99 投降 / 0 解散。结算面板不显示判定文字——判定结果由动画呈现,见 §1.8「判定结果动画」 |
bangwang / climb |
本局规则开关,用于结算面板上标注 |
cards |
冲关牌型叠加层的牌(见上) |
chongguan / wang / naward |
冲关奖数 / 王数 / 总奖数。叠加层需要并列显示奖数——以 naward(该家总奖数 N,8.4 节的支付基数)为主;chongguan / wang 作为明细可选展示 |
判定结果动画(D-8)
结算面板上不做判定文字。大光 / 小光 / 过庄 / 升N级 / 投降这几个判定,由动画在两个时机呈现:
| 时机 | 数据来源 | 说明 |
|---|---|---|
| 对局过程中 | curmultiple(随 chupai1/2/3 下发,S-1) |
捡分变化导致判定档位跳变时提示,例如从「大光」掉到「小光」、或闲家捡够分数「过庄→升级」 |
| 结算前 | aset.upgrade(结算包,带符号) |
末轮打完、结算面板出现之前播一次最终判定 |
动画播放遵守「数据优先、表现延后」(client 02 §3):先 setXxx 把结算数据写进 this.data,再播动画;动画的开始/结束/出错回调里只刷界面、不写核心数据。动画缺失或卡住时,结算面板与数据仍须正确。
curmultiple是带符号的(S-8 已改):3/2/1= 庄家大光/小光/过庄,-N= 闲家升 N 级,0= 叫分未定。判定动画按符号 + 绝对值两维映射即可,与结算包aset.upgrade同一套逻辑。
投降结算:只有 aset,无 chupai、无 bottom → 结算面板必须容忍底牌区缺失,不能因为读不到 bottom.cards 就崩或显示空框。
1.9 大局总结算 account 【图:大局结算.png】
- 仅当打到最后一局(
idx >= asetcount)时,jiesuan包才带account分组。 - 界面:图层 303,群组 241。三条玩家栏用精灵复制生成(见 §5.7a)。
版式(弹窗面板,圆角):
| 区 | 内容 |
|---|---|
| 标题栏(青绿底) | 二七王-3人 房号{roomcode} 共{asetcount}局 {开战时间} + 右上角关闭钮 |
| 玩家栏 ×3(按名次排序,行间分隔线) | 名次徽章 → 头像 → 昵称 / ID:{playerid}(两行)→ 基础分{n} / 总得分{n}(两行)→ 冲关分{n} → 傍王分{n} → 右侧大字总分 |
| 规则栏(浅绿底) | 规则:可查牌、傍王、爬坡算子 —— 据 roomtype 位串拼出已启用项 |
| 面板外底部 | 再来一局(黄) 分享好友(蓝) 复制战绩(蓝) 退出房间(红) |
- 名次徽章:3 帧(1 金 / 2 橙 / 3 蓝,花瓣形),按总分排名取帧。
- 总分大字:正分橙色带
+、负分蓝色带-,复用 §3.6 的NUM_RESULT_WIN/NUM_RESULT_LOSE。
四项分数已由 S-6 补齐:
account改为对象数组,含grade_jf_total(基础分)/grade_cg_total(冲关分)/grade_bw_total(傍王分)/score(总分),三项之和恒等于score。
1.10 解散结算 free_room 【待设计】
投递方式与 §1.8 完全不同(协议 §14.1),前端必须单独处理:
{ app:"youle", route:"room", rpc:"free_room",
data:{ seats:[], deskfree:{ rpc:"jiesuan", data:{ success, aset, account } } } }
- rpc 是平台的
free_room、route 是room,不是erqiwang/jiesuan; - 真实取值路径是
data.deskfree.data.aset与data.deskfree.data.account(多一层data包装); - 外层
data.success由平台填,子游戏的success在data.deskfree.data.success; - 解散局
aset.multiple = 0、upgrade = 0、各家grade = 0,account恒有; data.deskfree可能缺失(开战后、首局发牌前解散时get_disbandRoom返回null)→ 前端必须容忍。
界面复用 §1.9 的大局总结算面板。
解散的申请/投票/同意拒绝界面由平台全包(
Layer 420 CheckFree_Layer+GameUI.openCheck+Desk.self_apply_free_room/other_apply_free_room/self_agree_free_room/self_refuse_free_room/agreefree),子游戏不做投票界面,只处理上面这个结算包。
1.11 断线重连 deskinfo
不新增任何界面。重连的本质是「恢复数据 → 调各 UI 组件 set-refresh 恢复界面」,复用与正常流程完全相同的一条重画路径(前端 04 §3.3 / 05 §6)。
平台把 deskinfo 挂在 pack.data.deskinfo 下,按当前 step 只带对应分组:
step |
分组 | 恢复到 §1.x |
|---|---|---|
| 1 | CallRun(seat / countdown / nowcall / multiple / call[3]) |
§1.3 叫分 |
| 2 | ChooseMain(banker / call / multiple / countdown / bottomcards 仅庄家 / touxiang) |
§1.5 选主 |
| 3 | BuryCards(+ flower) |
§1.6 埋牌 |
| 5 | PushCards(playproc / seatlist / liangpai / pushlist / grade / gradecards / bottomcards 仅庄家) |
§1.7 出牌 |
| 6 | Balance(readystate / aset) |
§1.8 结算 |
另有 count / idx / PlayerInfo[3] / MyCards 全阶段通用。
关键点:
playproc.cards(当前轮桌面上的牌)两种查牌模式下都有 —— 否则后出的人无从跟牌;pushlist(往轮历史)与seatlist仅可查牌模式有 —— 不查牌模式下前端不得渲染出牌历史;- 70 分的 3 秒亮底牌不重放;
- 验收判据(前端 05 §6.2):任意时刻丢弃
this.data、仅凭最近一次服务端快照重画,界面必须完全一致。做不到即「前端私存了状态」或「服务端漏发了字段」,两者都要修。
1.12 准备 zhunbei
小局结算后各家点 下一局 进入下一局(§1.8),发 zhunbei { seat }。收 zhunbei { seat } → 该家玩家位显示「已准备」标记——用平台的准备标识(§0.2),子游戏不另做资源。
2. 常驻 UI
跨阶段常驻的部件,图层 101。
2.1 顶部信息条 【图:全部】
位置 x≈486–762, y≈4–72。三列表格式。
| 列 | 表头 | 数据 | 数据来源 |
|---|---|---|---|
| 1 | 主 |
花色图标 | xuanzhu.flower / aset.flower(1方块 2梅花 3红心 4黑桃);选主前显示占位 |
| 2 | 叫分(绿字) |
分数 + 蓝色角标 | shangzhuang.grade + multiple |
| 3 | 抓分(橙字) |
分数 + 橙色角标 | 分数 = 闲家累计捡分(逐轮 chupai3.grade 累加,结算时以 aset.grade 为准);角标 = Math.abs(curmultiple)(该字段带符号,角标只取大小,见 S-8) |
【待确认 T-16】:抓分 列的角标在 等待叫分.png 里是 1子、在 小局结算.png 里是 1倍,两图不一致。推定为 aset.upgrade 判定倍率(仅结算后有意义),需确认。
- 精灵:群组 201,号段 1001–1029。
- 资源:表格底图、花色小图标(4 帧)、角标底(2 种配色)。
2.2 玩家位附加标记 【图:全部】
平台负责头像/昵称/分数(§0.2),子游戏在其旁叠加:
| 元素 | 数据来源 | 显隐规则 |
|---|---|---|
庄 印章 |
shangzhuang.banker / aset.banker |
三家各一个精灵,按 banker 显隐其一(含底栏自己位) |
主N 角标(黄底黑字) |
seatlist[seat][4][0] 剩余主牌数 |
仅可查牌模式 + 已报无主;初始 [-1,-1] 时隐藏 |
对N 角标(白底黑字) |
seatlist[seat][4][1] 剩余主对数 |
同上 |
| 状态文字区 | 叫分阶段:60分 金色 / 不叫 白色 |
叫分阶段显示,进入选主后清空 |
- 精灵:群组 202(左上)/ 203(右上)/ 204(自己),号段 1100–1149。
2.3 已出牌区 【图:出牌2.png】
三家各一个区域,展示本轮打出的牌(资源 CARD_FACE_M)。
- 自己:中央偏下
- 右上家(下家):右上,头像内侧
- 左上家(上家):与右上家左右镜像——排列方式、牌尺寸、标签位置全部参照右上家,只是 x 方向对称、牌的堆叠朝向相反。已确认无需单独设计稿。
- 每张牌可叠加角标:
庄(橙色斜标)、大(大王圆标)等 - 区域左下角:牌型标签(
拖拉机等,§1.7) - 三家的布局参数走同一份配置的
bySeat三个变体,见 §6.5 - 每家预置 28 个牌精灵(= 单次出牌张数上限,甩牌最多可甩满手牌)。号段每家 100 个,容量充裕,因此不使用动态复制精灵,避免
SpriteCopyUtils的清理负担。 - 精灵:群组 212 / 213 / 214,号段 1300–1599。
2.4 倒计时 【图:多张】
参考图里倒计时数字(12 / 15 / 20)出现在当前操作者的位置旁:
- 轮到左上家 → 左上家头像右侧(x≈195–270, y≈165–235)
- 轮到自己 → 自己操作区左侧(x≈445–520, y≈345–400)
- 轮到右上家 → 对称位置
因此建 3 个倒计时精灵,按当前操作者显隐其一。
- 数据来源:各包的
countdown。 - 只做展示,不触发任何操作(design §11 / 协议 §0.3):倒计时归零后不自动叫分/选主/埋牌/出牌,也不判负、不跳过。前端不得在归零时做任何乐观界面推进(不跳阶段、不清控制权),一切仍等服务端推送。
- 归零后停在
0继续显示,不隐藏:协议 §0.3 明确归零不触发任何动作、牌局原地等待该玩家;隐藏会被误读为「已超时/已跳过」。 - 精灵:群组 224,号段 1150–1159。
- 精灵类型(2026-08-27 订正):3 个倒计时精灵均为多帧图数字精灵(非文字精灵)——玩家视线焦点、视觉权重最高的数字,参考图是带描边/渐变的美术字,文字精灵做不出这个效果。显示走
SpriteManager.setNumberImage,资源NUM_COUNTDOWN(§3.6),纯秒数无后缀。见 §5.4 / §6.8。
2.5 自己的主牌统计 + 余主公示(他家)【图:多张】
这是两套不同的东西,别混为一谈:
| 谁的 | 显示在 | 何时显示 | 数据来源 |
|---|---|---|---|
| 自己的主牌统计 | 手牌上方偏左(x≈35 y≈400 那条) | 有手牌时始终显示,与报无主无关 | 前端据 flower 本地统计自己手牌 |
| 他家的主牌数 / 对数(余主公示) | 左上、右上家头像下方的 主N 对N 角标 |
仅可查牌模式 + 已报无主(design §9) | seatlist[seat][4] = [剩余主牌数, 剩余主对数] |
自己的主牌统计条(群组 206 ZHU_STAT_BAR,精灵 ZHU_STAT_BG / ZHU_STAT_TEXT):
- 文案
x对 x主(暂定,见 §7.2 T-9),例如3对 12主。 - 始终显示、本地计算——自己的手牌自己完全可见,不需要服务端下发,也不受查牌模式与报无主影响。
- 参考图里的
主牌对子: 1对即此条。 - 2026-08-27 改名:本条原名「亮牌条 /
LIANGPAI_*」,与下方「亮牌」同名异实,已统一改为ZHU_STAT_*(详见 §0.3 群组表下的修订说明)。
余主公示:他家的 主N / 对N 角标(群组 202 / 203,结构见 §2.2):
- 一个图片底 + 一个文字精灵,两家各一组。
- 初始
[-1,-1]时隐藏;一旦全场有人报无主,服务端整表刷新seatlist并下发,两家的角标同时出现。 - 不可查牌模式下永不出现。
「亮牌」(
liangpai)与上面两者都不是一回事:它是 design §8.2 的规则——庄家达门槛时向闲家亮出自己全部固定主牌的具体牌面,用遮罩面板展示(§1.6,群组 242,复用HIST_*精灵),不是这里的统计条。 正因两者曾经同名,本条统计条在 2026-08-27 改名为ZHU_STAT_*;代码里凡LIANGPAI字样自此只属于亮牌那一侧(协议字段liangpai、EQW_Anim.LIANGPAI_AUTO_CLOSE)。
2.6 底栏 【图:全部】
y≈648–720 深色条。左侧头像/昵称/分数由平台渲染(§0.2),子游戏负责:
| 元素 | 位置(实测估值) | 显隐规则 |
|---|---|---|
庄 印章 |
x≈338–370 | 自己是庄时显示 |
踩 / 有分 / 没分 按钮 |
x≈335–573(占用同一区域) | 自己是闲家 + 出牌阶段时显示,与 庄 印章互斥(§1.7) |
局数 1/4 局 |
居中 x≈635–700 | 常驻,asetidx / asetcount |
| 右侧功能按钮共 5 个,按情况显隐(不是全部常驻): |
| 按钮 | 看什么 | 显示条件 |
|---|---|---|
上一轮 |
上一轮所有人出的牌 | 可查牌 + 出牌阶段 + 已打过至少一轮 |
出牌历史 |
所有人出过的全部牌 | 可查牌 + 出牌阶段 |
明牌 |
另两家手中全部未出主牌的具体牌面 | 可查牌 + 出牌阶段 + 场上已有人报无主(baozhu==1)→ 三家都显示 |
扣底 |
埋牌底牌:庄家埋下的 8 张 | 仅庄家 + 已埋牌之后 |
底牌(查底牌) |
底牌:发牌时没发给玩家、留在桌面的 8 张 | 庄家全程;闲家仅开底过的局(70 分坐庄)(S-3) |
术语已统一:按钮名 = 术语名
本项目采用修订后的术语(2026-08-25 定,取代 design.md 原表述):
新术语 指哪 8 张 design.md 原称 底牌 发牌时没有发给玩家、留在桌面的 8 张 暗牌埋牌底牌 庄家埋牌时从手里扣下的 8 张 底牌改后底栏按钮名实相符:
底牌按钮看底牌、扣底按钮看埋牌底牌,不再有命名倒挂。协议字段也已拆开(S-4 已完成),前端按字段名取值即可,不必再按所在包判断语义:
按钮 展示 协议字段 底牌底牌(发牌留桌 8 张) bottomcards——shangzhuang(庄家恒有,闲家仅 70 分时有)、ChooseMain/BuryCards(仅庄家)扣底埋牌底牌(庄家埋的 8 张) burycards——maipai、PushCards(仅庄家);结算包为bottom.cards实现要求:前端内部变量仍建议用
bottomCards/buryCards区分,与字段名一一对应。已列入验收清单(§7.3)。
- 精灵:群组 205,号段 1040–1069(5 个功能按钮 × 2 精灵 = 10,
扣底为 1056/1057,2026-08-27 补齐;另有 3 个提示按钮 × 2 精灵)。
2.7 手牌区 【图:全部】
| 形态 | 张数 | 位置(实测估值) |
|---|---|---|
| 单排(叫分 / 出牌) | 最多 36 | y≈455–645,x≈35–1250,重叠排列 |
| 双排(庄家埋牌) | 36(17 + 19) | 上排 y≈285–455,下排 y≈455–645 |
- 建 36 个手牌精灵(庄家摸底牌后的上限),资源
CARD_FACE_L。 - 张数少于 36 时隐藏多余精灵并重算间距。
- 选中态:牌上浮(Y 偏移),另可叠加选中标记。
- 牌上标记(
拖圆标、⭐、🔵)见 T-8。 - 精灵:群组 210,号段 1200–1249。
2.8 状态提示条(通用)【图:等待庄家选主.png / 强甩失败提示.png】
一条深色半透圆角条 + 居中白字,用于显示当前在等谁、或一次性的即时反馈。整个牌局复用同一个精灵,只换文字与位置。
| 用途 | 文案示例 | 位置(实测估值) |
|---|---|---|
| 等待类(常驻到状态结束) | 等待庄家选主、等待庄家埋牌、等待XX叫分 |
桌面中央 x≈500 y≈373 w≈320 h≈47 |
| 即时反馈类(自动淡出) | 强甩失败 |
桌面中央偏上 x≈462 y≈172 w≈363 h≈50 |
- 两类共用一套精灵(
BAR_TOAST+ 文字精灵),位置由布局配置的两个预设切换。 - 文案表进配置,不在代码里写死字符串。
- 精灵:图层 105 群组 230,
1760条底 +1761文字。
文案清单(T-33 已定)
全部 3 条。
| # | 文案 | 类型 | 谁看到 | 显示区间 |
|---|---|---|---|---|
| 1 | 等待庄家选主 |
状态类 | 两个闲家 | 收 shangzhuang 后 → 收 xuanzhu 前(§1.5) |
| 2 | 等待庄家埋牌 |
状态类 | 两个闲家 | 收 xuanzhu 后 → 收 maipai 前(§1.6) |
| 3 | 强甩失败 |
即时反馈 | 全场 | 收到 chupai1.shuaicuo == 1,自动淡出(§1.7) |
前 2 条是「状态类」——常驻到该状态结束、由收包驱动收起;第 3 条是「即时反馈类」——自动淡出。 两类共用同一套精灵(
BAR_TOAST+ 文字),只切位置预设与文案。
明确不做的(已确认):
| 不做 | 理由 |
|---|---|
| 叫分等待 | 倒计时已经指明在等谁——它就显示在当前叫分者的位置旁(§2.4) |
| 出牌等待 | 同上;且一局约 84 次切换,弹条只会吵 |
| 准备等待 | 平台自带已准备 / 未准备标识(§0.2),不重复造 |
| 玩家掉线 / 重连提示 | 平台已覆盖(Layer 615 Reconnect_Layer 等),子游戏不实现 |
| 开底提示 | 画面本身已经说清楚了——闲家看到底牌由背面翻成正面,就是开底;再加一行字是多余的 |
文案表进配置,不在代码里写死字符串。
原 §5.5 的
BAR_SHUAICUO(1754/1759)并入本部件——甩错只是这条通用提示条的一种文案,不必单独出图。
3. 图片资源总表
给美术清点用。按钮一律只出 1 帧普通态——点击的缩放/透明反馈由框架统一处理(client 02 §2)。 尺寸列为参考图实测估值,出图前请与最终设计稿核对。
3.1 牌面(3 套,见 §0.4)
| ID | 键名 | 用途 | 帧数 | 帧说明 | 单帧尺寸 | 整图 |
|---|---|---|---|---|---|---|
| 501 | CARD_FACE_L |
手牌、底牌 | 60 | 见 §0.4 帧表(10×6 通用排版) | 110 × 190 | 1100 × 1140 |
| 502 | CARD_FACE_M |
已出牌区 | 60 | 同上 | 90 × 155 | 900 × 930 |
| 503 | CARD_FACE_S |
结算埋牌底牌区 | 60 | 同上 | 50 × 70 | 500 × 420 |
3.2 花色图标
| ID | 键名 | 用途 | 帧数 | 帧说明 | 尺寸 |
|---|---|---|---|---|---|
| 511 | SUIT_ICON_S |
顶部信息条 主 列 |
4 | 帧1=方块♦ 帧2=梅花♣ 帧3=红心♥ 帧4=黑桃♠(按服务端 flower 编号 1–4 排序) | 30 × 30 |
SUIT_ICON_L |
不需要:选主面板花色图标已并入 BTN_SUIT_CHOOSE 帧1–4(2026-08-26,美术改一张图 5 帧出图) |
—— | —— | —— |
⚠️ 花色图标的帧序按服务端 flower 编号(1方块 2梅花 3红心 4黑桃),与牌面资源的花色顺序不同。两者互不换算,各自独立。
3.3 按钮
| ID | 键名 | 用途 | 帧数 | 帧说明 | 尺寸 |
|---|---|---|---|---|---|
| 531 | BTN_CALL_SCORE |
叫分档位按钮底 + 右上角角标底(同一张图,不含文字) | 4 | 帧1=浅黄+蓝角标(70/65/60/55) 帧2=金黄+绿角标(50/45/40) 帧3=橙+深橙角标(35…5) 帧4=灰(已叫过/不可选)。颜色按档位位置固定,只因不可叫变灰 | 74 × 56 |
| 532 | BTN_NO_CALL |
不叫 |
1 | 蓝色渐变 | 184 × 57 |
| 533 | BTN_SUIT_CHOOSE |
选主 / 投降面板按钮(花色按钮 + 投降按钮,一张图 5 帧) | 5 | 帧1–4=四花色按钮,每帧已含「按钮底 + 花色图标 + 右上角蓝色角标底」,花色序按服务端 flower 编号(帧1=方块♦ 帧2=梅花♣ 帧3=红心♥ 帧4=黑桃♠);帧5=投降按钮,已含「按钮底 + 投降二字」(2026-08-26 修订:原为按钮底单帧,花色图标/角标底/投降文字各自单独出精灵;美术侧实际按一张图 5 帧出图,改按此表) | 128 × 55 |
BTN_SURRENDER |
不需要:投降按钮已并入 BTN_SUIT_CHOOSE 帧5(2026-08-26) |
—— | —— | —— | |
| 535 | BTN_TIP |
提示 |
1 | 蓝色渐变 | 180 × 63 |
| 536 | BTN_BURY |
埋牌 (N/8) |
2 | 帧1=可提交(金黄) 帧2=置灰(未满 8 张) | 180 × 63 |
| 537 | BTN_PLAY |
出牌 |
2 | 帧1=可出 帧2=置灰 | 157 × 55 |
| 538 | BTN_BOTTOM_FUNC |
底栏功能钮底(明牌/已出牌/上一轮/底牌共用) | 1 | 深色圆角 | 88 × 30 |
BTN_READY |
不需要:准备标识用平台的(§0.2) | —— | —— | ||
| 540 | BTN_TISHI |
底栏 踩 / 有分 / 没分 按钮底(三者共用) |
1 | 深色圆角,同 BTN_BOTTOM_FUNC 风格但更窄 |
52 × 30 |
| 541 | BTN_NEXT_ASET |
结算 下一局 |
1 | 金黄渐变 | 180 × 65 |
| 542 | BTN_CG_CARDS |
结算 冲关牌型 |
1 | 蓝色渐变 | 183 × 63 |
| 543 | BTN_ACCOUNT_AGAIN |
大局结算 再来一局 |
1 | 黄色渐变 | 190 × 60 |
| 544 | BTN_ACCOUNT_SHARE |
大局结算 分享好友 |
1 | 蓝色渐变 | 190 × 60 |
| 545 | BTN_ACCOUNT_COPY |
大局结算 复制战绩 |
1 | 蓝色渐变 | 190 × 60 |
| 546 | BTN_ACCOUNT_EXIT |
大局结算 退出房间 |
1 | 红色渐变 | 190 × 60 |
| 547 | BTN_ACC_CLOSE |
大局结算标题栏右上角关闭 | 1 | —— | 36 × 36 |
3.4 标记类
| ID | 键名 | 用途 | 帧数 | 帧说明 | 尺寸 |
|---|---|---|---|---|---|
| 571 | MARK_BANKER |
庄 红色印章 |
1 | —— | 40 × 40 |
| 572 | MARK_BANKER_CORNER |
牌角 庄 橙色斜标 |
1 | —— | 28 × 28 |
| 573 | MARK_JOKER_BIG |
大王 大 圆标 |
2 | 帧1=大王 帧2=小王 | 34 × 34 |
| 574 | BADGE_ZHU_PAIR |
主N / 对N 角标底 |
2 | 帧1=黄底(主) 帧2=白底(对) | 44 × 20 |
| 575 | BADGE_MULTIPLE |
子数/倍数角标底 | 2 | 帧1=蓝底 帧2=橙底 | 34 × 18 |
| 576 | LABEL_CARDTYPE |
牌型标签 | 1 | 只做「毙」一种(前端只展示这一个标签)。数据层仍保留 毙 / 垫 / 混合出牌 三种标识以备扩展,但当前不出图、不显示 | 76 × 24 |
| 577 | MARK_CARD_GROUP |
手牌牌型标记 | 3 | 帧1=拖(拖拉机)帧2=橙色五角星(正2 / 正7)帧3=蓝色五角星(除正2正7外的其他主牌) |
26 × 26 |
| 578 | MARK_SELECTED |
手牌选中标记 | 1 | 待定(也可只用上浮,不出图) | 待定 |
| 579 | BADGE_RANK |
大局结算名次徽章(花瓣形) | 3 | 帧1=第1名(金) 帧2=第2名(橙) 帧3=第3名(蓝) | 44 × 44 |
3.5 面板底图
| ID | 键名 | 用途 | 帧数 | 尺寸 |
|---|---|---|---|---|
| 601 | PANEL_TOP_INFO |
顶部三列信息条底 | 1 | 276 × 68 |
| 602 | PANEL_CALL_SCORE |
叫分面板底 | 1 | 575 × 170 |
| 603 | BAR_HINT_TOP |
70分坐庄才可投降 提示条底 |
1 | 345 × 33 |
| 604 | BAR_CHOOSE_MAIN |
亮主 斜角标题条 |
1 | 425 × 50 |
| 605 | BAR_ZHU_STAT |
主牌统计条底(半透圆角,§2.5;2026-08-27 由 BAR_LIANGPAI 改名,ID 不变) |
1 | 210 × 35 |
| 606 | PANEL_BOTTOM_CARDS |
结算底牌区面板底 | 1 | 420 × 148 |
| 607 | GLOW_RESULT |
结算分数光晕背景 | 2 | 帧1=赢(橙) 帧2=输(蓝) |
| 608 | BAR_FOOTER |
底栏深色条 | 1 | 1280 × 72 |
| 609 | MASK_DIM |
半透黑遮罩(冲关牌型 / 出牌历史 / 明牌 共用) | 1 | 1280 × 720(纯色可拉伸,出 1 张小图即可) |
| 610 | PANEL_ACCOUNT |
大局总结算面板底(圆角浅灰绿) | 1 | 1100 × 540 |
| 611 | BAR_ACCOUNT_TITLE |
大局结算标题栏(青绿底,含圆角上沿) | 1 | 1100 × 56 |
| 612 | BAR_ACCOUNT_RULE |
大局结算底部规则栏(浅绿底,含圆角下沿) | 1 | 1100 × 62 |
| 613 | LINE_DIVIDER |
玩家栏之间的分隔线 | 1 | 1060 × 2 |
3.6 数字与符号
2026-08-26 修订(重要,出图规范订正):数字类资源 631/632/633/635/636 一律出成 16 帧、固定帧序
0123456789.+-x/p的多帧图片资源。 缘由:平台的SpriteManager.setNumberImage(spriteId, text, charWidth)就是为多位美术字数字准备的现成接口——把整串文本设给一个多帧图片精灵,引擎按字符逐帧渲染,并按字符数 ×charWidth自动调整精灵宽度。所以一个精灵就能显示一整串数字:既不用拆十位/个位,也不用setFrame逐位切(setFrame是"整个精灵显示第 N 帧",只适合状态/花色/牌面这类"选其一")。 帧号由字符直接换算('0'–'9'→ 帧1–10,后缀字 → 帧16),因此帧序不可重排、不可省略占位;用不到的帧位也要按顺序留出来,否则帧号对不上、画面串位。 三种显示机制的选用判据见前端文档02-渲染与UI组件体系.md;charWidth/charHeight等数值在EQW_Layout.NUM_STYLE.*(LayoutConstants.js)集中配置,本表只记出图规格。
固定帧序(所有 NUM_* 通用):
| 帧 | 1–10 | 11 | 12 | 13 | 14 | 15 | 16 |
|---|---|---|---|---|---|---|---|
| 内容 | 0–9 |
. |
+ |
- |
x |
/ |
可变后缀(该套资源自己的后缀字:分/倍/张) |
| ID | 键名 | 用途 | 帧数 | 第 16 帧(后缀) | 单字符尺寸 | 整图尺寸 |
|---|---|---|---|---|---|---|
| 631 | NUM_COUNTDOWN |
倒计时数字 | 16 | 无后缀(出空白占位) | 44 × 60 | 704 × 60(16 × 44) |
| 635 | NUM_CALL_SCORE |
叫分档位的分数数字(深棕描边美术字) | 16 | 【待美术与规则确认】档位只显示分数数字;若日后要显示 70分 则此帧出 分 |
30 × 40 | 480 × 40(16 × 30) |
| 632 | NUM_RESULT_WIN |
结算得分数字(赢,橙)——用到帧12 +、帧13 - |
16 | 【待美术与规则确认】结算大字目前只显示数字,也可能是 分 |
46 × 62 | 736 × 62(16 × 46) |
| 633 | NUM_RESULT_LOSE |
结算得分数字(输,蓝) | 16 | 同 632(含待确认项),仅配色不同 | 46 × 62 | 736 × 62(16 × 46) |
| 634 | ANI_JUDGE |
判定结果动画(大光 / 小光 / 过庄 / 升N级 / 投降)——帧动画资源,播放参数进 AnimationConfigs【待设计 D-8】。注意:这是帧动画,不适用本节的 16 帧数字规范 |
待定 | —— | 待定 | 待定 |
| 636 | NUM_MAIN_SUIT_COUNT |
选主面板花色张数数字(美术单独出图,字号配色与以上几套不同;一个花色一个精灵) | 16 | 张(显示形如 26张) |
24 × 32(估值) | 384 × 32(16 × 24) |
出图要求:16 帧等宽(后缀字与数字同宽,因为宽度按"字符数 × 单字宽"算);帧序严格照上表,用不到的帧位(如某些套的
.x/)仍要占位。 带描边/渐变的美术字用多帧图数字精灵 +setNumberImage(倒计时、结算得分、叫分分数、选主张数),文字精灵做不出这种效果——631–636 都要出图。 纯数据型小字用文字精灵(SpriteManager.setText/setTextWithWidth):叫分角标的子数(值域 2–15,随爬坡开关变)、主N/对N角标、局数、主牌统计条文案等。 2026-08-26 新增 636:选主张数原计划走文字精灵,但美术侧单独出了一套数字图(字号配色不同于既有几套);同日一度定为「十位/个位各一个精灵」,现已撤销——setNumberImage一个精灵就能显示26张。
3.7 浮层与气泡
| ID | 键名 | 用途 | 帧数 | 帧说明 | 尺寸 |
|---|---|---|---|---|---|
| 651 | BUBBLE_TISHI |
踩 / 没分 / 有分 提示气泡 | 6(3×2) | 帧1=踩·箭头向左 帧2=没分·箭头向左 帧3=有分·箭头向左 帧4=踩·箭头向右 帧5=没分·箭头向右 帧6=有分·箭头向右。帧序内层是 tip(1踩/2没分/3有分)、外层是箭头朝向 → frame = (arrowRight ? 3 : 0) + tip。箭头向左 = 头像在气泡左侧、箭头向右 = 头像在气泡右侧 |
待定 |
TXT_BAOZHU |
不需要:报无主不做全场提示(D-4),只让他家 主N/对N 角标出现 |
—— | —— | —— | |
| 653 | BAR_TOAST |
通用状态提示条底(深色半透圆角,白字居中)——等待庄家选主 / 强甩失败 等共用(§2.8) |
1 | 可九宫拉伸,按文案长度变宽 | 363 × 50 |
| 654 | TXT_GRADE_FLOAT |
捡分飘字底(20分 金色) |
1 | 待定 | 待定 |
PANEL_BOTTOM_3S |
不需要:底牌 3 秒展示复用庄家翻底牌那套 UI(D-2),仅可见范围不同 | —— | —— | —— |
3.8 建房选项
| ID | 键名 | 用途 | 帧数 | 帧说明 | 尺寸 |
|---|---|---|---|---|---|
| 681 | ROOM_OPT_BOX |
建房选择框(单选钮 + 复选框合一) | 4(2×2) | 帧1=单选·未选中(灰空心环) 帧2=单选·已选中(橙实心环) 帧3=复选·未选中(浅绿空方块) 帧4=复选·已选中。帧号 = (useCheckbox ? 3 : 1) + (selected ? 1 : 0);「单选(可不选)」用复选帧 3/4 |
22 × 22 |
| 682 | ROOM_CAT_TITLE |
建房类别标题(一张图多帧) | 3 | 帧1=牌局 帧2=模式 帧3=规则 | 60 × 24 |
| 683 | ROW_ROOM_OPT |
选项行底(可选,参考图为无底透明) | 1 | —— | 待定 |
4. 声音资源总表 【整节待确认 T-20】
design 与协议均未定义任何音效。以下是按牌类游戏常规推导的候选清单,未经确认,不得直接作为出音依据:
| ID | 键名 | 触发时机 |
|---|---|---|
| 101 | SND_DEAL |
发牌 |
| 102 | SND_CALL_SCORE |
叫分 |
| 103 | SND_NO_CALL |
不叫 |
| 104 | SND_BE_BANKER |
上庄 |
| 105 | SND_CHOOSE_MAIN |
选主 |
| 106 | SND_SURRENDER |
投降 |
| 107 | SND_BURY |
埋牌 |
| 108 | SND_PLAY_CARD |
出牌 |
| 109 | SND_SHUAI |
甩牌 |
| 110 | SND_SHUAICUO |
甩错 |
| 111 | SND_BI |
毙牌 |
| 112 | SND_WIN_ROUND |
赢下一轮 / 捡分 |
| 113 | SND_BAOZHU |
报无主 |
| 114 | SND_TISHI_1/2/3 |
踩 / 没分 / 有分 |
| 115 | SND_KOUDI |
扣底 |
| 116 | SND_RESULT_WIN |
小局结算 · 赢 |
| 117 | SND_RESULT_LOSE |
小局结算 · 输 |
| 118 | SND_COUNTDOWN_TICK |
倒计时最后 N 秒 |
| 119 | SND_BTN_CLICK |
通用按钮点击 |
要确认的:是否需要男/女声区分、是否需要方言语音包、SND_TISHI 是否用真人语音、倒计时提示音从第几秒开始。
5. 精灵结构表
格式遵循
gameabc-framework/templates/GameView_Sprites.template.js。 ID 为规划建议值,编辑器建成后须逐个回填校准(§0 前言)。 每条注明:类型(图片/文字/容器/热区)· 用途 · 资源键 · 帧说明。
5.1 Layer 101 · 牌桌常驻
| 群组 | 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
|---|---|---|---|---|---|
| 201 顶部信息条 | 1001 | TOP_INFO_BG |
图片 | 三列表格底 | PANEL_TOP_INFO |
| 1002 | TOP_SUIT_ICON |
图片 | 主 列花色 |
SUIT_ICON_S 帧 = flower |
|
| 1003 | TOP_CALL_TEXT |
文字 | 叫分数值 | —— | |
| 1004 | TOP_CALL_BADGE_BG |
图片 | 叫分角标底 | BADGE_MULTIPLE 帧1 |
|
| 1005 | TOP_CALL_BADGE_TEXT |
文字 | N子 |
—— | |
| 1006 | TOP_GRADE_TEXT |
文字 | 抓分数值 | —— | |
| 1007 | TOP_GRADE_BADGE_BG |
图片 | 抓分角标底 | BADGE_MULTIPLE 帧2 |
|
| 1008 | TOP_GRADE_BADGE_TEXT |
文字 | N倍【T-16】 |
—— | |
| 206 主牌统计条 | 1030 | ZHU_STAT_BG |
图片 | 半透圆角条 | BAR_ZHU_STAT |
| 1031 | ZHU_STAT_TEXT |
文字 | 自己主牌统计文案 x对 x主 |
—— | |
| 205 底栏 | 1040 | FOOTER_BG |
图片 | 底栏深色条 | BAR_FOOTER |
| 1041 | FOOTER_ASET_TEXT |
文字 | 1/4 局 |
—— | |
| 1042 | BTN_MINGPAI |
图片 | 明牌 |
BTN_BOTTOM_FUNC |
|
| 1043 | BTN_MINGPAI_TEXT |
文字 | 按钮文案 | —— | |
| 1044 | BTN_HISTORY |
图片 | 已出牌 |
BTN_BOTTOM_FUNC |
|
| 1045 | BTN_HISTORY_TEXT |
文字 | —— | —— | |
| 1046 | BTN_LAST_ROUND |
图片 | 上一轮 |
BTN_BOTTOM_FUNC |
|
| 1047 | BTN_LAST_ROUND_TEXT |
文字 | —— | —— | |
| 1048 | BTN_BOTTOM_CARDS |
图片 | 底牌 |
BTN_BOTTOM_FUNC |
|
| 1049 | BTN_BOTTOM_CARDS_TEXT |
文字 | —— | —— | |
| 1050 | BTN_TISHI_CAI |
图片 | 踩(闲家,占庄标区) |
BTN_TISHI |
|
| 1051 | BTN_TISHI_CAI_TEXT |
文字 | 踩 |
—— | |
| 1052 | BTN_TISHI_HAS |
图片 | 有分 |
BTN_TISHI |
|
| 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 |
文字 | 剩余主牌数 | —— | |
| 1103 | P_LEFT_PAIR_BG |
图片 | 对N 角标底 |
BADGE_ZHU_PAIR 帧2 |
|
| 1104 | P_LEFT_PAIR_TEXT |
文字 | 剩余主对数 | —— | |
| 1105 | P_LEFT_STATUS_TEXT |
文字 | 60分 / 不叫 |
—— | |
| 203 右上家标记 | 1110–1115 | P_RIGHT_* |
结构同 202 | ||
| 204 自己标记 | 1120 | P_SELF_BANKER |
图片 | 底栏 庄 印章 |
MARK_BANKER |
| 1121 | P_SELF_STATUS_TEXT |
文字 | 50分 / 不叫 |
—— |
5.2 Layer 102 · 手牌区(群组 210)
| 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
|---|---|---|---|---|
| 1200–1235 | HAND_CARD_1 … HAND_CARD_36 |
图片 ×36 | 自己手牌 | CARD_FACE_L,帧 = cardIdToFrame(id) |
| 2100–2135 | HAND_MARK_1 … HAND_MARK_36 |
图片 ×36 | 手牌牌面标记【T-8】,与 HAND_CARD_1..36 一一对应(HAND_MARK_i 属于 HAND_CARD_i) |
MARK_CARD_GROUP |
2026-08-26 修订:原表写「牌型分组标记 ×8,1236–1243」,与本文 §1.6 的「三种标记互斥、每张牌至多一个」相矛盾——按分组理解只需 ≤8 个(一手至多 8 组拖拉机),按每张牌理解则需与手牌等量。 裁决按「每张牌」:§1.6 是行为规格、比本表的措辞更权威,且标记的三种取值(
拖/ 正2正7 / 其他主牌)本就是逐张判定的属性,而非只标在拖拉机组上。实测一手 28 张牌通常带 13 个以上标记、36 张埋牌手更多,8 个远远不够。 号段改为 2100–2135(1236–1243 段太窄容不下 36 个,且其后 1250 起已被底牌区占用);1236–1243作废、不再分配。前端config/Sprites_Cards.js已按此落地,core/CardMark.js亦按每张牌返回标记。
5.3 Layer 103 · 桌面牌
| 群组 | 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
|---|---|---|---|---|---|
| 211 底牌 | 1250–1257 | BOTTOM_CARD_1..8 |
图片 ×8 | 底牌(发牌留桌 8 张);未揭示时帧 = 55 牌背,70 分公示 / 庄家查看时翻正面 | CARD_FACE_L |
| 215 埋牌底牌 | 1258–1265 | BURY_CARD_1..8 |
图片 ×8 | 结算时亮出的埋牌底牌 | CARD_FACE_S |
| 212 自己出牌 | 1300–1327 | PLAY_SELF_1..28 |
图片 ×28 | 本轮打出的牌 | CARD_FACE_M |
| 1328 | PLAY_SELF_TYPE_BG |
图片 | 牌型标签 | LABEL_CARDTYPE |
|
| 1329 | PLAY_SELF_TYPE_TEXT |
文字 | 标签文案 | —— | |
| 213 左上家出牌 | 1400–1429 | PLAY_LEFT_* |
结构同 212 | ||
| 214 右上家出牌 | 1500–1529 | PLAY_RIGHT_* |
结构同 212 |
5.4 Layer 104 · 阶段操作区
| 群组 | 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
|---|---|---|---|---|---|
| 220 叫分面板 | 1600 | CALL_PANEL_BG |
图片 | 面板底 | PANEL_CALL_SCORE |
| 1601 | CALL_HINT_BG |
图片 | 提示条底 | BAR_HINT_TOP |
|
| 1602 | CALL_HINT_TEXT |
文字 | 70分坐庄才可投降 |
—— | |
| 1603–1616 | CALL_BTN_1..14 |
图片 ×14 | 档位按钮底(含角标底,70…5) | BTN_CALL_SCORE 帧1–3 按档位位置固定 / 帧4 灰 |
|
| 1617–1630 | CALL_BTN_NUM_1..14 |
多帧图数字精灵 ×14 | 档位分数(70…5),一个精灵显示整串(setNumberImage,两位数不拆精灵;2026-08-26,见 §1.3/§3.6) |
NUM_CALL_SCORE(16 帧)+ NUM_STYLE.CALL_SCORE.charWidth |
|
| 1631–1644 | CALL_BTN_BADGE_1..14 |
文字 ×14 | 该档 multiple 子数(2子…15子),随爬坡开关变 |
—— | |
| 1645 | CALL_BTN_NONE |
图片 | 不叫 |
BTN_NO_CALL |
|
| 1646 | CALL_BTN_NONE_TEXT |
文字 | —— | —— | |
| 221 选主面板(2026-08-26 修订:美术改一张图 5 帧出图,花色图标/角标底/投降文字并入按钮帧,见 §1.5/§3.3) | 1650 | MAIN_TITLE_BG |
图片 | 亮主 斜角条 |
BAR_CHOOSE_MAIN |
| 1651 | MAIN_TITLE_TEXT |
文字 | 亮主 |
—— | |
| 1652–1655 | MAIN_SUIT_BTN_1..4 |
图片 ×4 | 花色按钮(已含按钮底+花色图标+角标底),帧=花色序1–4 | BTN_SUIT_CHOOSE 帧1–4 |
|
| 1668–1671 | MAIN_SUIT_PAIR_TEXT_1..4 |
文字 ×4 | N对,叠在对应按钮角标底之上 |
—— | |
| 1674–1677 | MAIN_SUIT_COUNT_1..4 |
多帧图数字精灵 ×4 | 该花色在庄家手中的张数,显示 26张(一个花色一个精灵,setNumberImage;2026-08-26 由十位/个位 8 个精灵改回 4 个,见 §3.6) |
NUM_MAIN_SUIT_COUNT(16 帧,第16帧=张)+ NUM_STYLE.MAIN_SUIT_COUNT.charWidth |
|
| 1672 | MAIN_BTN_SURRENDER |
图片 | 投降(已含按钮底+文字) |
BTN_SUIT_CHOOSE 帧5 |
|
MAIN_SUIT_ICON_1..4 / 原 MAIN_SUIT_COUNT_1..4(文字精灵)/ MAIN_SUIT_PAIR_BG_1..4 / MAIN_BTN_SURRENDER_TEXT |
—— | 不需要:分别并入按钮帧、或改为上方 1674–1677 的数字精灵,空出的 ID 不复用 | —— | ||
MAIN_SUIT_COUNT_3/4_TENS/ONES |
—— | 不需要(2026-08-26):setNumberImage 一个精灵就能显示整串,十位/个位拆分作废,空出的 4 个 ID 不复用 |
—— | ||
| 222 埋牌操作条 | 1700 | BURY_BTN_TIP |
图片 | 提示 |
BTN_TIP |
| 1701 | BURY_BTN_TIP_TEXT |
文字 | —— | —— | |
| 1702 | BURY_BTN_SUBMIT |
图片 | 埋牌 |
BTN_BURY 帧1可提交/帧2灰 |
|
| 1703 | BURY_BTN_SUBMIT_TEXT |
文字 | 埋牌 (N/8) |
—— | |
| 223 出牌操作条 | 1710 | PLAY_BTN_SUBMIT |
图片 | 出牌 |
BTN_PLAY 帧1可出/帧2灰 |
| 1711 | PLAY_BTN_SUBMIT_TEXT |
文字 | —— | —— | |
| 1712 | PLAY_BTN_TIP |
图片 | 提示(出牌阶段必备) |
BTN_TIP |
|
| 1713 | PLAY_BTN_TIP_TEXT |
文字 | 按钮文案 | —— | |
| 224 倒计时(2026-08-27 订正:由文字精灵改为多帧图数字精灵,见 §2.4/§6.8) | 1150 | CD_LEFT |
多帧图数字精灵 | 左上家位倒计时 | NUM_COUNTDOWN(16 帧)+ NUM_STYLE.COUNTDOWN.charWidth |
| 1151 | CD_RIGHT |
多帧图数字精灵 | 右上家位倒计时 | NUM_COUNTDOWN(16 帧)+ NUM_STYLE.COUNTDOWN.charWidth |
|
| 1152 | CD_SELF |
多帧图数字精灵 | 自己操作区倒计时 | NUM_COUNTDOWN(16 帧)+ NUM_STYLE.COUNTDOWN.charWidth |
5.5 Layer 105 · 桌面浮层(群组 230)
| 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
|---|---|---|---|---|
| 1750–1752 | BUBBLE_TISHI_LEFT/RIGHT/SELF |
图片 ×3 | 踩/没分/有分 气泡(按发送者位置) | BUBBLE_TISHI 帧 = tip |
TXT_BAOZHU |
—— | 不需要(D-4) | —— | |
BAR_SHUAICUO |
—— | 并入下方通用状态提示条 | —— | |
| 1760 | BAR_TOAST |
图片 | 通用状态提示条底(§2.8) | BAR_TOAST |
| 1761 | TXT_TOAST |
文字 | 提示文案(等待类 / 即时反馈类共用) | —— |
| 1755 | GRADE_FLOAT_BG |
图片 | 捡分飘字底 | TXT_GRADE_FLOAT |
| 1756 | GRADE_FLOAT_TEXT |
文字 | 20分 |
—— |
BOTTOM_3S_* |
—— | 不需要(D-2:底牌 3 秒展示复用底牌区翻牌,仅可见范围不同) | —— |
5.6 Layer 302 · 小局结算(群组 240)
| 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
|---|---|---|---|---|
| 1800 | RESULT_BOTTOM_PANEL |
图片 | 底牌区面板底 | PANEL_BOTTOM_CARDS |
| 1801 | RESULT_BOTTOM_TEXT |
文字 | 叫分{multiple}子 底牌 {grade1}x{bottom.multiple} |
—— |
| 1802–1804 | RESULT_GLOW_LEFT/RIGHT/SELF |
图片 ×3 | 三家分数光晕 | GLOW_RESULT 帧1赢/帧2输 |
| 1805–1807 | RESULT_SCORE_LEFT/RIGHT/SELF |
多帧图数字精灵 ×3(2026-08-27 由文字精灵改,见 §1.9/§6.9) | 三家总分(aset.seatlist[i].grade),正分橙带 +/负分蓝带 -,与 ACC_TPL_SCORE_NUM(1914)同一套资源与用法 |
NUM_RESULT_WIN(赢)/ NUM_RESULT_LOSE(输)+ NUM_STYLE.RESULT_WIN/RESULT_LOSE.charWidth |
| 1808–1810 | RESULT_JF_LEFT/RIGHT/SELF |
文字 ×3 | 捡分子数得分 grade_jf【T-13】 |
—— |
| 1811–1813 | RESULT_AW_LEFT/RIGHT/SELF |
文字 ×3 | 算奖得分 grade_aw【T-13】 |
—— |
RESULT_JUDGE_TEXT |
—— | 不需要:结算面板不显示判定文字,改由动画呈现(§1.8) | —— | |
| 1815 | RESULT_BTN_CG |
图片 | 冲关牌型 按钮 |
BTN_CG_CARDS |
| 1816 | RESULT_BTN_CG_TEXT |
文字 | 按钮文案 | —— |
| 1817 | RESULT_BTN_NEXT |
图片 | 下一局 按钮 |
BTN_NEXT_ASET |
| 1818 | RESULT_BTN_NEXT_TEXT |
文字 | 按钮文案 | —— |
底牌 8 张精灵复用 §5.3 群组 215(1258–1265),不在此重复。
5.6a 冲关牌型叠加层(Layer 302,群组 244,精灵复制)
本层的牌用 SpriteCopyUtils 运行时复制,不预置固定张数。 aset.seatlist[i].cards 的长度不定(四王 + 长连对链 + 八个 7 + 八个 2 可达 20 余张),预置既可能不够、又在多数局里白占 ID。
只需在编辑器里建 5 个精灵(3 个容器 + 1 个牌模板 + 1 个遮罩):
| 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
|---|---|---|---|---|
| 1820 | CG_MASK |
图片 | 半透黑遮罩(拉伸满屏,兼作点击关闭热区) | MASK_DIM |
| 1821 | CG_BOX_LEFT |
容器 | 左上家冲关牌容器(复制的父精灵) | —— |
| 1822 | CG_BOX_RIGHT |
容器 | 右上家冲关牌容器 | —— |
| 1823 | CG_BOX_SELF |
容器 | 自己冲关牌容器 | —— |
| 1824 | CG_CARD_TPL |
模板 | 冲关牌模板(编辑器里放好、默认隐藏,只作样式来源) | CARD_FACE_L |
| 1825–1827 | CG_COUNT_LEFT/RIGHT/SELF |
文字 ×3 | 奖数,与该家的冲关牌并列显示(取 aset.seatlist[i].naward;是否另列 chongguan/wang 明细见下) |
—— |
生成方式:
// 每个座位一个容器,tag 用牌在 cards 里的下标(父精灵内唯一即可)
var pos = LayoutSolver.solve(EQW_Layout.CG_CARDS, seatKey, cards.length); // fan 布局,见 §6.7
for (var i = 0; i < cards.length; i++) {
var sid = SpriteCopyUtils.create(boxId, sprites.CG_CARD_TPL, pos[i].x, pos[i].y, i);
SpriteManager.setFrame(sid, cardIdToFrame(cards[i])); // §0.4
}
清理是硬要求:关闭叠加层 / 组件 onDestroy 时必须 SpriteCopyUtils.removeRange(boxId, 0, cards.length),否则复制精灵残留(client 02 §6)。
RESULT_BTN_NEXT(1817/1818)在遮罩之上仍需可见可点 —— 其图层内层级须高于CG_MASK。
预置 vs 精灵复制的选用判据
| 判据 | 预置固定精灵 | 精灵复制 |
|---|---|---|
| 数量 | 有明确且不大的上限 | 上限不定或很大 |
| 常态占用率 | 多数时候都在用 | 多数时候只用极少几个 |
| 逐个控制 | 需要独立 z 序 / 动画 / 命名引用 | 只需批量摆位 + 设帧 |
| 清理成本 | 无 | 必须显式 remove,忘了就残留 |
据此,本清单的选用——全项目只有「冲关牌型」一处用复制,其余一律预置:
| 区域 | 方式 | 理由 |
|---|---|---|
| 冲关牌型 | 复制 | 张数不定、无小上限,多数局用不满 |
| 自己手牌(36) | 预置 | 上限确定;需逐张选中上浮、独立动画与点击 |
| 已出牌区(28 × 3) | 预置 | 需叠压 z 序与出牌动画,逐张独立控制 |
| 底牌(8)/ 埋牌底牌(8) | 预置 | 固定 8 张 |
| 建房规则选项 | 预置 | 选项集固定(4 组 8 项),数量小 |
精灵段 1001–2999 有近 2000 个空位(§0.3),预置的 ID 开销不构成压力;复制只用在「数量真的不定」的地方,避免给每处都背上显式清理的负担。
5.7a Layer 303 · 大局总结算(群组 241,玩家栏用精灵复制)
三条玩家栏结构完全相同、仅数据不同,用 SpriteCopyUtils 复制生成;面板外壳与按钮预置。
| 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
|---|---|---|---|---|
| 1900 | ACC_PANEL_BG |
图片 | 面板底(圆角浅灰绿) | PANEL_ACCOUNT |
| 1901 | ACC_TITLE_BAR |
图片 | 标题栏(青绿底) | BAR_ACCOUNT_TITLE |
| 1902 | ACC_TITLE_TEXT |
文字 | 二七王-3人 房号… 共…局 … |
—— |
| 1903 | ACC_BTN_CLOSE |
图片 | 右上角关闭 | BTN_ACC_CLOSE |
| 1904 | ACC_RULE_BAR |
图片 | 底部规则栏(浅绿底) | BAR_ACCOUNT_RULE |
| 1905 | ACC_RULE_TEXT |
文字 | 规则:可查牌、傍王、爬坡算子 |
—— |
| 1910 | ACC_ROW_CONTAINER |
容器 | 玩家栏的复制父精灵 | —— |
| 1911 | ACC_TPL_RANK |
模板 | 名次徽章 | BADGE_RANK,帧 = 名次 1–3 |
| 1912 | ACC_TPL_AVATAR |
模板 | 头像 | 运行时贴玩家头像 |
| 1913 | ACC_TPL_TEXT |
模板 | 通用文字(昵称/ID/各项分数,一行一个) | —— |
| 1914 | ACC_TPL_SCORE_NUM |
模板 | 右侧总分大字(数字精灵) | NUM_RESULT_WIN / NUM_RESULT_LOSE |
| 1915 | ACC_TPL_DIVIDER |
模板 | 行间分隔线 | LINE_DIVIDER |
| 1920–1927 | ACC_BTN_* |
图片×4 + 文字×4 | 再来一局 / 分享好友 / 复制战绩 / 退出房间 |
BTN_ACCOUNT_* |
tag 分段(SpriteCopyUtils.createTagManager):rank 1–20 / avatar 21–40 / text 41–140(每行 6 条文字)/ score 141–160 / divider 161–180。
清理:关闭面板时 removeRange 清掉各段。
解散结算复用本面板(协议 §14.1,解散包也带
account),只是aset各项为 0。布局配置见 §6.9a(2026-08-27 补齐;此前本 View 没有任何布局节点)。
5.7b Layer 304 / 305 · 出牌历史与明牌(群组 242 / 243,牌用精灵复制)
两者版式相同(遮罩 + 每家一排牌,照 冲关牌型显示.png),差别只在数据源与家数,共用同一套渲染:
| 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
|---|---|---|---|---|
| 1950 | HIST_MASK |
图片 | 半透黑遮罩(兼关闭热区) | MASK_DIM |
| 1951–1953 | HIST_BOX_LEFT/RIGHT/SELF |
容器 ×3 | 每家一个牌容器 | —— |
| 1954 | HIST_CARD_TPL |
模板 | 牌模板 | CARD_FACE_L |
| 1955–1957 | HIST_LABEL_LEFT/RIGHT/SELF |
文字 ×3 | 座位标签(昵称 / 张数) | —— |
| 2000 | MING_MASK |
图片 | 明牌遮罩 | MASK_DIM |
| 2001–2002 | MING_BOX_A/B |
容器 ×2 | 另两家各一个容器(明牌只看他家) | —— |
| 2003 | MING_CARD_TPL |
模板 | 牌模板 | CARD_FACE_L |
| 2004–2005 | MING_LABEL_A/B |
文字 ×2 | 座位标签 | —— |
- 出牌历史:三家都显示,数据 =
pushlist摊平聚合到各家、按主牌序排序(§1.7 D-7)。 - 上一轮:同一套精灵,数据只取
pushlist末尾一项。 - 明牌:只显示另两家,数据 =
mingpai.others[].zhucards(§1.7 D-6)。 - 亮牌:只显示一排(庄家的固定主牌),数据 =
liangpai.cards(§1.6)。复用同一套遮罩 + 容器 + 牌模板,仅数据源与排数不同。 ⚠ 这里的「亮牌」是 design §8.2 那件事,与 §2.5 手牌上方的主牌统计条(群组 206ZHU_STAT_*)无关——后者 2026-08-27 前也叫「亮牌条」,已改名以消歧义。
布局配置见 §6.9c(2026-08-27 补齐;此前
HIST_*/MING_*都没有布局节点)。解散投票由平台提供(Layer 420),子游戏无需精灵。
5.8 建房规则选项(群组 250,2050–2099,预置)
3 个类别、4 个选项组、8 个选项(§1.1)。选项集固定,全部预置。
| 精灵 ID | 键名 | 类型 | 用途 | 资源 / 帧 |
|---|---|---|---|---|
| 2050–2052 | ROOM_CAT_TITLE_1..3 |
图片 ×3 | 类别标题(牌局 / 模式 / 规则) | ROOM_CAT_TITLE,帧 = 1 / 2 / 3 |
| 2053–2054 | ROOM_BOX_ASET_1..2 |
图片 ×2 | 局数选择框(6局 / 12局) | ROOM_OPT_BOX,单选帧 1–2 |
| 2055–2056 | ROOM_TEXT_ASET_1..2 |
文字 ×2 | 局数选项文字 | —— |
| 2057–2058 | ROOM_BOX_CARD_1..2 |
图片 ×2 | 扣卡选择框(房主 / AA) | ROOM_OPT_BOX,单选帧 1–2 |
| 2059–2060 | ROOM_TEXT_CARD_1..2 |
文字 ×2 | 扣卡选项文字 | —— |
| 2061 | ROOM_TEXT_CARD_COST |
文字 | 房卡消耗附注(灰色小字,随局数 × 扣卡联动) | —— |
| 2062–2063 | ROOM_BOX_PEEK_1..2 |
图片 ×2 | 查牌选择框(可查 / 不查) | ROOM_OPT_BOX,单选帧 1–2 |
| 2064–2065 | ROOM_TEXT_PEEK_1..2 |
文字 ×2 | 查牌选项文字 | —— |
| 2066–2067 | ROOM_BOX_RULE_1..2 |
图片 ×2 | 附加规则选择框(傍王 / 爬坡) | ROOM_OPT_BOX,复选帧 3–4 |
| 2068–2069 | ROOM_TEXT_RULE_1..2 |
文字 ×2 | 附加规则选项文字 | —— |
共 20 个精灵。挂在平台创建房间界面所在图层(T-3)。布局配置见 §6.9b。
精灵虽预置,渲染仍由 §1.1 的配置数据驱动:配置里每个选项声明自己用哪个精灵键、
type(决定选择框帧号)、bit/value(决定roomtype拼串)。渲染代码不认识「傍王」「爬坡」这些具体玩法名。
6. 布局配置规范与配置清单
硬要求:所有布局参数一律外提为配置,业务代码零裸值。 位置、大小、排列方式、间距、对齐、朝向、缩放、文字样式——凡是「摆在哪、多大、怎么排」的参数, 全部写进布局配置文件,代码只读配置。这既是工程总则 §6「配置优先于硬编码」,也是 client 02 §2 「布局文件是纯数据:无函数、无副作用」的要求。
⚠️ 本节所有数值均为参考图(1280×720)目视实测估值,误差约 ±5px,是给美术和编辑器的起点、不是最终值。 设计稿到位后必须整体复核。但布局器类型(
kind)与参数结构是设计决定,不随数值变动。
6.0 与框架 AlignmentUtils 的对齐
参数命名直接采用框架 gameabc-framework/ui/AlignmentUtils.js 的入参名,配置对象可原样喂进框架方法,中间零转换:
配置的 kind |
落到框架的方法 |
|---|---|
line |
AlignmentUtils.distribute({direction, anchorX, anchorY, count, itemWidth, itemHeight, spacing, anchor}) |
fan |
先算出 spacing,再走同一个 AlignmentUtils.distribute |
attach(corner 为空) |
AlignmentUtils.alignSpriteToSprite(targetId, spriteId, hAlign, vAlign, offset) |
attach(corner 有值) |
AlignmentUtils.alignSpriteCornerTopLeft/TopRight/BottomLeft/BottomRight(targetId, spriteId, offset) |
grid |
逐行调 distributeHorizontally |
point |
直接 SpriteManager.setPosition |
对齐常量沿用框架的 AlignmentUtils.ALIGN:水平 left/center/right、垂直 top/middle/bottom。
精灵锚点恒在左上角、不可更改(AlignmentUtils 文件头注释),所有对齐都是基于锚点的换算。配置里写的
anchorX/anchorY是对齐基准点,不是精灵左上角坐标。
6.1 五种布局器(kind)
每个部件的配置必须声明 kind,kind 决定它合法的参数集。
point — 定点
单个元素放在固定位置。
{ kind: 'point', x: 486, y: 4, w: 276, h: 68 }
// 可选:scale(倍数,业务单位)、opacity(0.0–1.0)
line — 等距排列
数量可变但间距固定的一排(底牌 8 张、埋牌底牌 8 张)。
{ kind: 'line', direction: 'horizontal',
anchorX: 655, anchorY: 110, // 对齐基准点
itemWidth: 110, itemHeight: 190,
spacing: -36, // 负值 = 重叠
anchor: 'center' } // left | center | right
count 由运行时数据给出,不进配置。
逐项不等宽:给出可选的 items 时逐项取宽,itemWidth 失效——用于底栏功能钮组(74/87/93/78)与埋牌操作条(180/60/180)这类宽度不一的排:
{ kind: 'line', direction: 'horizontal',
anchorX: 1250, anchorY: 672, itemHeight: 30, spacing: 15, anchor: 'right',
items: [ {key:'BTN_MINGPAI', width:74}, {key:'BTN_HISTORY', width:87},
{key:'BTN_LAST_ROUND', width:93}, {key:'BTN_BOTTOM_CARDS', width:78} ] }
fan — 自适应压缩排
张数可变、总宽受限、需要动态压缩间距的牌排(手牌、出牌区、冲关牌)。
{ kind: 'fan', direction: 'horizontal',
anchorX: 640, anchorY: 455,
maxWidth: 1215, // 可用总宽上限
itemWidth: 110, itemHeight: 190,
spacingMax: 0, // 张数少时的最大间距(0 = 紧贴不重叠)
spacingMin: -84, // 张数多时的最大重叠量(负值)
anchor: 'center',
overlapFrom: 'left' } // left = 右边的牌压在左边的牌之上
间距算法(唯一实现,不散落):
count <= 1 → spacing 不参与,直接按 anchor 摆一张
otherwise → raw = (maxWidth - itemWidth) / (count - 1) - itemWidth
spacing = clamp(raw, spacingMin, spacingMax)
overlapFrom 决定 z 序方向:'left' 时后面的牌盖住前面的(自己手牌、右上家);'right' 时反过来(左上家镜像用)。
grid — 网格
固定行列的按钮阵(叫分 14 档 = 7×2)。
{ kind: 'grid',
anchorX: 640, anchorY: 160,
cols: 7, rows: 2,
itemWidth: 74, itemHeight: 56,
spacingX: 7, spacingY: 24,
anchor: 'center',
fillOrder: 'row' } // row = 先填满一行再换行
attach — 相对贴附
贴在另一个精灵上的从属元素(角标贴按钮、庄标贴头像、气泡贴头像)。
{ kind: 'attach',
target: 'P_LEFT_AVATAR', // 目标精灵的键名,不写 ID
hAlign: 'right', vAlign: 'top',
offsetX: 8, offsetY: -4,
corner: 'topRight' } // 可选;有值 = 贴到目标【外侧】角,无值 = 在目标【内部】对齐
target一律写键名而非数字 ID——ID 回填时只改一处映射表,配置文件不用动。
6.2 座位变体 bySeat
三个显示位上的同名部件共用一份配置,差异写在 bySeat 里;未列出的字段继承外层 base。
PLAY_AREA: {
kind: 'fan', direction: 'horizontal', // ← base:三家共同的部分
itemWidth: 90, itemHeight: 155, // (牌尺寸、压缩规则三家一致)
maxWidth: 170, spacingMax: -35, spacingMin: -62,
bySeat: {
SELF: { anchorX: 650, anchorY: 265, anchor: 'center', overlapFrom: 'left' },
RIGHT: { anchorX: 1022, anchorY: 120, anchor: 'center', overlapFrom: 'left' },
LEFT: { anchorX: 258, anchorY: 120, anchor: 'center', overlapFrom: 'right' } // 与 RIGHT 左右镜像
}
}
座位键固定为 SELF / LEFT / RIGHT(显示位,不是服务端座位号)。服务端座位 → 显示位的换算见 §0.1,只在一处实现。
6.3 文字样式 textStyle
文字精灵的样式也进配置,不在代码里写字号颜色。
{ fontSize: 24, color: '#FFFFFF', align: 'center', maxWidth: 130, bold: false }
6.4 牌尺寸档
三套牌面尺寸集中定义,各区域引用档名,不重复写数字。
CARD_SIZE: {
L: { w: 110, h: 190, res: 'CARD_FACE_L' }, // 手牌、底牌、冲关牌
M: { w: 90, h: 155, res: 'CARD_FACE_M' }, // 已出牌区
S: { w: 50, h: 70, res: 'CARD_FACE_S' } // 结算埋牌底牌
}
改牌面尺寸只动这一处,所有引用它的区域自动跟随。
6.5 常驻区配置
| 部件 | kind | 关键参数(实测估值) |
|---|---|---|
| 顶部信息条底 | point |
x:486 y:4 w:276 h:68 |
| 顶部 · 花色图标 | attach |
target:TOP_INFO_BG, hAlign:left, vAlign:bottom, offsetX:20, offsetY:-8 |
| 顶部 · 叫分角标 | attach |
target:TOP_CALL_TEXT, corner:topRight, offsetX:4, offsetY:6 |
| 顶部 · 抓分角标 | attach |
target:TOP_GRADE_TEXT, corner:topRight, offsetX:4, offsetY:6 |
主牌统计条(节点 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†,78](逐项不等宽,见 §6.1)。†扣底 的 78 是估值(2026-08-27 补项,本表原只列 4 项)——参考图(等待叫分.png)底栏当时也只画出 底牌 一项;依据取自 底牌 实测的 78,不能笼统说「两字按钮 = 78」:同为两字的 明牌 实测只有 74,两者不同,待设计稿复核 |
| 底栏 · 庄标 | 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 |
| 右侧聊天钮(平台) | point |
x:1210 y:385 w:56 h:56 |
6.6 玩家位配置(含气泡朝向)
平台负责头像/昵称/分数,子游戏的附加标记全部 attach 到平台头像框上——这样平台布局一调,标记自动跟随。
| 部件 | kind | 参数 |
|---|---|---|
| 头像框(平台) | point |
bySeat{ LEFT:{x:22,y:122}, RIGHT:{x:1160,y:122}, SELF:{x:22,y:645} },w:91 h:118(SELF 为 84×53)。需同步写进 Game_Modify.PLAYER_INFO_LAYOUT(§6.11) |
庄 印章 |
attach |
bySeat{ LEFT:{corner:'topRight',offsetX:7,offsetY:8}, RIGHT:{corner:'topLeft',offsetX:-40,offsetY:8}, SELF:{point x:338 y:668} } |
主N 角标 |
attach |
target:头像框, corner:bottomLeft, offsetX:0, offsetY:6, w:40 h:19 |
对N 角标 |
attach |
target:主N角标, hAlign:right, vAlign:middle, offsetX:44, offsetY:0 |
状态文字(60分/不叫) |
point |
bySeat{ LEFT:{x:170,y:165}, RIGHT:{x:980,y:165} },w:130 h:70,textStyle{fontSize:46, align:center} |
| 倒计时(多帧图数字精灵,2026-08-27 订正) | point |
bySeat{ LEFT:{x:195,y:165}, RIGHT:{x:1010,y:165}, SELF:{x:445,y:345} },h:NUM_STYLE.COUNTDOWN.charHeight(60);w 运行时注入(1–2 位数字,setNumberImage 按字符数 × charWidth 自动改宽) |
提示气泡的朝向与位置(资源 BUBBLE_TISHI 6 帧,§3.7):
| 气泡属于 | 头像在气泡的 | 用帧 | 贴附方式 |
|---|---|---|---|
| 左上家 | 左侧 | 箭头向左(帧 1–3) | attach{ target:LEFT头像框, hAlign:right, vAlign:middle, offsetX:+10 } |
| 右上家 | 右侧 | 箭头向右(帧 4–6) | attach{ target:RIGHT头像框, hAlign:left, vAlign:middle, offsetX:-10 }(气泡向左展开) |
| 自己 | 左侧 | 箭头向左(帧 1–3) | attach{ target:SELF头像, hAlign:right, vAlign:top, offsetX:+10, offsetY:-70 } |
帧号计算:frame = (arrowRight ? 3 : 0) + tip(tip:1踩 / 2没分 / 3有分)。
朝向本身也应是配置项(arrowRight: true|false)而非代码里按座位硬判。
自己发的提示,本人看不到自己的气泡(协议 §13.7 不回执,且只转发给对家)。表格里列出 SELF 的气泡配置,是为了「另一闲家看到我的气泡」时——那时在对方屏幕上我处于 LEFT 或 RIGHT 位。SELF 位的气泡实际不会出现【待确认 T-26:是否需要给自己一个本地回显】。
6.7 牌区配置
| 区域 | kind | 参数(实测估值) |
|---|---|---|
| 自己手牌 · 单排 | fan |
anchorX:640 anchorY:455 maxWidth:1215 size:L spacingMax:0 spacingMin:-78 anchor:center overlapFrom:left。36 张时算出 spacing = 1215−110)/35 − 110 ≈ −78,即每张露 32px,与参考图实测 33px 吻合 |
| 自己手牌 · 双排(埋牌) | fan ×2 |
上排 anchorX:644 anchorY:285 maxWidth:928 size:L spacingMin:-65;下排 anchorX:644 anchorY:455 maxWidth:928 size:L spacingMin:-65。分行策略:上排 floor(n/2)、下排 ceil(n/2)(36 张 = 18/18)。参考图的 17/19 属填充画法、不作依据(§0.5) |
| 手牌 · 选中上浮 | —— | selectedOffsetY: -40(配置项,不写死) |
| 底牌区 | line |
anchorX:655 anchorY:110 size:L spacing:-36 anchor:center(8 张) |
| 埋牌底牌区(结算) | line |
anchorX:640 anchorY:163 size:S spacing:2 anchor:center(8 张) |
| 已出牌区 | fan |
见 §6.2 的 bySeat 示例(三家共用 base,LEFT 镜像) |
| 已出牌 · 牌型标签 | attach |
target:该区首张牌, corner:bottomLeft, offsetX:0, offsetY:-24 |
已出牌 · 牌角 庄/大 标 |
attach |
target:对应牌, corner:topRight, offsetX:-28, offsetY:0 |
| 冲关牌(叠加层) | fan |
size:L spacingMax:-40 spacingMin:-88 maxWidth:420;bySeat{ LEFT:{anchorX:260,anchorY:120}, RIGHT:{anchorX:1035,anchorY:120}, SELF:{anchorX:640,anchorY:400} }。精灵复制(§5.6a):求解结果直接作为 SpriteCopyUtils.create 的 x/y(相对容器)。spacingMin 放宽到 -88(即最窄只露 22px)以容纳 20+ 张的极端情况 |
6.8 阶段操作区配置
2026-08-26 修订(其一):选主面板花色图标、对数角标底已并入按钮帧(见 §1.5/§3.3),对应布局节点删除。 2026-08-26 修订(其二):数字统一走
SpriteManager.setNumberImage(§3.6)后,一个多位数只占一个精灵——花色张数的「十位 / 个位」两个节点合并为一个MAIN_SUIT_COUNT。 两个数字节点的h恒为单字高,直接引用EQW_Layout.NUM_STYLE.*.charHeight(SSOT:数值只在LayoutConstants.js定义一处,布局文件不再手抄);w则留到运行时注入——setNumberImage会按「字符数 ×charWidth」自动改精灵宽,位数变宽度就变。
| 部件 | kind | 参数(实测估值) |
|---|---|---|
| 叫分 · 面板底 | point |
x:355 y:140 w:575 h:170 |
| 叫分 · 提示条 | point |
x:470 y:100 w:345 h:33 |
| 叫分 · 14 档按钮 | grid |
anchorX:640 anchorY:160 cols:7 rows:2 itemWidth:74 itemHeight:56 spacingX:7 spacingY:24 anchor:center fillOrder:row |
| 叫分 · 档位分数数字 | attach |
target:对应档位按钮, hAlign:center, vAlign:middle, offsetY:4, h:NUM_STYLE.CALL_SCORE.charHeight(40);w 运行时注入(= 字符数 × 30,由 setNumberImage 自动设) |
| 叫分 · 档位子数角标 | attach |
target:对应档位按钮, corner:topRight, offsetX:-30, offsetY:2 |
叫分 · 不叫 按钮 |
point |
x:553 y:345 w:184 h:57 |
| 叫分 · 自己叫分大字 | point |
x:570 y:320 w:140 h:70,textStyle{fontSize:52, align:center} |
| 选主 · 标题斜角条 | point |
x:330 y:315 w:425 h:50 |
| 选主 · 4 花色 + 投降 | line |
direction:horizontal anchorX:330 anchorY:373 itemWidth:128 itemHeight:55 spacing:9 anchor:left(共 5 项;投降不显示时只排 4 项,anchor:left 保证前 4 个位置不变) |
| 选主 · 张数 | 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:446 anchorY:345 itemHeight:55 spacing:35 anchor:left,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,高度差待设计稿裁定。2026-08-27 再订正:补「提示」项后若沿用 anchor:center,整排重新居中会把已有的倒计时/出牌两项相对原先(仅 2 项时)左移 107.5px,导致「出牌」按钮偏离参考图 出牌.png 的实测位置(556–711)。改为 anchor:left, anchorX:446(= 参考图出牌按钮实测起点 556 − 倒计时宽 75 − 间距 35),求解结果:倒计时 x=446、出牌 x=556(与实测吻合)、提示 x=748 |
| 捡分飘字 | 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 |
多帧图数字样式配置 EQW_Layout.NUM_STYLE(2026-08-26 新增,在 LayoutConstants.js,与 CARD_SIZE/TEXT_STYLE 并列)——setNumberImage 所需数值的唯一出处,业务代码不许内联:
| 键 | res(资源键名) |
charWidth |
charHeight |
suffix(第16帧后缀) |
典型显示 |
|---|---|---|---|---|---|
COUNTDOWN |
NUM_COUNTDOWN |
44 | 60 | ''(无) |
15 |
RESULT_WIN |
NUM_RESULT_WIN |
46 | 62 | ''(第16帧待确认) |
+120 |
RESULT_LOSE |
NUM_RESULT_LOSE |
46 | 62 | ''(同上) |
-120 |
CALL_SCORE |
NUM_CALL_SCORE |
30 | 40 | ''(第16帧待确认) |
70 |
MAIN_SUIT_COUNT |
NUM_MAIN_SUIT_COUNT |
24 | 32 | 张 |
26张 |
charWidth是setNumberImage的入参,精灵宽度 = 字符数 ×charWidth(该接口自动设),所以布局节点的w是运行时值、不写死在配置里。charHeight供布局节点定h(setNumberImage不改高度)。suffix只能是''/分/倍/张——接口内部把这三个字统一编码到第 16 帧,写别的字不会被识别。res存的是资源键名而非 ID(与CARD_SIZE.res同一约定):布局文件是纯数据、不引用其他模块,调用方用EQW_Images[style.res]取真实 ID。
6.9 结算区配置
| 部件 | kind | 参数(实测估值) |
|---|---|---|
| 底牌面板底 | point |
x:430 y:140 w:420 h:148 |
| 底牌说明文字 | attach |
target:底牌面板底, hAlign:center, vAlign:bottom, offsetY:-14 |
| 三家分数光晕 | point |
bySeat{ LEFT:{x:175,y:150}, RIGHT:{x:865,y:150}, SELF:{x:490,y:340} },w:225 h:100 |
| 三家总分大字(多帧图数字精灵,2026-08-27 由文字精灵改,见 §1.9/§5.6) | attach |
target:对应光晕, hAlign:center, vAlign:middle,h:NUM_STYLE.RESULT_WIN.charHeight(62)(与 RESULT_LOSE 相同);w 运行时注入 |
三家 牌局分 |
attach |
target:对应光晕, hAlign:left, vAlign:bottom, offsetX:-15, offsetY:24 |
三家 冲关分 |
attach |
target:对应光晕, hAlign:right, vAlign:bottom, offsetX:15, offsetY:24 |
冲关牌型 按钮 |
point |
x:535 y:515 w:183 h:63 |
下一局 按钮 |
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 行仅前两列有文字)。估值精度:本节点是等距列模型(相对容器 192/368/544/720),参考图目视实测列 x 约 272/455/634/800(列距 183/179/166,并不等距),偏差约 10px,比本节头部通用的「±5px」更大,待设计稿复核 |
| 行内 · 右侧总分大字 | 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.9b 建房规则选项配置(§1.1)
布局是两层嵌套:类别竖排,类别内的选项组横排。
| 部件 | kind | 参数(按参考图比例估,实际以平台建房界面尺寸为准) |
|---|---|---|
| 类别(竖排) | line |
direction:vertical, anchorX:0, anchorY:0, itemHeight:32, spacing:8, anchor:left;itemHeight 为单行类别高,折行类别按实际行数累加 |
| 类别标题 | attach |
target:所在类别行, hAlign:left, vAlign:middle, offsetX:0;ROOM_CAT_TITLE 帧 = 类别序号 |
| 类别内选项槽(横排) | line |
direction:horizontal, anchorX:70, itemWidth:150, spacing:0, anchor:left(itemWidth = 一个「选择框 + 文字」的槽宽) |
| 选项组之间的额外间隔 | —— | groupGap: 40(同类别下两个选项组之间比组内选项多留的间距,配置项) |
| 选择框 | attach |
target:所在选项槽, hAlign:left, vAlign:middle |
| 选项文字 | attach |
target:同槽的选择框, hAlign:right, vAlign:middle, offsetX:8 |
| 房卡附注 | attach |
target:扣卡组最后一个选项, hAlign:right, vAlign:middle, offsetX:20,textStyle{fontSize:16, color:'#999999'} |
| 折行 | grid |
选项数超过 maxPerRow 时改用 grid{cols:maxPerRow, spacingX:0, spacingY:8, fillOrder:'row'};maxPerRow: 4(配置项,参考图「玩法」行即 4 列折 2 行)。二七王每组最多 2 项,不会触发 |
文字选中态也是配置(单选选中时文字变橙):
ROOM_OPT_TEXT: {
normal: { fontSize: 18, color: '#DDDDDD' },
selected: { fontSize: 18, color: '#E8873A' }
},
ROOM_CAT_TITLE_STYLE: { fontSize: 18, color: '#7FBFB0', bold: true, align: 'right', maxWidth: 60 }
不要在代码里写死 '#E8873A'。
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装不下。 2026-08-27 订正:原估值maxWidth:500的推导算错了——fan的间距公式是spacing = max(spacingMin, min(spacingMax, (maxWidth-itemWidth)/(count-1) - itemWidth)),代入maxWidth 500 / itemWidth 110 / count 28得(500-110)/27-110 ≈ -95.56,没有触到spacingMin:-96的下限;而fan的总宽恒等于maxWidth(只要 spacing 未被下限截断),并不是旧注释算的「488」。RIGHT座位锚点anchorX:1035配合总宽 500、anchor:center,整排右边缘落在1035+250=1285,超出 1280 设计画布 5px(LEFT/SELF因锚点更靠左未暴露)。 2026-08-27 再订正(裁定 maxWidth:480):曾先收窄到maxWidth:490让RIGHT恰好贴住 1280,但零余量太脆弱(这些锚点本身是参考图目视实测、±5px 误差),且 490 时spacingMin:-96永远不触底、是个死参数,与「每张最窄只露 14px」这条约束名存实亡;旧注释原写的「每张露 14px、总宽 488」正是spacingMin触底后的结果,说明 488 才是当初想要的值,maxWidth:500是与注释不符的笔误。改为maxWidth:480:代入公式(480-110)/27-110 ≈ -96.30,触及spacingMin:-96下限,实际 spacing 截断为-96(不再等于 raw),总宽= 28×110 + 27×(-96) = 488(不再等于maxWidth,因为 spacing 已被下限截断)。spacingMin:-96就此真正生效、不再是死参数;每张露110-96=14px,与旧注释精确一致。求解验证(count=28):LEFT首尾 x =16 → 504,RIGHT首尾 x =791 → 1279,SELF首尾 x =396 → 884,均落在 0–1280 内且有余量(RIGHT距边界 1px、LEFT/SELF余量更大)。maxWidth:480与spacingMin:-96仍是估值,待设计稿复核。 已知限制:每张仅露 14px、视觉偏窄,待设计稿复核是否改为分两排显示,或改用CARD_SIZE.M——这是估值阶段接受的限制,留给后续复核。 牌用精灵复制:三个容器精灵摆在原点、尺寸铺满屏,故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:480, spacingMax:-40, spacingMin:-96;bySeat{ LEFT:{260,120}, RIGHT:{1035,120}, SELF:{640,400} }。求解验证(count=28,spacing 触底 -96、总宽 488):LEFT 首尾 x = 16 → 504,RIGHT 首尾 x = 791 → 1279,SELF 首尾 x = 396 → 884,均落在 0–1280 内且有余量 |
| 出牌历史 · 座位标签 | 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.10 配置文件组织
按 client 02 §2 的三件套拆分,布局部分建议再按界面拆文件,用保护性声明合并:
codes/config/
LayoutConstants.js // var EQW_Layout = EQW_Layout || {}; —— 总则:CARD_SIZE、textStyle 预设、座位键
Layout_Table.js // 常驻区(§6.5)+ 玩家位(§6.6)
Layout_Cards.js // 牌区(§6.7)
Layout_Action.js // 阶段操作区(§6.8)
Layout_Result.js // 结算区(§6.9)
Layout_CreateRoom.js // 建房规则选项(§6.9b)
ImageResources.js // 图片资源 ID(§3)
SoundResources.js // 声音资源 ID(§4)
Sprites_*.js // 精灵结构(§5)
每个文件顶部 var EQW_Layout = EQW_Layout || {};,加载后合并为一份(client 02 §2「多文件用保护性声明」)。
布局文件是纯数据:不得出现函数、不得引用其他模块、不得有副作用。fan 的间距算法、bySeat 的合并、attach 的换算都属于布局求解器的职责,放在 codes/ui/LayoutSolver.js(或直接调 AlignmentUtils),不写进配置文件。
6.11 与平台布局配置的衔接
平台的玩家信息与气泡布局在 01_SubGame_modify.js 的配置区(该文件只允许在配置区填值):
Game_Modify.PLAYER_INFO_LAYOUT.POSITIONS—— 平台默认 ind0 南(6,592)、ind1 东(1186,85)、ind3 西(7,59),与 §6.6 实测值不一致,须改为 §6.6 的值。Game_Modify.BUBBLE_LAYOUT.POSITIONS—— 平台聊天/语音气泡锚点,同样按三人局位置调整。
这两处是平台契约配置,与子游戏自己的
EQW_Layout是两份东西,但坐标必须一致(否则平台画的头像和子游戏贴的庄标会错位)。建议:EQW_Layout里的头像框坐标为权威,01_SubGame_modify.js配置区手工抄写并在注释里注明「与 EQW_Layout.PLAYER.AVATAR 保持一致」【T-28:转发壳配置区不能引用 codes,只能手工同步,需在验收清单里加一条一致性检查】。
7. 待补充清单
状态汇总(2026-08-26):待确认规格 34 项只剩 T-20 音效(已明确后补);设计稿只剩 D-8(判定结果动画)。 §7.5 服务端待补项 8 条全部处理完毕。服务端侧无遗留——D-8 只差动画设计稿与触发细节。
7.1 待出设计稿的界面
只剩 D-8 一项(已定稿的保留在表内备查)。
| 编号 | 界面 | 状态 |
|---|---|---|
| D-8 | 判定结果动画(大光 / 小光 / 过庄 / 升N级 / 投降) | ⬜ 已定形态:不做结算面板上的静态文字,改为动画,在对局过程中与结算前播放(§1.8)。缺动画设计稿与触发细节 |
| 建房规则选项区 | ✅ 定稿:版式照 创建房间选项…png,内容按 §1.1 的 3 类别 / 4 选项组。子游戏只做「类别标签 + 选项」内容区,弹窗背景 / 标题 / 关闭 / 确认按钮均由平台提供 |
|
| 底牌 3 秒展示 | ✅ 定稿:复用庄家翻开底牌那套 UI(叫分确定庄.png),不要倒计时。非 70 分只有庄家能看、70 分全场能看——同一套界面,只差可见范围 |
|
| 甩错提示 | ✅ 定稿:桌面中央深色半透条 强甩失败(强甩失败提示.png),不做收回动画,直接落下那张被强制打出的最小主牌 |
|
| 报无主 | ✅ 定稿:不做全场提示。只让他家 主N/对N 角标出现;自己的主牌统计条本来就常显(§2.5) |
|
| 踩 / 没分 / 有分 | ✅ 定稿:底栏三按钮(占庄标区)+ 3×2 六帧气泡 | |
| 明牌面板 | ✅ 定稿:版式照 冲关牌型显示.png(遮罩 + 每家一排牌)。按钮条件按 design 手册:可查牌 + 已有任一玩家报无主 → 三家都显示、可随时查看 |
|
| 出牌历史面板 | ✅ 定稿:版式同上。不按轮次,按玩家聚合、用主牌序排序。前端摊平 pushlist 即可,无需改服务端 |
|
| 大局总结算 | ✅ 定稿:大局结算.png,玩家栏用精灵复制(§5.7a)。四项分数协议缺 → 见 S-6 |
|
| 解散结算 | ✅ 复用 D-9 面板;投票界面平台全包(Layer 420) | |
| 准备标识 | ✅ 用平台的 | |
| 左上家已出牌区 | ✅ 与右上家左右镜像 | |
扣底 查看面板 |
✅ 与 底牌 按钮复用同一个「8 张牌」展示面板,仅数据源不同 |
7.2 待确认的规格问题
仍未决(1 项)
| 编号 | 问题 | 影响 |
|---|---|---|
| T-20 | 整套音效:清单、是否需要语音包、是否分男女声、倒计时提示音从第几秒起 | §4 全节;已明确「等待后续补充」 |
已定论(33 项)
| 编号 | 结论 |
|---|---|
class.paiju.js:264 get_nextseat = (seat+1)%3,下家显示在右上(§0.1) |
|
解散投票平台全包(Layer 420 + GameUI.openCheck + Desk.*_free_room),子游戏只处理结算包 |
|
建房界面 = Layer 27 CreateRoom_Layer(Layer 28 是代开房/抽水,无关) |
|
| 需要发牌动画:从右往左铺开(§1.2) | |
| 见下方「T-5 手牌排序」小节 | |
| 叫分按钮按档位位置固定三档配色(浅黄/金黄/橙)+ 灰=已叫过;按钮底与角标底各 4 帧(§1.3) | |
| 选主按钮中央大数字 = 该花色张数,右上角标 = 该花色对数(§1.5) | |
手牌标记 3 帧:拖=拖拉机 / 橙星=正2正7 / 蓝星=其他主牌;前端据 flower 本地标注(§1.6) |
|
出牌阶段必有 提示 按钮;服务端已下发 mustcard 供自动选中(S-2 ✅) |
|
| 牌型标签只做「毙」一种;数据层保留 毙/垫/混合出牌 三种标识备扩展,当前不出图 | |
底牌 20x0 的 x 后面是扣底倍数(bottom.multiple);未扣底显示 0(§1.8) |
|
结算两个小字 = 牌局分(grade_jf) / 冲关分(grade_aw) |
|
| 冲关明细走独立的冲关牌型叠加层 | |
| 准备标识用平台的 | |
抓分 角标 = 当前捡分对应判定倍率的实时预览;服务端已下发 curmultiple(S-1 ✅) |
|
倒计时归零停在 0 不隐藏 |
|
底栏 5 按钮:上一轮/出牌历史/明牌/扣底(看埋牌底牌)/底牌(看底牌);术语已统一见 §2.6;可见性按手册 → S-3 |
|
| 数字一律用图片多帧精灵(参考图数字带描边渐变,文字精灵做不出),资源 631–634 全部要出 | |
手牌单排 spacingMin:-78、双排 -65(§6.7) |
|
| 冲关牌型叠加层:全屏半透明遮罩本身即关闭热区,点击遮罩关闭,不另设关闭钮 | |
叠加层需要并列显示奖数(以 naward 为主) |
|
| 冲关牌用精灵复制,张数不设上限 | |
line 支持可选 items 逐项不等宽 |
|
| 自己发的提示需要本地回显(受控例外,理由见 §1.7) | |
埋牌双排 floor(n/2) / ceil(n/2) |
|
EQW_Layout 为权威,配置区手工同步 + 验收检查 |
|
| 建房整体位置尺寸随 Layer 27 定,编辑器建好后回填 | |
等待庄家选主.png 里底牌仍摊着与 design §4 顺序不符 |
|
T-5 手牌排序(已定)
前端排序对齐服务端主牌序(design §3),不另造一套——服务端 class.arith.js 的 order_cards(mainflower, cards) 即权威顺序(从大到小),下发的 pushlist 等字段也已按此排好。
- 选主前(叫分阶段):
flower未定,只有固定主牌(双王 + 全部 2、7)是主牌,其余按花色分组。 - 选主后:
flower确定,正 2 / 正 7 升格、主花色普通牌并入主牌段,必须整体重排。重排动画暂不做(先直接重画),后续可加。 - 主牌段落在左侧——排序从大到小、主牌最大,自然靠左。
7.3 验收检查清单
编码完成后必须逐条核对(每条都对应一处已知易错点):
| # | 检查项 | 依据 |
|---|---|---|
| 1 | cardIdToFrame 通过 §0.4 的 10 条校验样例 |
花色段与 id 段序相反,最易静默画错牌 |
| 2 | 三家显示位映射正确:下家 (mySeat+1)%3 在右上 |
§0.1 |
| 3 | 提示按钮顺序(踩/有分/没分)与 tip 编号(1踩/2没分/3有分)的映射未按下标硬推 |
§1.7 |
| 4 | 气泡帧号 = (箭头向右?3:0)+tip,朝向按头像相对位置取 |
§1.7 / §6.6 |
| 5 | 不可查牌模式下:明牌/已出牌/上一轮 按钮不出现、亮牌面板不弹出(design §8.2 那个遮罩面板,群组 242)、主N/对N 角标不出现。⚠ §2.5 自己的主牌统计条(群组 206)不在此列——它任何模式下都常显 |
design §9 / §2.5 |
| 6 | 投降结算(无 bottom)与解散结算(无 deskfree 的情形)都不崩、不显示空框 |
§1.8 / §1.10 |
| 7 | 解散包从 data.deskfree.data.aset 取值,不是 data.aset |
§1.10 |
| 8 | 倒计时归零不做任何界面推进 | 协议 §0.3 |
| 9 | 冲关牌型叠加层关闭时 SpriteCopyUtils.removeRange 已清理 |
§5.6a |
| 10 | EQW_Layout 与 Game_Modify.PLAYER_INFO_LAYOUT 的头像框坐标一致 |
§6.11 |
| 11 | 丢弃 this.data、仅凭最近一次服务端快照重画,界面完全一致 |
前端 05 §6.2 |
| 12 | 所有布局参数都在配置文件里,业务代码无裸值 | §6 |
| 13 | 底牌 / 埋牌底牌未写反:底牌 按钮读 bottomcards、扣底 按钮读 burycards;内部变量 bottomCards/buryCards 一一对应 |
§2.6 |
| 14 | 叫分按钮配色按档位位置取(非按子数),已叫过的档位置灰 | §1.3 |
| 15 | 自己发的提示本地回显后,收到失败回包时能撤掉 | §1.7 |
| 16 | 自己的主牌统计条有手牌时常显、不受查牌模式与报无主影响;他家 主N/对N 角标只在「可查牌 + 已报无主」时出现 |
§2.5 |
| 17 | 出牌历史按玩家聚合 + 主牌序排序,不是按轮次分组 | §1.7 D-7 |
| 18 | 明牌 按钮在「场上有人报无主」时三家都显示(含报无主那家自己),不是只给自己无主的那家 |
§1.7 D-6 |
7.4 开发前置条件
在本清单的资源补齐前,前端不具备开发条件的部分:
- 美术出图 → §3 全部资源(尤其 3 套牌面 × 60 帧)
- 编辑器建资源与精灵 → §5 全部 ID 回填本文
- D-1 建房界面 → 影响
roomtype拼串与进入牌局的第一步
不受阻、可先行的部分:
client/js/01_SubGame/codes/目录结构与SubGameHooks.js骨架cardIdToFrame转换与其单元测试(§0.4 的 10 条校验样例可直接作为用例)- 收包分发骨架(一 rpc 一处理器)与
data.success判定 - 布局配置骨架与布局求解器(§6)——
kind五型的参数结构与求解逻辑是设计决定、不依赖具体数值,可先写好并用占位坐标跑通,等设计稿到位只改配置值 shared/同步机制
7.5 服务端待补项(需改服务端才能实现的前端需求)
以下 3 条来自本轮确认的需求,当前协议/服务端不支持,需在服务端补齐后前端才能实现。三条都要同步更新 packet_protocol.md。
S-1 · 「当前抓分的倍数」字段 curmultiple —— ✅ 已完成(2026-08-25)
语义:当前捡分对应判定倍率的实时预览——「若此刻结束是几倍」,取绝对值。
当前捡分 grade 相对叫分 call |
判定 | curmultiple |
|---|---|---|
grade == 0 |
庄家:大光 | 3 |
0 < grade < Q |
庄家:小光 | 2 |
Q ≤ grade < call |
庄家:过庄 | 1 |
grade ≥ call |
闲家:升 N 级 | N |
(Q = 小光/过庄分界兼升级级距,常规算子固定 40、爬坡按叫分分段,design §7.2.0 / §7.3.2。)
下发位置(随现有包,不另开推送):shangzhuang、chupai1、chupai2、chupai3、deskinfo.PushCards。
要点:
- 三家同值,整表下发不涉及泄露(
grade本就公开)。 - 与结算包
aset.upgrade同源同算法(get_qvalue+get_upgrade),差别只在这里不含扣底——扣底要到末轮打完才产生。 - 叫分未定时为 0,前端不显示角标。
- 前端不得自算(服务端权威)。
实现:class.paiju.js 新增 get_curmultiple();mod.js / class.export.js 组包处下发。
S-2 · 下发「应当选中的牌」mustcard —— ✅ 已完成(2026-08-25)
语义:下一个出牌者本轮跟牌的必出牌(design §5.2),前端收到后自动选中(上浮),玩家确认后点 出牌。
下发位置:chupai1 / chupai2(给 nextseat)、deskinfo.PushCards(给轮到的那一家)。
可见性(关键):只发给 nextseat 一家。它是该玩家自己手牌的子集,发给他本人不泄露;整表下发会把另两家的手牌结构透露出去(server 红线:发全 ≠ 发多,按可见性下发)。已纳入 test_leak.js 的 CARD_FIELDS 审计白名单。
不下发的情形:
- 非出牌阶段;
- 该座位是本轮首家(自由出牌,无必出);
- 首家是甩牌——甩牌跟牌走
flush_follow_ok的逐分量匹配(design §5.4.4),与get_followcard不是同一条路径,给建议会给错,宁可不发; - 算出的必出牌为空(玩家可自由选)。
实现:class.paiju.js 新增 get_mustcard(seat),内部复用与出牌校验完全相同的 get_followcard,故建议与校验结果天然一致。
不违反「请求包只带意图」:方向是服务端 → 前端的建议,前端仍只回传 cards,合法性最终由服务端校验。
S-3 · 底牌的可见性:按手册办(对应 T-18)—— 已定
结论:按 design 手册,即前述方案 (a)。底栏 底牌 按钮只在能合法看到底牌时可用:
| 谁 | 何时可用 |
|---|---|
| 庄家 | 全程可用(他本来就摸过这 8 张) |
| 闲家 | 仅 70 分坐庄局可用(这 8 张已向全场公示过 3 秒);其余局按钮不显示 |
依据 design §4:非 70 分坐庄时这 8 张只有庄家可见;协议也一致(shangzhuang.bottomcards 闲家仅 70 分时才有,重连包的同名字段标注「只有庄家有此属性」)。
服务端无需改动——现有下发面正好支持这条规则:闲家在非 70 分局本来就收不到数据,按钮不显示即可,不存在「拿到了但不渲染」的泄露风险(服务端红线:下发即泄露)。
S-4 · 拆分 bottomcards 字段名 —— ✅ 已完成(2026-08-25)
两批牌原先共用 bottomcards、只靠所在包区分语义,现已拆分:
| 字段名 | 含义 | 出现在 |
|---|---|---|
bottomcards |
底牌(发牌留桌 8 张) | shangzhuang、deskinfo.ChooseMain、deskinfo.BuryCards |
burycards |
埋牌底牌(庄家埋下 8 张) | maipai、deskinfo.PushCards |
bottom.cards |
埋牌底牌 | 结算包 bottom 分组(分组名已表明是抠底相关,未改名) |
服务端改动:mod.js(maipai 组包)、class.export.js(deskinfo.PushCards),另同步了两处的注释术语。
测试:test/test_leak.js 的 CARD_FIELDS 白名单加入 burycards(否则新字段会静默脱离下发面审计);test/test_rpc.js 新增 11 条正反用例锁死拆分结果。
协议文档:packet_protocol.md §0.0 与相关字段表已更新。
前端取值:直接按字段名区分即可,不再需要「按所在包判断语义」:
// 底牌(发牌留桌 8 张)——底栏「底牌」按钮
data.bottomcards // shangzhuang / ChooseMain / BuryCards
// 埋牌底牌(庄家埋下 8 张)——底栏「扣底」按钮
data.burycards // maipai / PushCards
data.bottom.cards // 结算包
S-5 · 同步 design.md 与 packet_protocol.md 的术语 —— ✅ 已完成(2026-08-25)
术语变更(暗牌→底牌、底牌→埋牌底牌)已在各处生效:
| 文档 / 代码 | 状态 |
|---|---|
docs_dev/二七王-UI资源与精灵清单.md(本文) |
✅ 全文新术语 |
server/games/erqiwang/docs/design/design.md |
✅ 全文 38 处替换;术语表后补「术语变更记录」说明改名缘由 |
server/games/erqiwang/docs/protocol/packet_protocol.md |
✅ 新增 §0.0 术语小节;字段说明同步;字段名随 S-4 拆分 |
mod.js / class.export.js / test/test_leak.js 注释 |
✅ 随 S-4 一并更新 |
docs/compliance/*.md(3 份,24 处) |
⬜ 有意不改——这三份是历次核对的历史记录,反映当时的 design 表述;下轮核对按新 design 重做即可,不追溯修改 |
test/*.js 其余注释(约 14 处) |
⬜ 仅注释、不影响行为,后续顺手清理 |
S-6 · 大局结算的三项分解 —— ✅ 已完成(2026-08-26)
问题:大局结算面板要显示 基础分 / 冲关分 / 傍王分,而原 account 只有「累积得分 + 每局得分数组」。其中傍王分尤其拆不出来——N = 冲关奖数 + 傍王王数 两个来源在求和之后才代入 grade_aw = X×(2Ni−Nj−Nk),事后无法反推各自占比。
解法:在算钱时就拆。把 N 分成 N_冲关(只计庄家)与 N_傍王(勾选后庄闲都算),分别代入同一公式各算一次。公式对 N 线性,故恒有 grade_cg + grade_bw == grade_aw——这条恒等式正好当回归断言。
小局包 aset.seatlist[i] 新增:
| 字段 | 说明 |
|---|---|
grade_cg |
算奖得分里的冲关分量(不含傍王) |
grade_bw |
算奖得分里的傍王分量(未勾傍王时恒 0) |
大局包 account 结构改了(原为二元数组,现为对象数组):
[{ "score": 0, "grades": [], "grade_jf_total": 0, "grade_cg_total": 0, "grade_bw_total": 0 }, …]
| 面板栏位 | 取值 |
|---|---|
| 基础分 | grade_jf_total |
| 冲关分 | grade_cg_total |
| 傍王分 | grade_bw_total |
| 右侧总分大字 | score |
恒等式:grade_jf_total + grade_cg_total + grade_bw_total == score。
顺带解决了小局结算「冲关分」标签的不严谨(见 §0.0):该标签现在应改取 grade_cg 而非 grade_aw,开傍王时也名副其实了。
面板上「基础分」取
grade_jf_total、「总得分」取score。参考图里这两行数值相同、且与右侧大字对不上,是填充假数据所致,不作依据(§0.5)。
S-7 · 明牌按钮的显示条件 —— ✅ 已定论:按手册,服务端无需改动(2026-08-26)
结论:按 design §9.3 手册办——任一玩家报无主后,三家都显示 明牌 按钮,且可随时查看。
| 项 | 取值 |
|---|---|
| 显示条件 | 可查牌模式 + 出牌阶段 + baozhu == 1(任一玩家主牌出空) |
| 谁能看 | 全体三人,包括刚刚报无主的那位自己 |
| 次数 | 不限,随时可点开、可关闭 |
服务端无需改动——mingpai 现有的受理条件 have_baofu()(任一玩家报无主)正好就是这条规则,与 design §9.3 一致。此前我把前端条件收紧成「自己是无主玩家」,比手册严格,反而与服务端校验对不上;现已改回。
之前记录的「有主牌的玩家伪造请求也能拿到明牌数据」这一泄露担忧不成立:按手册他本来就有权查看,服务端受理是正确行为,不是校验缺失。
S-8 · curmultiple 改为带符号 —— ✅ 已完成(2026-08-26)
问题:S-1 实现时取了绝对值,而判定的正负号恰恰是「谁赢」的区分——3 大光与 -3 升3级、2 小光与 -2 升2级、1 过庄与 -1 升1级,取绝对值后三对完全撞在一起,D-8 的过程中动画无从分辨该播哪个。
改法:get_curmultiple 直接返回 get_upgrade 的原值,与结算包 aset.upgrade 完全同口径:
| 值 | 含义 |
|---|---|
3 / 2 / 1 |
庄家 大光 / 小光 / 过庄 |
-N |
闲家升 N 级 |
0 |
叫分未定 |
前端用法:
- 顶部「抓分」角标只关心倍数大小 →
Math.abs(curmultiple)(§2.1)。 - 判定动画靠符号分辨该播哪个(§1.8 D-8),一套映射通吃「过程中」与「结算前」两条路径。
测试(hint 33 → 46 checks):新增两组——一组直接钉住三对「绝对值相同、判定相反」的组合可区分;另一组直接调 get_curmultiple 本身覆盖负数分支。
后一组是补上的测试盲点:原有断言里,算法层的
cm()走的是A.get_upgrade、绕过了get_curmultiple,而端到端那局恰好是大光(正数),取不取绝对值结果一样。第一次反向验证(把实现退回取绝对值)竟然全绿,正是因为这个盲点。补齐后再验,4 条断言立刻失败。
附:本文与其他文档的关系
| 文档 | 关系 |
|---|---|
server/games/erqiwang/docs/design/design.md |
玩法规则权威源。本文引用其条款,不重新定义规则;术语「底牌 / 埋牌底牌」已同步(见 §0.0) |
server/games/erqiwang/docs/protocol/packet_protocol.md |
协议字段权威源。本文的「渲染什么」全部溯源到具体字段 |
docs/client/development-guide/ |
前端规范权威源。ID 范围、组件范式、红线均以其为准 |
docs_dev/uiref/*.png |
参考图,16 张(牌桌态 + 叫分按钮面板 + 大局结算 + 强甩失败 + 等待庄家选主 + 1 张建房样式范式,末者内容属他游戏、不可照抄) |
client/js/gameabc-framework/ui/AlignmentUtils.js |
布局求解的框架能力。§6 的配置参数名与其入参一一对应,配置可原样喂入 |
client/js/gameabc-framework/ui/SpriteCopyUtils.js |
精灵复制。用于冲关牌型、大局结算玩家栏、出牌历史 / 明牌(§5.6a 判据表) |
client/js/gameabc-framework/templates/*.template.js |
常量文件写法蓝本。本清单落地为常量文件时按其格式 |