用途
本技能用于在使用 Phaser 4 开发游戏时实现响应式设计,处理显示缩放、居中、全屏、屏幕方向以及尺寸变化后的重排。核心对象是 ScaleManager,可在游戏实例上通过 game.scale 访问,也可在 Scene 内通过 this.scale 访问。
主要能力
ScaleManager 负责根据配置和父容器尺寸计算画布大小,并在保持游戏内部尺寸不变的前提下,通过 CSS 缩放画布完成适配。其内部由三个 Size 组件驱动计算:gameSize 为配置中的原始游戏尺寸,用于世界边界和相机;baseSize 为自动取整后的游戏尺寸,设置 canvas 的实际 width/height 属性;displaySize 为应用缩放模式、父容器边界和 zoom 后得到的 CSS 显示尺寸,设置 canvas 的 style 宽高。输入坐标转换依赖 displayScale(baseSize 与 canvasBounds 的比值)。
缩放模式通过 scale.mode 配置,可选 NONE、WIDTH_CONTROLS_HEIGHT、HEIGHT_CONTROLS_WIDTH、FIT、ENVELOP、RESIZE、EXPAND。FIT 会在父容器内保持宽高比缩放,可能产生留白;ENVELOP 会覆盖整个父容器并可能裁剪内容;RESIZE 会直接把画布调整为父容器大小,形成 1:1 像素映射;EXPAND 是 RESIZE 与 FIT 的混合。居中通过 scale.autoCenter 配置,可选 NO_CENTER、CENTER_BOTH、CENTER_HORIZONTALLY、CENTER_VERTICALLY,通过设置画布的 marginLeft 和 marginTop 实现。
缩放倍率通过 scale.zoom 配置,可使用 NO_ZOOM、ZOOM_2X、ZOOM_4X、MAX_ZOOM 或任意数值,只影响 CSS 显示尺寸,不改变画布分辨率。MAX_ZOOM 会自动计算能放入父容器的最大整数倍率。
屏幕方向可通过 game.scale.orientation 读取,常量包括 landscape-primary、landscape-secondary、portrait-primary、portrait-secondary,并有 isPortrait、isLandscape、isGamePortrait、isGameLandscape 等便捷布尔值。
使用方式
最常见的响应式配置是 FIT 模式配合居中:
const config = {
type: Phaser.AUTO,
scale: {
parent: 'game-container',
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
width: 800,
height: 600
},
scene: MyScene
};
const game = new Phaser.Game(config);
动态调整画布尺寸时使用 RESIZE 模式,并监听 resize 事件:
create() {
this.scale.on('resize', this.handleResize, this);
}
handleResize(gameSize, baseSize, displaySize) {
this.cameras.resize(gameSize.width, gameSize.height);
}
全屏切换需在 pointerup 手势中调用,可使用 startFullscreen、stopFullscreen、toggleFullscreen,并通过 isFullscreen 读取状态。若未配置 fullscreenTarget,Phaser 会创建临时 div 承载画布。iframe 中需要 allowfullscreen 属性。
方向变化可监听 orientationchange 事件,并可在移动端尝试 lockOrientation('landscape')。
像素风格游戏可结合 pixelArt: true 与 zoom: Phaser.Scale.MAX_ZOOM 获得清晰渲染。也可通过 snap 配置在尺寸变化时按网格取整,通过 min、max 限制显示尺寸范围。
适用场景
适合需要让 Phaser 4 游戏适配不同屏幕尺寸、容器尺寸或设备方向的场景,包括桌面与移动端响应式布局、像素风游戏整数倍放大、全屏游戏、需要动态改变游戏基础尺寸的项目,以及需要根据方向切换 UI 的移动端游戏。
限制
父元素必须有可计算的尺寸,未设置样式的 div 高度为零会破坏居中与缩放;父元素不应设置 padding,ScaleManager 不予计算。不要直接给 canvas 设置样式,否则会与 ScaleManager 冲突。全屏必须由 pointerup 触发,pointerdown 在触摸设备上可能被阻止。RESIZE 模式在高分辨率屏幕上会生成很大的 1:1 画布,可能影响低端设备性能。resize() 仅适用于 NONE 模式,缩放模式应使用 setGameSize()。百分比宽高依赖有尺寸的父容器,否则回退到 window 尺寸。resizeInterval 是旧浏览器兜底轮询,默认 500 毫秒。