如何基于Phaser实现多设备多方向的游戏适配缩放?
Phaser 横竖屏适配优化方案
1. 优先用Phaser内置缩放模式替代手动计算
Phaser的ScaleManager自带类似Unity的自动适配能力,无需手动逐个调整元素。初始化游戏时配置好缩放规则,就能自动处理横竖屏切换的缩放与居中:
const gameConfig = { type: Phaser.AUTO, // 设定基准分辨率(示例为横屏1920x1080) width: 1920, height: 1080, scale: { // FIT模式:保持比例缩放,填满屏幕且不变形 mode: Phaser.Scale.FIT, // 自动居中画布 autoCenter: Phaser.Scale.CENTER_BOTH, // 限制最小/最大分辨率,避免极端尺寸下的显示异常 min: { width: 960, height: 540 }, max: { width: 3840, height: 2160 }, // 防抖resize事件,避免频繁触发导致性能损耗 resizeInterval: 100 }, scene: { preload: preload, create: create, // 仅当需要额外自定义逻辑时保留resize函数 resize: resize } }; new Phaser.Game(gameConfig);
2. 用容器(Container)批量管理元素
把关联元素(玩家、卡片、UI组件等)放进容器,只需调整容器的缩放和位置,就能批量控制所有子元素,彻底告别逐个设置的低效操作:
// 在create函数中初始化容器 create() { // 创建玩家容器并居中 this.playerContainer = this.add.container(this.cameras.main.centerX, this.cameras.main.centerY); // 将所有玩家精灵添加到容器 this.players.forEach(playerSprite => this.playerContainer.add(playerSprite)); // 同理创建卡片容器 this.cardContainer = this.add.container(this.cameras.main.centerX, this.cameras.main.height - 60); this.cards.forEach(cardSprite => this.cardContainer.add(cardSprite)); }
3. 优化resize函数,减少手动计算
利用Phaser内置的相机属性和缩放因子,替代window.innerWidth这类原生API,同时通过容器统一控制元素:
resize() { const camera = this.cameras.main; // Phaser自动计算的适配缩放比例 const scaleFactor = this.scale.scaleFactor.x; this.stopTweening(); // 背景图直接铺满相机视口 this.bg.setDisplaySize(camera.width, camera.height); this.bg.setPosition(camera.centerX, camera.centerY); // 桌子容器居中并按比例缩放 this.containerOfTable.setPosition(camera.centerX, camera.centerY); this.containerOfTable.setScale(scaleFactor); // 计时器与按钮基于相机视口定位 this.timer.setScale(scaleFactor) .setPosition(this.table.getTopRight().x - 30 * scaleFactor, this.table.getTopRight().y + 20 * scaleFactor); this.button.setScale(scaleFactor) .setPosition(camera.width - 20 * scaleFactor, 30 * scaleFactor); // 批量更新玩家与卡片容器 this.playerContainer.setScale(scaleFactor); this.playerContainer.setPosition(camera.centerX, camera.centerY); this.cardContainer.setScale(scaleFactor); this.cardContainer.setPosition(camera.centerX, camera.height - 60 * scaleFactor); this.tweenAs(this.cards[0], this.cards[2], this.cards[3]); }
4. 横竖屏特殊布局处理
如果横竖屏需要不同的元素排列(比如玩家位置切换),可以通过this.scale.isPortrait判断,结合Phaser的对齐工具快速调整:
resize() { // ... 其他代码 ... const scaleFactor = this.scale.scaleFactor.x; const camera = this.cameras.main; if (this.scale.isPortrait) { // 竖屏:玩家垂直居中排列 Phaser.Display.Align.To.AlignIn(this.playerContainer, camera, Phaser.Display.Align.CENTER, 0, 20 * scaleFactor); Phaser.Display.Align.To.VerticalCenter(this.playerContainer.getChildren(), 20 * scaleFactor); } else { // 横屏:玩家水平居中排列 Phaser.Display.Align.To.AlignIn(this.playerContainer, camera, Phaser.Display.Align.CENTER, 20 * scaleFactor, 0); Phaser.Display.Align.To.HorizontalCenter(this.playerContainer.getChildren(), 20 * scaleFactor); } }
关键注意事项
- 避免直接使用
window.innerWidth/Height,优先用this.cameras.main.width/height获取适配后的视口尺寸 - 给resize事件加防抖,防止屏幕旋转时频繁触发导致的性能问题
- 对于需要保持固定比例的元素,用
Math.min(this.scale.scaleFactor.x, this.scale.scaleFactor.y)统一缩放,避免拉伸变形
内容的提问来源于stack exchange,提问作者a_7md.f
相关产品推荐
相关产品推荐

