You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 14:38:12