资讯动态

Phaser 3.60 BitmapText 增强详解:行距控制、显示尺寸、边界组件与字距(Kerning)修复

发布时间:2026/9/19 4:36:43 来源:尧图企业网站定制
Phaser 3.60 BitmapText 增强详解行距控制、显示尺寸、边界组件与字距Kerning修复【免费下载链接】phaserPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.项目地址: https://gitcode.com/gh_mirrors/ph/phaser本文以 Phaser 3.60.0 变更日志中 BitmapTextGameObject.md 的内容为骨架系统讲解该版本为BitmapText游戏对象带来的四项核心变化新增setLineSpacing行距控制、新增只读属性displayWidth/displayHeight并接入GetBounds组件、GetBitmapTextSize结果中新增字符索引idx以及字距kerning偏移在 WebGL 与 Canvas 两种渲染器下的修复。读完本文你将能够利用行距精确排版多行位图字体文本正确获取 BitmapText 的尺寸与边界包括放入Container之后的场景并理解 kerning 从字体解析、尺寸计算到逐字符渲染的完整链路。一、3.60 中 BitmapText 更新总览在 changelog/v3/3.60/BitmapTextGameObject.md 中Phaser 3.60.0 对BitmapText的变更可分为三类类别变更内容说明新特性BitmapText.setLineSpacing方法及lineSpacing属性控制多行位图文本的垂直行距可正可负用法与Text对象一致更新新增只读属性displayWidth、displayHeight使 BitmapText 能正确配合GetBounds组件使用更新BitmapText 接入GetBounds组件修复 #6237可在Container中正确获取尺寸更新GetBitmapTextSize结果新增idx字段字符在原始文本中的索引不受自动换行影响修复逐字符 kerning 偏移渲染时正确应用字距偏移修复GetBitmapTextSize中的 kerning 计算WebGL 与 Canvas 渲染结果一致下文逐一展开每个变更的用法、源码实现与验证方式。二、行距控制setLineSpacing 与 lineSpacing2.1 API 形态3.60 之前多行 BitmapText 的行与行之间只能使用字体文件自身定义的lineHeight间距不可调整。3.60 起可以通过两种方式控制// 方式一链式方法默认值 0 bitmapText.setLineSpacing(8); // 方式二直接读写属性 bitmapText.lineSpacing 8;关键约定该值会叠加到字体本身的 lineHeight 之上用于计算整体行高可正可负正值加大行距负值收紧行距仅对多行文本以\r、\n或\r\n分隔生效单行文本没有影响传入undefined时默认重置为0。2.2 源码实现方法定义位于 src/gameobjects/bitmaptext/static/BitmapText.jssetLineSpacing: function (spacing) { if (spacing undefined) { spacing 0; } this.lineSpacing spacing; return this; },内部通过lineSpacing属性同一文件写入私有字段_lineSpacing并将_dirty标记为true从而触发后续尺寸重算lineSpacing: { set: function (value) { this._lineSpacing value; this._dirty true; }, get: function () { return this._lineSpacing; } },_lineSpacing字段本身从 3.60.0 开始引入src/gameobjects/bitmaptext/static/BitmapText.js。在序列化方法toJSON中lineSpacing也会随font、text、fontSize、letterSpacing、align一起被导出同一文件便于场景数据持久化。2.3 行距在尺寸计算中的生效点行距真正参与排版的位置在 src/gameobjects/bitmaptext/GetBitmapTextSize.js。当遍历到换行符charCode 10时通过以下公式计算下一行文字的 y 偏移yAdvance (lineHeight lineSpacing) * currentLine;也就是说第 N 行文字相对顶部的偏移是(lineHeight lineSpacing) × N。这也解释了为什么行距对单行文本无影响——只有出现第二个换行符时currentLine才会递增。2.4 实战示例this.add.bitmapText(100, 100, desyrel, First Line\nSecond Line\nThird Line) .setLineSpacing(12); // 三行文本行距加大 12 像素将行距设为负值可让多行文本更加紧凑bitmapText.setLineSpacing(-4); // 行距收紧 4 像素三、displayWidth / displayHeight 与 GetBounds 组件3.1 背景Issue #62373.60 之前BitmapText 在放入Container后Container无法正确计算其边界尺寸因为 BitmapText 缺少GetBounds组件所依赖的displayWidth/displayHeight属性。3.60 为 BitmapText 补齐了这两个只读属性并接入GetBounds组件src/gameobjects/bitmaptext/static/BitmapText.js 的 Mixins 列表包含Components.GetBounds。3.2 属性语义displayWidth源码与displayHeight源码均为只读属性返回考虑了缩放因子的显示尺寸内部委托给width/height的取值器它们基于getTextBounds计算出的global尺寸允许赋值setter 会先将 X/Y 方向缩放重置为 1再根据目标尺寸反算scaleX/scaleY等价于“以目标显示尺寸反向设定缩放”文档注释明确标注readonly推荐通过setDisplaySize3.61或直接设置scale来控制显示大小。3.3 GetBounds 组件提供的能力接入后BitmapText 拥有了 src/gameobjects/components/GetBounds.js 提供的一整套边界查询方法getBounds()返回轴对齐包围矩形AABB会考虑旋转与父Container变换getTopLeft()/getTopRight()/getBottomLeft()/getBottomRight()四角坐标getCenter()/getTopCenter()/getLeftCenter()等中心与边中点所有方法都支持includeParent参数以纳入父Container的变换矩阵。这些方法在内部均依赖this.displayWidth与this.displayHeight计算参见 GetBounds.js 的getCenter实现这正是新增两个属性的意义所在。3.4 实战示例const label this.add.bitmapText(200, 150, desyrel, Score: 100); // 直接读取显示尺寸已包含 scale console.log(label.displayWidth, label.displayHeight); // 获取边界矩形用于碰撞检测或布局 const rect label.getBounds(); console.log(rect.x, rect.y, rect.width, rect.height); // 放入 Container 后依然能正确计算 const group this.add.container(0, 0, [label]); const boundsInGroup label.getBounds(); // 已计入父容器变换四、GetBitmapTextSize 新增字符索引 idx4.1 背景GetBitmapTextSize在计算尺寸时会把超长文本按maxWidth自动换行src/gameobjects/bitmaptext/GetBitmapTextSize.js。换行会向文本中插入\n导致“换行后的字符下标”与“原始文本中的字符下标”不一致。原有i字段表示的是换行处理后的索引无法定位回原始字符串。4.2 idx 字段3.60 起characters数组中的每个BitmapTextCharacter对象新增idx字段src/gameobjects/bitmaptext/GetBitmapTextSize.jscharacters.push({ i: charIndex, // 换行后的索引原有 idx: i, // 原始文本中的索引3.60 新增 char: text[i], code: charCode, // ... });类型定义位于 src/gameobjects/bitmaptext/typedefs/BitmapTextCharacter.jsi该字符在换行后文本中的索引idx该字符在原始文本不包含自动换行中的索引。4.3 使用场景当maxWidth触发自动换行时idx可用来把字符级信息如逐字染色、命中检测映射回用户输入的原字符串const bounds bitmapText.getTextBounds(); bounds.characters.forEach((char) { // char.idx 指向原始文本下标不受换行影响 console.log(char.idx, char.char, char.x, char.y); });注意BitmapTextCharacter中x/y已按字号缩放但尚未换算为游戏对象本地坐标w/h为字形尺寸t/r/b分别表示所在行的顶部、字符右沿与行底部typedefs 说明。五、字距Kerning修复从解析到渲染5.1 问题3.60 修复了两个 kerning 相关问题渲染阶段BitmapText 渲染时没有应用逐字符的 kerning 偏移尺寸计算阶段GetBitmapTextSize中的 kerning 计算有误导致文本尺寸与实际绘制不一致。修复后WebGL 与 Canvas 两种渲染器的表现统一。5.2 字体解析kerning 数据的来源kerning 数据来自位图字体 XML 的kerning节点解析逻辑在 src/gameobjects/bitmaptext/ParseXMLBitmapFont.jsvar kernings xml.getElementsByTagName(kerning); for (i 0; i kernings.length; i) { var kern kernings[i]; var first getValue(kern, first); var second getValue(kern, second); var amount getValue(kern, amount); data.chars[second].kerning[first] amount; }每个字形对象持有kerning映射表键为前一个字符的 charCode在构造字形时初始化为空对象ParseXMLBitmapFont.js。5.3 尺寸计算kerning 的正确应用GetBitmapTextSize遍历字符时会查询当前字形相对上一个字符的 kerning 偏移src/gameobjects/bitmaptext/GetBitmapTextSize.jsif (lastGlyph ! null) { var kerningOffset glyph.kerning[lastCharCode]; x (kerningOffset ! undefined) ? kerningOffset : 0; }该偏移同时参与字符宽度计算与 x 方向推进GetBitmapTextSize.jsvar charWidth glyph.xOffset glyph.xAdvance ((kerningOffset ! undefined) ? kerningOffset : 0); // ... xAdvance glyph.xAdvance letterSpacing ((kerningOffset ! undefined) ? kerningOffset : 0);5.4 渲染BatchChar 逐字符提交WebGL 渲染路径中每个字符通过 src/gameobjects/bitmaptext/BatchChar.js 提交为四边形var x (char.x - src.displayOriginX) offsetX; var y (char.y - src.displayOriginY) offsetY; var xw x char.w; var yh y char.h;由于char.x已在尺寸计算阶段5.3 节计入 kerning 偏移渲染时直接使用该位置即可从而保证“量出来”的尺寸与“画出来”的结果一致。Canvas 渲染器同理统一消费GetBitmapTextSize的输出。5.5 验证测试用例仓库测试 tests/gameobjects/bitmaptext/GetBitmapTextSize.test.js 中包含对 kerning 的精确断言describe(kerning)分组字形 B 声明相对 AcharCode 65的 kerning 偏移为-2期望AB的整体宽度为18而非无 kerning 时的20且字符 B 的x为8。同一测试文件还覆盖了 3.60 新增特性的相关行为lineSpacing生效A\nB且lineSpacing4时第二行 y 偏移为(16 4) × 1 20整体高度为36describe(multi-line text)maxWidth自动换行写入wrappedTextdescribe(word wrap)round、updateOrigin、letterSpacing、对齐等既有行为回归describe(letter spacing)、describe(alignment)等。六、升级与使用建议行距排版3.60 起多行 BitmapText 的垂直节奏可以像Text一样自由控制优先使用setLineSpacing而不是手动拼接带空行的字符串布局与碰撞新接入的GetBounds组件让 BitmapText 在Container中也能得到正确边界涉及 UI 面板、对话框、按钮文字对齐时可直接使用getBounds()/getCenter()等方法字符级操作如果需要把字符坐标映射回原始输入字符串例如逐字描边、点击判字优先使用characters[].idx而非i字体文件kerning 修复后携带kerning节点的 BMFont 类字体在两种渲染器下表现一致若发现个别字符间距异常可从字体 XML 的first/second/amount节点数据入手排查。完整的 3.60.0 变更汇总可查阅 changelog/v3/3.60/CHANGELOG-v3.60.md。【免费下载链接】phaserPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.项目地址: https://gitcode.com/gh_mirrors/ph/phaser创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价