I’m making a game with multiple levels, which I have implemented using different scenes. The problem arises when I change the scenes frequently using the menu system I built. If I follow the expected route a player would take, the problem is not very noticeable. If I go back and forth between the menu screens, the scene order is thrown out of whack.
I change scenes using:
//stopping all scene sound
this.sound.stopAll();
//starting a new scene
this.scene.start('sceneName')
This is an example of the problem:
Level 1 has finished due to the player losing lives, the game over screen has loaded and afterwards, the hi-score screen (displayed) has loaded. But now there are values being logged in the background, which belong to Level 1 (acceleration values for falling items).
This happens, given that I’ve changed between the menu items on my title screen and level select screen.
Is it a problem with scenes buffering and then starting out of order when they load? Am I misunderstanding how scenes work? (I know they can run simultaneously, which is likely the thing that is causing the issue here) Am I supposed to stop the previous scene after the one I want displayed loads?
So I’ve tried stopping scenes entirely after a new one is selected using this.scene.stop() after I .start() a new scene. I thought this would stop the scene leaks, since the menu system in the title scene would no longer render, but it didn’t stop the leaks.
That leaves the issue being associated with solely the menu system. I believe that if I change between title and level select quickly, the values get muddled up and multiple scenes get selected simultaneously (I got 2 gameOvers from 2 different scenes running simultaneously with only one of them rendering on screen.)
Here is the code for the menu system in the Title Scene
//menu system
let activeText = 0;
let textGroup = [];
const texts = ['Story Mode', 'Level Select', 'Hi Scores', '[credits]'];
texts.forEach((text, index) => {
textGroup.push(new MenuText(this, config.scale.width / 2, 400 + 70 * index + 1, "pixelFont", text, 60, index).setOrigin(0.5));
});
this.input.keyboard.on('keydown', event => {
switch (event.key) {
case 'ArrowUp':
activeText -= 1;
this.events.emit('CHANGE_BUTTON');
break;
case 'ArrowDown':
activeText += 1;
this.events.emit('CHANGE_BUTTON');
break;
case 'Enter':
this.events.emit('SELECT');
break;
case 'f':
this.events.emit('FULLSCREEN');
break;
}
});
this.events.addListener('CHANGE_BUTTON', payload => {
this.click.play();
if (activeText < 0)
activeText += texts.length;
if (payload && typeof payload.setIndex !== 'undefined')
activeText = payload.setIndex;
textGroup.forEach(text => {
text.setStyleActive(text.index === activeText % texts.length);
});
});
this.events.addListener('SELECT', payload => {
this.sound.stopAll();
if (activeText == 0){
storyMode = true;
console.log("Title to lvl1 instructions");
this.scene.start('instructions1');
console.log("Stopping current scene");
this.scene.stop();
}
if (activeText == 1){
console.log("Title to level select");
this.scene.start('levelSelect');
console.log("Stopping current Scene");
this.scene.stop();
}
if (activeText == 2){
console.log("Title to HiScores");
this.scene.start('displayHiScores');
console.log("Stopping current Scene");
this.scene.stop();
}
if (activeText == 3){
console.log("Title to credits");
this.scene.start('credits');
console.log("Stopping current Scene");
this.scene.stop();
}
activeText += texts.length;
if (payload && typeof payload.setIndex !== 'undefined')
activeText = payload.setIndex;
textGroup.forEach(text => {
text.setStyleActive(text.index === activeText % texts.length);
});
});
this.events.addListener('FULLSCREEN', payload => {
if (this.scale.isFullscreen)
{
this.scale.stopFullscreen();
}
else
{
this.scale.startFullscreen();
}
});
Here is the menu system code for level select:
//menu options
let activeText = 0;
let textGroup = [];
let iconGroup = [];
const texts = ['Level 1', 'Level 2', 'Level 3'];
const icons = [0,1,2];
icons.forEach((icon, index) => {
iconGroup.push(new Icon(this, 300 + 210 * index + 1, 300, "level_icon", index).setOrigin(0.5));
});
texts.forEach((text, index) => {
textGroup.push(new MenuText(this, 300 + 210 * index + 1, 420, "pixelFont", text, 60, index).setOrigin(0.5));
});
textGroup.push(new MenuText(this, config.scale.width/2, 550, "pixelFont", "[back]", 60, 3).setOrigin(0.5));
this.input.keyboard.on('keydown', event => {
switch (event.key) {
case 'ArrowLeft':
activeText -= 1;
this.events.emit('CHANGE_BUTTON');
break;
case 'ArrowRight':
activeText += 1;
this.events.emit('CHANGE_BUTTON');
break;
case 'ArrowDown':
activeText = 3;
this.events.emit('CHANGE_BUTTON');
break;
case 'ArrowUp':
activeText = 1;
this.events.emit('CHANGE_BUTTON');
break;
case 'Enter':
this.events.emit('SELECTITEM');
break;
}
});
this.events.addListener('CHANGE_BUTTON', payload => {
this.click.play();
if (activeText < 0)
activeText += textGroup.length;
if (payload && typeof payload.setIndex !== 'undefined')
activeText = payload.setIndex;
textGroup.forEach(text => {
text.setStyleActive(text.index === activeText % textGroup.length);
});
});
this.events.addListener('SELECTITEM', payload => {
this.levelSelectBGM.stop();
if (activeText == 0){
this.select.play();
console.log("Level Select to lvl1 instructions");
this.scene.start('instructions1');
console.log("Stopping current Scene");
this.scene.stop();
}
if (activeText == 1){
this.select.play();
console.log("Level Select to lvl2 instructions");
this.scene.start('instructions2');
console.log("Stopping current Scene");
this.scene.stop();
}
if (activeText == 2){
this.select.play();
console.log("Level Select to lvl3 instructions");
this.scene.start('instructions3');
console.log("Stopping current Scene");
this.scene.stop();
}
if (activeText == 3){
console.log("Level Select to title");
this.scene.start('gameTitle');
console.log("Stopping current Scene");
this.scene.stop();
}
activeText += texts.length;
if (payload && typeof payload.setIndex !== 'undefined')
activeText = payload.setIndex;
textGroup.forEach(text => {
text.setStyleActive(text.index === activeText % texts.length);
});
});
I would love it if you could take a look and tell me if I’m missing something. I’ll keep trying to debug this…
I used @yannick 's menu system post in this thread:
Turns out I overlooked the fact that every time I change back to the title screen and the level select screen (and any scenes branching from those 2), a listener for the ‘SELECT’ event gets added each time, increasing the number of times a scene gets selected.
I also spotted a few other bugs to do with menu navigation along the way and fixed them.
To fix the initial bug where a listener gets added every time, I added