如何使用 Phaser 3 创建适合任何屏幕尺寸的响应式游戏?

shi*_*imo 17 javascript game-engine phaser-framework

我一直在寻找一种解决方案,能够使用 Phaser 3 让我的游戏完全响应任何屏幕分辨率,例如:

调整屏幕大小

这个例子是用Construct 2制作的,顺便说一下,实现这个效果非常简单。

有谁知道使用 Phaser 3 实现这一目标的最佳方法是什么?

shi*_*imo 13

通过研究,我找到了解决问题的方法:

关键是使用父场景来控制所有其他子场景,该场景的尺寸将与设备的屏幕尺寸相同。当屏幕尺寸发生变化时,它还会调整子场景的大小,但始终保持宽高比。

HandlerScene.js

export default class Handler extends Phaser.Scene {

    // Vars
    sceneRunning = null

    constructor() {
        super('handler')
    }

    create() {
        this.cameras.main.setBackgroundColor('#FFF')
        this.launchScene('preload')
    }

    launchScene(scene, data) {
        this.scene.launch(scene, data)
        this.gameScene = this.scene.get(scene)
    }

    updateResize(scene) {
        scene.scale.on('resize', this.resize, scene)

        const scaleWidth = scene.scale.gameSize.width
        const scaleHeight = scene.scale.gameSize.height

        scene.parent = new Phaser.Structs.Size(scaleWidth, scaleHeight)
        scene.sizer = new Phaser.Structs.Size(scene.width, scene.height, Phaser.Structs.Size.FIT, scene.parent)

        scene.parent.setSize(scaleWidth, scaleHeight)
        scene.sizer.setSize(scaleWidth, scaleHeight)

        this.updateCamera(scene)
    }

    resize(gameSize) {
        // 'this' means to the current scene that is running
        if (!this.sceneStopped) {
            const width = gameSize.width
            const height = gameSize.height

            this.parent.setSize(width, height)
            this.sizer.setSize(width, height)

            const camera = this.cameras.main
            const scaleX = this.sizer.width / this.game.screenBaseSize.width
            const scaleY = this.sizer.height / this.game.screenBaseSize.height

            camera.setZoom(Math.max(scaleX, scaleY))
            camera.centerOn(this.game.screenBaseSize.width / 2, this.game.screenBaseSize.height / 2)
        }
    }

    updateCamera(scene) {
        const camera = scene.cameras.main
        const scaleX = scene.sizer.width / this.game.screenBaseSize.width
        const scaleY = scene.sizer.height / this.game.screenBaseSize.height

        camera.setZoom(Math.max(scaleX, scaleY))
        camera.centerOn(this.game.screenBaseSize.width / 2, this.game.screenBaseSize.height / 2)
    }

}
Run Code Online (Sandbox Code Playgroud)

这样我们就可以在父场景中并行启动其他场景。

PreloadScene.js

export default class Preload extends Phaser.Scene {

    handlerScene = null
    sceneStopped = false

    constructor() {
        super({ key: 'preload' })
    }

    preload() {
        // Images
        this.load.image('logo', 'assets/images/logo.png')   

        this.width = this.game.screenBaseSize.width
        this.height = this.game.screenBaseSize.height

        this.handlerScene = this.scene.get('handler')
        this.handlerScene.sceneRunning = 'preload'
        this.sceneStopped = false

        ...
    }

    create() {
        const { width, height } = this
        // CONFIG SCENE         
        this.handlerScene.updateResize(this)
        // CONFIG SCENE  

        // GAME OBJECTS  
        this.add.image(width / 2, height / 2, 'logo').setOrigin(.5)
        // GAME OBJECTS
    }
}
Run Code Online (Sandbox Code Playgroud)

在子场景中,updateResize必须从每个场景的create函数中调用父场景的函数。

ConfigGame.js

import Handler from './scenes/handler.js'
import Preload from './scenes/preload.js'

// Aspect Ratio 16:9 - Portrait
const MAX_SIZE_WIDTH_SCREEN = 1920
const MAX_SIZE_HEIGHT_SCREEN = 1080
const MIN_SIZE_WIDTH_SCREEN = 270
const MIN_SIZE_HEIGHT_SCREEN = 480
const SIZE_WIDTH_SCREEN = 540
const SIZE_HEIGHT_SCREEN = 960

const config = {
    type: Phaser.AUTO,
    scale: {
        mode: Phaser.Scale.RESIZE,
        parent: 'game',
        width: SIZE_WIDTH_SCREEN,
        height: SIZE_HEIGHT_SCREEN,
        min: {
            width: MIN_SIZE_WIDTH_SCREEN,
            height: MIN_SIZE_HEIGHT_SCREEN
        },
        max: {
            width: MAX_SIZE_WIDTH_SCREEN,
            height: MAX_SIZE_HEIGHT_SCREEN
        }
    },
    dom: {
        createContainer: true
    },
    scene: [Handler, Preload]

}

const game = new Phaser.Game(config)

// Global

game.screenBaseSize = {
    maxWidth: MAX_SIZE_WIDTH_SCREEN,
    maxHeight: MAX_SIZE_HEIGHT_SCREEN,
    minWidth: MIN_SIZE_WIDTH_SCREEN,
    minHeight: MIN_SIZE_HEIGHT_SCREEN,
    width: SIZE_WIDTH_SCREEN,
    height: SIZE_HEIGHT_SCREEN
}
Run Code Online (Sandbox Code Playgroud)

mode: Phaser.Scale.RESIZE非常重要,也是屏幕尺寸的最大值和最小值。

我的完整解决方案在这里:

https://github.com/shimozurdo/mobile-game-base-phaser3

解释:

https://labs.phaser.io/edit.html?src=src/scalemanager/mobile%20game%20example.js