简体   繁体   中英

How to create a responsive game for any screen size with Phaser 3?

I've been looking for a solution to be able to make my game fully responsive to any screen resolution using Phaser 3, for example:

调整屏幕大小

This example was made with Construct 2, where by the way it is very simple to do this effect.

Does anyone know what is the best approach to achieve this using Phaser 3?

Doing research I was able to find a solution to my problem:

The key is use a parent scene to control all other child scenes, This scene is going to measure the same as the device's screen size. It will also resize the child scenes when the screen size changes, but always keeping the aspect ratio.

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)
}

}

In this way we can start other scenes in parallel within the parent scene.

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
}

}

In the child scenes, the updateResize function of the parent scene must be called from the create function of each scene.

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
}

the mode: Phaser.Scale.RESIZE is very important and also a maximum and a minimum for the screen size.

Mi complete solution is here:

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

Explation:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM