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.
My complete solution is here:
https://github.com/shimozurdo/mobile-game-base-phaser3
Explanation:
https://labs.phaser.io/edit.html?src=src/scalemanager/mobile%20game%20example.js