After conducting thorough research, I discovered a solution to the issue at hand:
The key is to utilize a parent scene to oversee all other child scenes. This parent scene will match the device's screen size and adjust the child scenes accordingly while maintaining the aspect ratio.
HandlerScene.js
export default class Handler extends Phaser.Scene {
// Variables
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' refers to the current running scene
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)
}
}
This approach allows for running multiple scenes simultaneously 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
setting is crucial, along with defining maximum and minimum screen sizes.
You can find my complete solution here:
https://github.com/shimozurdo/mobile-game-base-phaser3
For further explanation, visit: