1

I'm working on a proof of concept that involves the game switching between 2 scenes. The scenes switch when the player character moves in front of a door sprite and presses a button.

Update: Here is the code from the first scene, including that lets allows for switching from the first scene, called play, to the other scene, called secondScene.

    class Play extends Phaser.Scene {
    constructor() {
        super('play');
    }

preload(){

    this.load.image('testBackground', "assets/testBackground.png");
    this.load.image('testGround', "assets/testGround.png");
    this.load.image('TestCharacter', "assets/TestCharacter.png");
    this.load.image('testNPC', "assets/testNPC.png");
    this.load.image('testPlatform', "assets/testPlatform.png");
    this.load.image('testDoor', "assets/testDoor.png");
    this.load.image('testItem', "assets/testItem.png");

}

create(){

    let width = config.width;
    let height = config.height;
    this.physics.world.gravity.y = 1000;

    keyA = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
    keyD = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
    keyW = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
    keyT = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.T);
    keyG = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.G);

    this.bg = this.add.tileSprite(0,0, game.config.width, game.config.height, 'testBackground').setOrigin(0,0);
    //this.cameras.main.setBackgroundColor('#CCC');

    this.items = [null, null, null, null, null, null, null, null, null];

    this.ground = this.physics.add.sprite(800, 900, 'testGround');
    this.ground.body.immovable = true;
    this.ground.body.allowGravity = false;

    this.door = this.physics.add.sprite(14.5, 770, 'testDoor');
    this.door.body.immovable = true;
    this.door.body.allowGravity = false;

    this.hammer = this.physics.add.sprite(200 ,700, 'testItem');


    //this.menuConfig = {
    //    fontFamily: 'Courier',
    //   fontSize: '28px',
    //    backgroundColor: '#F3B141',
    //    color: '#843605',
    //    align: 'right',
    //    padding: {
    //        top: 5,
    //        bottom: 5,
    //     },
    //    fixedWidth: 0
    //}

    this.p1 = this.physics.add.sprite(500, 500, 'TestCharacter');
    this.p1.setCollideWorldBounds(true);

    this.talker = this.physics.add.sprite(600, 770, 'testNPC');

    this.platforms = this.add.group();

    this.low = this.physics.add.sprite(600, 720, 'testPlatform');
    this.low.body.immovable = true;
    this.low.body.allowGravity = false;
    this.platforms.add(this.low);

    this.high = this.physics.add.sprite(450, 700, 'testPlatform');
    this.high.body.immovable = true;
    this.high.body.allowGravity = false;
    this.platforms.add(this.high);

    this.physics.add.collider(this.p1, this.ground);
    this.physics.add.collider(this.talker, this.ground);
    this.physics.add.collider(this.p1, this.ground);
    this.physics.add.collider(this.hammer, this.ground);


}

update(){
    
    if(keyA.isDown) {
        this.p1.setVelocityX(-200);
    }
    else if(keyD.isDown) {
        this.p1.setVelocityX(200);
    }
    else {
        this.p1.setVelocityX(0);
    }

    if(this.p1.body.touching.down && Phaser.Input.Keyboard.JustDown(keyW)) {
        this.p1.body.setVelocityY(-500);
    }

    if (this.checkCollision(this.p1, this.hammer) && Phaser.Input.Keyboard.JustDown(keyT)){
        this.space = 0;
        if (this.items[this.space] == null){
            this.items[this.space] == this.hammer;
            this.hammer.destroy();
        }
    }    

    if (this.checkCollision(this.p1, this.talker)) {
        this.add.text(game.config.width/2, 30, 'blah blah blah)', { font: '14px Futura', fill: '#FFFFFF' }).setOrigin(0.5);
    }

    if (this.checkCollision(this.p1, this.door) && Phaser.Input.Keyboard.JustDown(keyT)){
        this.p1.x = 55;
        console.log(Phaser.Input.Keyboard.JustDown(keyT));
        this.scene.switch('secondScene');
    }
    
}

checkCollision(a, b) {
    // simple AABB checking
    if ((a.x < b.x + b.width && 
        a.x + a.width > b.x && 
        a.y < b.y + b.height &&
        a.height + a.y > b.y) ) {
            return true;
    } 
    else {
        return false;
    }
}

}   

And here is the code from secondScene, including that which is supposed to allow for switching back to play.

    class SecondScene extends Phaser.Scene {
    constructor() {
        super('secondScene');
    }

preload(){

    this.load.image('testBackground', "assets/testBackground.png");
    this.load.image('testGround', "assets/testGround.png");
    this.load.image('TestCharacter', "assets/TestCharacter.png");
    this.load.image('testNPC', "assets/testNPC.png");
    this.load.image('testPlatform', "assets/testPlatform.png");
    this.load.image('testDoor', "assets/testDoor.png");

}

create(){

    let width = config.width;
    let height = config.height;
    this.physics.world.gravity.y = 1000;

    keyA = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
    keyD = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
    keyW = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
    keyT = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.T);
    keyG = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.G);

    this.bg = this.add.tileSprite(0,0, game.config.width, game.config.height, 'testBackground').setOrigin(0,0);
    //this.cameras.main.setBackgroundColor('#CCC');

    this.ground = this.physics.add.sprite(800, 900, 'testGround');
    this.ground.body.immovable = true;
    this.ground.body.allowGravity = false;

    this.door = this.physics.add.sprite(14.5, 770, 'testDoor');
    this.door.body.immovable = true;
    this.door.body.allowGravity = false;

    //this.menuConfig = {
    //    fontFamily: 'Courier',
    //   fontSize: '28px',
    //    backgroundColor: '#F3B141',
    //    color: '#843605',
    //    align: 'right',
    //    padding: {
    //        top: 5,
    //        bottom: 5,
    //     },
    //    fixedWidth: 0
    //}

    this.p1 = this.physics.add.sprite(500, 500, 'TestCharacter');
    this.p1.setCollideWorldBounds(true);

    this.talker = this.physics.add.sprite(600, 774.5, 'testNPC');

    this.low = this.physics.add.sprite(600, 720, 'testPlatform');
    this.low.body.immovable = true;
    this.low.body.allowGravity = false;

    this.physics.add.collider(this.p1, this.ground);
    this.physics.add.collider(this.talker, this.ground);
    this.physics.add.collider(this.p1, this.low);

    

}

update(){
    
    if (Math.round(this.low.x) == 600){       
         this.low.setVelocityX(100);  
    }

    if (Math.round(this.low.x) == 1500){
        this.low.setVelocityX(-100);
    }

    if(keyA.isDown) {
        this.p1.setVelocityX(-200);
    }
    else if(keyD.isDown) {
        this.p1.setVelocityX(200);
    }
    else {
        this.p1.setVelocityX(0);
    }

    if(this.p1.body.touching.down && Phaser.Input.Keyboard.JustDown(keyW)) {
        this.p1.body.setVelocityY(-500);
    }

    if (this.checkCollision(this.p1, this.talker)) {
        this.add.text(game.config.width/2, 30, 'blah blah blah)', { font: '14px Futura', fill: '#FFFFFF' }).setOrigin(0.5);
    }

    if (this.checkCollision(this.p1, this.door) && Phaser.Input.Keyboard.JustDown(keyT)){
        this.p1.x = 55;
        console.log(Phaser.Input.Keyboard.JustDown(keyT));
        this.scene.switch('play');
    }
    

}

checkCollision(a, b) {
    // simple AABB checking
    if ((a.x < b.x + b.width && 
        a.x + a.width > b.x && 
        a.y < b.y + b.height &&
        a.height + a.y > b.y) ) {
            return true;
    } 
    else {
        return false;
    }
}

}

When switching from play to secondScene, everything works fine, but when switching from secondScene to play, the game freezes once it shows the scene's visuals.

When the game freezes, the player character is still over the door sprite and the movement buttons don't do anything. When I open the inspect screen, it doesn't show that an error occurred, so I'm wondering if it's somehow soft-locked.

I'm not sure how to get past this, given my inexperience with Phaser. Can someone please help?

If it helps lead to a solution, I'm using Phaser 3 in VSCode, employing arcade physics.

EmptyStone
  • 235
  • 1
  • 7
  • 1
    Maybe you are stuck in a loop where the scenes keep switching? Because you are still hitting the door and pressing down? You can test that by requiring a different key to be pressed in scene 2. – Kokodoko Aug 11 '22 at 10:39
  • Hey, just tried that. It didn't work, the game still froze. – EmptyStone Aug 11 '22 at 19:00
  • In that case some other code must cause some kind of infinite loop or freeze. I suggest placing breakpoints or lots of `console.logs()` in your code to find out exactly where it freezes. – Kokodoko Aug 12 '22 at 08:32

1 Answers1

0

You would have to share more code, because the main premise of switching Scene, with a key-press event, works without freezing loop.

I assume you are setting the keyboard key's in a global variable (like the keyT in the shown code example), and therefore it works, only from Scene 1 to Scene 2 and than "breaks" on return. Since the global variable is probably overridden in the create function, and the create function is only called once on the first start/switch of each Scene.

I updated the example to show this. Now there is an extra key X, that is defined globally. This key will only work on the first Scene until the first switch, because the global variable globalTestKey will stay referenced to the X-key of the Second Scene.

Seen here in small this example:

document.body.style = 'margin:0;';

var globalTestKey;

class FirstScene extends Phaser.Scene {
  constructor(){
    super('first');
  }
  
  create(){
    this.statusLabel = this.add.text(10, 10, 'STATUS');
    this.add.text(50, 40, 'FIRST -> press Key A to switch\nOr global   -> press Key X');
    this.key = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
    
    globalTestKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.X);
  }
  
  update(){
    this.statusLabel.setText(`SceneName of global X-Key: ${globalTestKey.plugin.scene.constructor.name}`);
    if(globalTestKey.isDown){
        let info = this.add.text(50, 80, 'X was pressed');
        setTimeout(_ => info.destroy(), 1000);
    }
    if(this.key.isDown){
        this.scene.switch('second');
    }
  }
}

class SecondScene extends Phaser.Scene {
  constructor(){
    super('second');
  }
  
  create(){
    this.statusLabel = this.add.text(10, 10, 'STATUS');
    this.add.text(50, 40, 'SECOND -> press Key D to switch\nOr global   -> press Key X');
    this.key = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
     globalTestKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.X);
  }
  
  update(){
    this.statusLabel.setText(`SceneName of global X-Key: ${globalTestKey.plugin.scene.constructor.name}`);
    if(globalTestKey.isDown){
        let info = this.add.text(50, 80, 'X was pressed');
        setTimeout(_ => info.destroy(), 1000);
    }
    if(this.key.isDown){
        this.scene.switch('first');
    }
  }
}

var config = {
    type: Phaser.AUTO,
    width: 536,
    height: 183,
    scene: [FirstScene, SecondScene],
    banner: false
}; 

new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.js"></script>

Update:

The easy/fast solution would be, to make all global variables to Scene Properties.

Replace in both Scenes all:

 ...
 keyA = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
 keyD = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
 keyW = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
 keyT = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.T);
 keyG = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.G);
 ...

With this:

 ...
 this.keyA = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
 this.keyD = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
 this.keyW = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
 this.keyT = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.T);
 this.keyG = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.G);
 ...

And also all other references, similar to this one:

...
if(keyA.isDown) {
...

With:

...
if(this.keyA.isDown) {
...

With other words, change any usage of keyW, keyA, keyD, keyG and keyT to this.keyW, this.keyA, this.keyD, this.keyG and this.keyT

winner_joiner
  • 12,173
  • 4
  • 36
  • 61
  • Well, what I did share is really all the code regarding scene switch I have. Is there something in particular you want to look at? – EmptyStone Aug 13 '22 at 00:09
  • @EmptyStone well there are some parts that would be interesting: the creation of `keyT` where is it done, and what scope does it have (global, function local, ....)? Are there more different places in the code, where a Scene switch can be triggert? And a question do you know if the code is stuck in onspecific Scene, or if it is changing scenes. Are you maye using global variables, that are overrriden from the second scene, so that inputs don't work on switching back? Later would explain the it works only oneway. – winner_joiner Aug 13 '22 at 04:40
  • @EmptyStone I think I have found the problem. I updated my answer, to showcase this issue. – winner_joiner Aug 13 '22 at 07:03
  • I added the rest of the code I'm using, even if a lot of it is unrelated to the problem. Sorry if that's not the norm on stackoverflow, but I'm extremely new here. I hope it helps. I'm struggling to understand your example, but what I'm getting is that you believe I declared keyT globally and that it gets overridden somewhere in the create function. If I got it right, I'm admittedly not sue how to fix that. But as I'm planning to have T be a general interaction button, used for picking up items, talking to characters, and using doors to go to other scenes, I need it to work. – EmptyStone Aug 13 '22 at 18:02
  • @EmptyStone I updated my answer, I hope it is clear, what I mean. – winner_joiner Aug 13 '22 at 18:55