diff --git a/client/js/01_SubGame/codes/config/ImageResources.js b/client/js/01_SubGame/codes/config/ImageResources.js index 2a1949a..735baa0 100644 --- a/client/js/01_SubGame/codes/config/ImageResources.js +++ b/client/js/01_SubGame/codes/config/ImageResources.js @@ -280,23 +280,31 @@ var EQW_Images = EQW_Images || { LINE_DIVIDER: 613, //===================== §3.6 数字与符号 ===================== + // + //【2026-08-26 出图方式变更】以下 NUM_* 数字类资源【不是】编辑器里配好帧数的多帧资源, + //而是【等宽连续排列的一张图】:所有字符横向排成一行、每格等宽,图里不留间隙。 + //代码不用 setFrame(一个精灵一次只显示一帧=只能显示一位数),改为按字宽裁源矩形叠绘: + //第 idx 格的源矩形 = (idx * 单字宽, 0, 单字宽, 单字高),由框架 NumberRenderer 逐位画在 + //【同一个】精灵上,故一个多位数只需一个精灵。样式(单字宽高/字间距/对齐/绘制区宽)见 + //EQW_Layout.NUM_STYLE.*(LayoutConstants.js),本处只记出图规格。 + //美术出图请严格按「字符排列顺序 + 单字符宽高 + 整图尺寸」执行,字符必须等宽对齐格子。 //用途:倒计时数字(带描边/渐变美术字) - //帧数:10 - //帧说明:帧1–10 = 0–9 - //尺寸:44×60 + //排列:等宽连续一行,字符顺序 0 1 2 3 4 5 6 7 8 9(索引 0–9) + //单字符尺寸:44×60 + //整图尺寸:440×60(10 格 × 44) NUM_COUNTDOWN: 631, //用途:结算得分数字(赢,橙,带描边/渐变美术字) - //帧数:12 - //帧说明:帧1–10 = 0–9,帧11 = +,帧12 = - - //尺寸:46×62 + //排列:等宽连续一行,字符顺序 0 1 2 3 4 5 6 7 8 9 + -(索引 0–9 为数字,10 = 「+」,11 = 「-」) + //单字符尺寸:46×62 + //整图尺寸:552×62(12 格 × 46) NUM_RESULT_WIN: 632, //用途:结算得分数字(输,蓝,带描边/渐变美术字) - //帧数:12 - //帧说明:帧1–10 = 0–9,帧11 = +,帧12 = - - //尺寸:46×62 + //排列:与 NUM_RESULT_WIN 完全一致——等宽连续一行,0–9 后接 「+」「-」(共 12 格),仅配色不同 + //单字符尺寸:46×62 + //整图尺寸:552×62(12 格 × 46) NUM_RESULT_LOSE: 633, //用途:判定结果动画(大光/小光/过庄/升N级/投降)——帧动画资源,播放参数进 AnimationConfigs【待设计 D-8】 @@ -306,15 +314,16 @@ var EQW_Images = EQW_Images || { ANI_JUDGE: 634, //用途:叫分档位的分数数字(深棕描边美术字,带描边/渐变,文字精灵做不出此效果) - //帧数:10 - //帧说明:帧1–10 = 0–9 - //尺寸:30×40 + //排列:等宽连续一行,字符顺序 0 1 2 3 4 5 6 7 8 9(索引 0–9) + //单字符尺寸:30×40 + //整图尺寸:300×40(10 格 × 30) + //说明:14 个档位中 13 个是两位数(70…10),靠叠绘一个精灵画两位,见 Sprites_Action.js 的 CALL_BTN_NUM_1..14 NUM_CALL_SCORE: 635, - //用途:选主面板花色张数数字(美术单独出图,字号配色与以上几套不同;十位/个位各占一个精灵,见 Sprites_Action.js) - //帧数:10 - //帧说明:帧1–10 = 0–9 - //尺寸:24×32(估值,与选主按钮 128×55 协调估算,出图前须与最终设计稿核对) + //用途:选主面板花色张数数字(美术单独出图,字号配色与以上几套不同;一个花色一个精灵,见 Sprites_Action.js) + //排列:等宽连续一行,字符顺序 0 1 2 3 4 5 6 7 8 9(索引 0–9) + //单字符尺寸:24×32(估值,与选主按钮 128×55 协调估算,出图前须与最终设计稿核对) + //整图尺寸:240×32(10 格 × 24) NUM_MAIN_SUIT_COUNT: 636, //===================== §3.7 浮层与气泡 ===================== diff --git a/client/js/01_SubGame/codes/config/Layout_Action.js b/client/js/01_SubGame/codes/config/Layout_Action.js index 44555d9..2eb2472 100644 --- a/client/js/01_SubGame/codes/config/Layout_Action.js +++ b/client/js/01_SubGame/codes/config/Layout_Action.js @@ -18,12 +18,14 @@ EQW_Layout.CALL_BTN_GRID = { anchor: 'center', fillOrder: 'row' }; -//档位分数文字:贴对应档位按钮居中。CALL_BTN_1..14 是 14 个固定精灵,但本节点是共用模板, -//target 由调用方按第几档注入(不预置单一 target)。宽高随数字位数变化,清单未给固定值, -//资源 NUM_CALL_SCORE 单字位 30×40 仅供参考,不作为本节点的 w/h +//档位分数数字:贴对应档位按钮居中。CALL_BTN_1..14 是 14 个固定精灵,但本节点是共用模板, +//target 由调用方按第几档注入(不预置单一 target)。 +//2026-08-26:改为图集叠绘(NumberRenderer),一个精灵画完整分数,故宽高【不再随位数变化】—— +//直接取 NUM_STYLE.CALL_SCORE 的绘制区宽与单字高(SSOT:数值只在 LayoutConstants 定义一处) EQW_Layout.CALL_BTN_SCORE_TEXT = { kind: 'attach', targetKind: 'sprite', hAlign: 'center', vAlign: 'middle', offsetY: 4, - runtime: ['target', 'w', 'h'] + w: EQW_Layout.NUM_STYLE.CALL_SCORE.width, h: EQW_Layout.NUM_STYLE.CALL_SCORE.charHeight, + runtime: ['target'] }; //档位子数角标:贴对应档位按钮右上角,纯文字无底图,清单未给宽高(同上,调用方注入 target) @@ -49,15 +51,11 @@ EQW_Layout.MAIN_SUIT_LINE = { itemWidth: 128, itemHeight: 55, spacing: 9, anchor: 'left' }; -//张数数字(十位):贴对应花色按钮下方偏左,资源 NUM_MAIN_SUIT_COUNT 24×32(十位为 0 时该精灵隐藏,调用方注入 target) -EQW_Layout.MAIN_SUIT_COUNT_TENS = { - kind: 'attach', targetKind: 'sprite', hAlign: 'center', vAlign: 'bottom', offsetX: -12, offsetY: -6, w: 24, h: 32, - runtime: ['target'] -}; - -//张数数字(个位):贴对应花色按钮下方偏右,紧邻十位,资源 NUM_MAIN_SUIT_COUNT 24×32(调用方注入 target) -EQW_Layout.MAIN_SUIT_COUNT_ONES = { - kind: 'attach', targetKind: 'sprite', hAlign: 'center', vAlign: 'bottom', offsetX: 12, offsetY: -6, w: 24, h: 32, +//张数数字:贴对应花色按钮下方居中,一个花色【一个】精灵(图集叠绘,两位数由 NumberRenderer 逐位画)。 +//2026-08-26:原十位/个位两节点合并为本节点;宽高取 NUM_STYLE.MAIN_SUIT_COUNT(SSOT,调用方注入 target) +EQW_Layout.MAIN_SUIT_COUNT = { + kind: 'attach', targetKind: 'sprite', hAlign: 'center', vAlign: 'bottom', offsetY: -6, + w: EQW_Layout.NUM_STYLE.MAIN_SUIT_COUNT.width, h: EQW_Layout.NUM_STYLE.MAIN_SUIT_COUNT.charHeight, runtime: ['target'] }; diff --git a/client/js/01_SubGame/codes/config/Sprites_Action.js b/client/js/01_SubGame/codes/config/Sprites_Action.js index 4fe344f..0ae998a 100644 --- a/client/js/01_SubGame/codes/config/Sprites_Action.js +++ b/client/js/01_SubGame/codes/config/Sprites_Action.js @@ -36,7 +36,9 @@ EQW_Sprites.CallPanelView = { CALL_BTN_13: 1615, CALL_BTN_14: 1616, - //—— 14 档位分数数字(图片型数字精灵),资源 EQW_Images.NUM_CALL_SCORE,帧1–10=数字0–9,按档位分数(70..5)拼帧 —— + //—— 14 档位分数数字(图集叠绘数字精灵),资源 EQW_Images.NUM_CALL_SCORE,样式 EQW_Layout.NUM_STYLE.CALL_SCORE。 + // 一个精灵画完整档位分数:NumberRenderer 按字宽从等宽连续数字图里逐位裁源矩形叠绘, + // 故 14 档(其中 13 档是两位数)各只需【一个】精灵(2026-08-26 改,原多帧 setFrame 一次只显示一位、两位数根本画不出)—— CALL_BTN_NUM_1: 1617, CALL_BTN_NUM_2: 1618, CALL_BTN_NUM_3: 1619, @@ -78,9 +80,11 @@ EQW_Sprites.CallPanelView = { //以下键号在源清单中被显式判定「不需要」,本文件不占用,留空号以便追溯(美术改一张图 5 帧出图, //花色图标与右上角角标底已并入 BTN_SUIT_CHOOSE 各帧,2026-08-26): // 1656–1659 MAIN_SUIT_ICON_1..4 —— 花色图标并入 BTN_SUIT_CHOOSE 帧1–4 -// 1660–1663 MAIN_SUIT_COUNT_1..4 —— 原文字精灵,改为下方 8 个数字图片精灵(张数最多两位) +// 1660–1663 MAIN_SUIT_COUNT_1..4 —— 原文字精灵,改为下方数字图片精灵(键名沿用,ID 改到 1674–1677) // 1664–1667 MAIN_SUIT_PAIR_BG_1..4 —— 角标底并入 BTN_SUIT_CHOOSE 帧1–4 // 1673 MAIN_BTN_SURRENDER_TEXT —— 「投降」二字并入 BTN_SUIT_CHOOSE 帧5 +// 1678–1681 原 MAIN_SUIT_COUNT_3/4_TENS/ONES —— 张数改为「一个花色一个精灵」(图集叠绘,见下), +// 上一轮的十位/个位拆分作废,空出的 4 个 ID 不复用(2026-08-26) EQW_Sprites.ChooseMainView = { Layer: EQW_Layers.ACTION, //104 @@ -103,16 +107,14 @@ EQW_Sprites.ChooseMainView = { MAIN_SUIT_PAIR_TEXT_3: 1670, MAIN_SUIT_PAIR_TEXT_4: 1671, - //—— 8 个花色张数数字图片精灵:该花色在庄家手中的张数(两副牌单花色最多 26 张,两位数), - // 资源 EQW_Images.NUM_MAIN_SUIT_COUNT,帧 = 数字+1(帧1–10=0–9),十位为 0 时该精灵隐藏、个位始终显示 —— - MAIN_SUIT_COUNT_1_TENS: 1674, - MAIN_SUIT_COUNT_1_ONES: 1675, - MAIN_SUIT_COUNT_2_TENS: 1676, - MAIN_SUIT_COUNT_2_ONES: 1677, - MAIN_SUIT_COUNT_3_TENS: 1678, - MAIN_SUIT_COUNT_3_ONES: 1679, - MAIN_SUIT_COUNT_4_TENS: 1680, - MAIN_SUIT_COUNT_4_ONES: 1681, + //—— 4 个花色张数数字精灵(图集叠绘,一花色一个):该花色在庄家手中的张数 + // (两副牌单花色最多 26 张,两位数),资源 EQW_Images.NUM_MAIN_SUIT_COUNT, + // 样式 EQW_Layout.NUM_STYLE.MAIN_SUIT_COUNT;NumberRenderer 逐位裁源矩形画在同一精灵上, + // 不再需要十位/个位各一个精灵(2026-08-26)—— + MAIN_SUIT_COUNT_1: 1674, + MAIN_SUIT_COUNT_2: 1675, + MAIN_SUIT_COUNT_3: 1676, + MAIN_SUIT_COUNT_4: 1677, MAIN_BTN_SURRENDER: 1672 //图片:「投降」按钮,资源 EQW_Images.BTN_SUIT_CHOOSE 帧5(已含底与「投降」字) } diff --git a/client/js/01_SubGame/codes/config/Sprites_Result.js b/client/js/01_SubGame/codes/config/Sprites_Result.js index 93eeb12..c54a9e5 100644 --- a/client/js/01_SubGame/codes/config/Sprites_Result.js +++ b/client/js/01_SubGame/codes/config/Sprites_Result.js @@ -97,6 +97,10 @@ EQW_Sprites.AccountView = { ACC_TPL_AVATAR: 1912, //模板:头像,运行时贴玩家头像 ACC_TPL_TEXT: 1913, //模板:通用文字(昵称/ID/各项分数,一行一个) ACC_TPL_SCORE_NUM: 1914, //模板:右侧总分大字(数字精灵),资源 EQW_Images.NUM_RESULT_WIN / NUM_RESULT_LOSE + //【2026-08-26 待定】NUM_RESULT_* 已改为等宽连续图 + 图集叠绘(见 ImageResources.js §3.6), + //而本精灵是【复制模板】、运行时 ID 为字符串,SpriteEventController.registerDraw 只收数字 ID、 + //复制精灵也不单独收绘制事件 → 无法用 NumberRenderer。玩家栏总分的呈现方式待 F 阶段定 + //(改文字精灵 / 改预置精灵 / 由父容器统一叠绘),此处先记风险不改结构 ACC_TPL_DIVIDER: 1915, //模板:行间分隔线,资源 EQW_Images.LINE_DIVIDER //—— 底部 4 个功能按钮 —— diff --git a/client/tests/test_constants.js b/client/tests/test_constants.js index 358bfc8..5b865e8 100644 --- a/client/tests/test_constants.js +++ b/client/tests/test_constants.js @@ -43,7 +43,7 @@ const index = EQW_SpriteIndex.build(EQW_Sprites); const spriteVals = Object.keys(index).map(k => index[k]); // 钉住精确数量:松下界(如 >200)删掉整个 View 都还能通过。 // 增删精灵时连同本数字一起改——有意的顺手更新,不是有意的就红给你看 -t.eq('精灵总数', spriteVals.length, 382); +t.eq('精灵总数', spriteVals.length, 378); const spriteOk = spriteVals.every(v => v >= 1001 && v <= 2999); if (!spriteOk) { console.log('越界精灵: ' + JSON.stringify(spriteVals.filter(v => v < 1001 || v > 2999))); } t.eq('精灵落在 1001-2999', spriteOk, true); @@ -238,7 +238,7 @@ t.eq('全部布局节点可求解、矩形数与坐标都对', solveFailures, [] // 钉住节点总数:松下界(如 >40)删掉整个 View 都还能通过,任何意外的增删都要在这里可见。 // 增删布局节点时,连同本数字一起改——改动是有意的就顺手更新,不是有意的就红给你看 -t.eq('布局节点总数', allNodes.length, 62); +t.eq('布局节点总数', allNodes.length, 61); // ---- 布局文件是纯数据:不含函数 ---- const funcs = []; @@ -319,4 +319,30 @@ t.eq('roomtype 位号铺满 0-4', Object.keys(bitsSeen).map(Number).sort((a, b) t.eq('CARD_SIZE.' + size + ' 的资源存在', EQW_Images.hasOwnProperty(EQW_Layout.CARD_SIZE[size].res), true); }); +// ---- 数字样式(图集叠绘):资源键存在、字段齐全合法 ---- +// 与 CARD_SIZE 同一约定:纯数据配置只存资源【键名】,调用方用 EQW_Images[res] 取真实 ID +const numStyleProblems = []; +Object.keys(EQW_Layout.NUM_STYLE).forEach(key => { + const s = EQW_Layout.NUM_STYLE[key]; + if (!EQW_Images.hasOwnProperty(s.res)) { numStyleProblems.push(key + ' 的资源键不存在: ' + s.res); } + ['charWidth', 'charHeight', 'width'].forEach(f => { + if (typeof s[f] !== 'number' || s[f] <= 0) { numStyleProblems.push(key + '.' + f + ' 非正数: ' + s[f]); } + }); + if (typeof s.spacing !== 'number') { numStyleProblems.push(key + '.spacing 非数字: ' + s.spacing); } + if (['left', 'center', 'right'].indexOf(s.align) < 0) { numStyleProblems.push(key + '.align 非法: ' + s.align); } + // 绘制区至少放得下一个字符,否则这套样式一开始就画不出东西 + if (s.width < s.charWidth) { numStyleProblems.push(key + ' 绘制区比单字还窄'); } +}); +if (numStyleProblems.length) { console.log('数字样式问题:\n ' + numStyleProblems.join('\n ')); } +t.eq('NUM_STYLE 资源键存在且字段合法', numStyleProblems, []); + +// 引用 NUM_STYLE 的布局节点必须与样式同源(SSOT:数值只在 LayoutConstants 定义一处, +// 有人在 Layout_Action.js 里手抄一个不同的数就在这里变红) +[['CALL_BTN_SCORE_TEXT', 'CALL_SCORE'], ['MAIN_SUIT_COUNT', 'MAIN_SUIT_COUNT']].forEach(pair => { + const node = EQW_Layout[pair[0]]; + const st = EQW_Layout.NUM_STYLE[pair[1]]; + t.eq(pair[0] + '.w 与 NUM_STYLE.' + pair[1] + '.width 同源', node.w, st.width); + t.eq(pair[0] + '.h 与 NUM_STYLE.' + pair[1] + '.charHeight 同源', node.h, st.charHeight); +}); + process.exit(t.done('constants') ? 0 : 1); diff --git a/client/tests/test_spriteindex.js b/client/tests/test_spriteindex.js index 408daf7..d803d27 100644 --- a/client/tests/test_spriteindex.js +++ b/client/tests/test_spriteindex.js @@ -83,6 +83,6 @@ let realIndex = {}; try { realIndex = EQW_SpriteIndex.build(EQW_Sprites); } catch (e) { realOk = false; console.log('建索引失败: ' + e.message); } t.eq('真实精灵常量无重复键', realOk, true); // 钉住精确数量(与 test_constants.js 同一个数):松下界删掉整个 View 都还能通过 -t.eq('真实精灵数量', Object.keys(realIndex).length, 382); +t.eq('真实精灵数量', Object.keys(realIndex).length, 378); process.exit(t.done('spriteindex') ? 0 : 1);