如何在CraftyJS 0.9.0中让视口正确居中适配静态场景?
CraftyJS 0.9.0 场景缩放适配后无法居中的问题排查与解决
我来帮你梳理这个问题的原因,以及对应的修复方案:
问题重现
你想要实现固定尺寸(640x960)的场景在窗口中自适应缩放并居中,当前缩放逻辑正常,但调用Crafty.viewport.centerOn()后场景无法正确居中。你的完整代码如下:
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/crafty/0.9.0/crafty.js"></script>
CSS
body, html { margin: 0; padding: 0; }
JavaScript
const staticSceneWidth = 640 const staticSceneHeight = 960 Crafty.init() Crafty.background('rgb(127,127,127)') // grid of four rectangles // top left Crafty.e('2D, Canvas, Color, Fourway') .attr({ x: 0, y: 0, w: 320, h: 480 }) .color('red') // top right Crafty.e('2D, Canvas, Color, Fourway') .attr({ x: 320, y: 0, w: 320, h: 480 }) .color('green') // bottom left Crafty.e('2D, Canvas, Color, Fourway') .attr({ x: 0, y: 480, w: 320, h: 480 }) .color('blue') // bottom right Crafty.e('2D, Canvas, Color, Fourway') .attr({ x: 320, y: 480, w: 320, h: 480 }) .color('yellow') // dummy for centering const scene = Crafty.e('2D').attr({ x: 0, y: 0, w: 640, h: 960 }) function fitViewportToScene() { const heightScale = Crafty.viewport.height / staticSceneHeight const widthScale = Crafty.viewport.width / staticSceneWidth if (heightScale < widthScale) { Crafty.viewport.scale(heightScale) } else { Crafty.viewport.scale(widthScale) } Crafty.viewport.centerOn(scene, 0) } window.onresize = fitViewportToScene fitViewportToScene()
问题原因
在CraftyJS 0.9.0中,Crafty.viewport.centerOn()的设计逻辑是将目标实体的中心对齐到视口的逻辑中心,但这个逻辑中心的计算并没有考虑你之前设置的视口缩放比例。当你调用Crafty.viewport.scale()修改缩放因子后,视口的显示比例变了,但centerOn仍然基于原始的未缩放坐标系统计算偏移量,导致场景的实际显示位置偏离窗口中心。
简单说:缩放操作改变了场景的显示大小,但centerOn没有同步适配这个缩放比例,所以算出的居中位置是错误的。
修复方案
我们需要手动计算视口的偏移量,替代centerOn来实现真正的居中。核心思路是:先确定缩放比例,计算缩放后场景与窗口的留白,再将视口偏移到对应位置(注意要转换回世界坐标系统)。
修改后的fitViewportToScene函数如下:
function fitViewportToScene() { const staticSceneWidth = 640; const staticSceneHeight = 960; // 计算宽高缩放比,取较小值作为最终缩放比例 const heightScale = Crafty.viewport.height / staticSceneHeight; const widthScale = Crafty.viewport.width / staticSceneWidth; const scale = Math.min(heightScale, widthScale); // 应用缩放比例到视口 Crafty.viewport.scale(scale); // 计算缩放后场景的实际显示尺寸 const scaledSceneWidth = staticSceneWidth * scale; const scaledSceneHeight = staticSceneHeight * scale; // 计算窗口与缩放后场景的留白,再转换为世界坐标下的偏移量 const offsetX = (Crafty.viewport.width - scaledSceneWidth) / 2; const offsetY = (Crafty.viewport.height - scaledSceneHeight) / 2; // 设置视口的世界坐标偏移(需要除以缩放比例,转换回世界坐标系) Crafty.viewport.x = -offsetX / scale; Crafty.viewport.y = -offsetY / scale; }
关键细节解释
- 我们直接取
Math.min(heightScale, widthScale)来简化缩放比例的判断,逻辑和之前一致,但更简洁 Crafty.viewport.x和y是世界坐标的偏移值,不是窗口像素偏移。所以我们需要把窗口的留白偏移除以缩放比例,才能得到正确的世界坐标偏移,让场景在窗口中居中- 现在你可以移除那个用于居中的dummy实体
scene了,因为我们不再依赖它来计算居中位置
修改后,无论窗口是横向还是纵向,场景都会自动缩放并完美居中在窗口内,调整窗口大小时也能实时适配。
内容的提问来源于stack exchange,提问作者maiermic
相关产品推荐
相关产品推荐

