Reputation: 559
I am creating an animation with phaser which contains a timer.
The issue occurs when I Alt-Tab or minimize the page as the timer keeps on running but the animation stops, so the GameObjects are not in sync with the timers.
I've looked through the config class of the phaser object and couldn't find any parameter related to this.
I also tried using this.game.loop.wake()
when changing visibility but it doesn't seem to be working also (it still stops the animation while I'm not on the page)
create()
{
//[...]
this.setupVisibilityChangeListener();
}
setupVisibilityChangeListener() {
document.addEventListener('visibilitychange', () => {
this.game.loop.wake();
});
}
EDIT 1
As requested here are some additional details
The project is a react project and initialize the game inside the useEffect of a certain page with the below config
useEffect(() => {
//[...]
const config: Phaser.Types.Core.GameConfig = {
type: Phaser.AUTO,
parent: 'phaser-container',
width: width,
height: height,
transparent: true,
scene: [new RaceScene(data, isMobile)],
physics: {
default: 'arcade',
arcade: {
debug: false,
fps: 30,
},
},
fps: {
target: 30,
forceSetTimeOut: true,
},
input: {
touch: {
capture: false,
},
},
}
const game = new Phaser.Game(config)
//[...]
})
I'm using Phaser 3.80.1
that I installed with npm
I use the time from the time
parameter in the update
function and emit the event with a React Event Emitter like seen below
import animationEventEmitter from '<path>/animation.event'
update(time: number, delta: number): void {
//[...]
animationEventEmitter.emit('timeUpdate', time)
//[...]
}
And here is the simple event emitter
import { EventEmitter } from 'events'
const animationEventEmitter = new EventEmitter()
export default animationEventEmitter
No timeout or delay is used anywhere
As suggested I tried to add the below inside the create
of the scene
this.game.events.on('visible', () =>{
this.game.resume()
});
this.game.events.on('hidden', () => {
this.game.pause()
});
But the timer kept on moving even thought I alt-tab ed while the animation stopped...
Upvotes: 1
Views: 106
Reputation: 14670
If you use phaser Timer functions, this should not happen since, it uses the game clock. (link to documentation)
Are you maybe using setTimeout
, setInterval
or using timestamps? If so you could rewrite your code to use phaser time/timer functions.
Short Demo [Updated]:
(ShowCasing the timer, loosely based on official example)
class DemoScene extends Phaser.Scene {
timedEvent;
text;
image;
pauseCount;
create () {
this.text = this.add.text(32, 32);
this.pauseCount = 0;
this.timedEvent = this.time.addEvent({ delay: 2000, callback: this.onEvent, callbackScope: this, repeat: 4 });
this.game.events.on('visible', () =>{
console.info('PAUSE END fired!');
this.pause = false;
});
this.game.events.on('hidden', () => {
console.info('PAUSE START fired!');
this.pause = true;
this.pauseCount++;
});
}
update (time) {
if(this.pause){
console.info(time)
return
}
this.text.setText(`Event.progress: ${this.timedEvent.getProgress().toString().substr(0, 4)}\nEvent.repeatCount: ${this.timedEvent.repeatCount}\nPause Counter: ${this.pauseCount}`);
}
onEvent () {
console.info('EVENT fired!');
}
}
var config = {
width: 540,
height: 180,
scene: DemoScene,
};
new Phaser.Game(config);
console.clear();
document.body.style = 'margin:0;';
<script src="//cdn.jsdelivr.net/npm/phaser/dist/phaser.min.js"></script>
Tip: If possible always opt for phaser function / features, before turning to vanilla javascript.
Update 2:
If your timer relies on the time
parameter of the update
function, time wll not stand still since as mentioned before, it starts with the start of the application. A "quick" solution could be to sum the pause-time and subtract it, from the time parameter:
create () {
//[...]
this.pauseTimeSum = 0;
this.game.events.on('visible', () =>{
this.pause = false;
if ( this.pauseStart > 0 ){
this.pauseTimeSum += Date.now() - this.pauseStart;
}
});
this.game.events.on('hidden', () => {
this.pause = true;
this.pauseStart = Date.now();
});
}
update(time: number, delta: number): void {
//[...]
animationEventEmitter.emit('timeUpdate', time - this.pauseTimeSum)
//[...]
}
It's not nice but it is a quick & easy solution, if you need to use the time
parameter.
Upvotes: 1