Search code examples
javascriptcollisionphaser-frameworkscene

Phaser3 Scene switching error. How can i do?


I have this error when I touch a wall to change scene:

Cannot read properties of undefined (reading 'start')

I tried several techniques but none worked, yet I have no other errors and my code is quite simple and I don't understand why it doesn't work... Here is my code:

class SceneMilieu extends Phaser.Scene {

  constructor() {
   super({key: 'sceneMilieu'});
 }


  //Chargement des images
  preload() {
    // this.load.image("Backgrond", "javascript/assets/Background.png");
    this.load.image("player", "javascript/assets/player.png");
    this.load.image("run1", "javascript/assets/run1.png");
    this.load.image("run2", "javascript/assets/run2.png");
    this.load.image("playerLeftRun1", "javascript/assets/playerLeftRun1.png");
    this.load.image("playerLeftRun2", "javascript/assets/playerLeftRun2.png");
    this.load.image("wall", "javascript/assets/wall.png");

  }

  create() {
    cursor = this.input.keyboard.createCursorKeys(); //touches des fleches

    var w = config.width;
    var h = config.height;

    //Les animations
    this.anims.create({
      key : "playerWalkUp",
      frames : [
        {key : "run1"},
        {key : "run2"}],
      frameRate : 7,
      repeat : 0
    })

    this.anims.create({
      key : "playerWalkLeft",
      frames : [
        {key : "playerLeftRun1"},
        {key : "playerLeftRun2"}],
      frameRate : 7,
      repeat : 0
    })

    // L'apparition + le controle et les collisions ce fais ci dessous

    // var backgroundImage = this.add.sprite(0, 0, "Background");
    // backgroundImage.setPosition(w/2, h/2);
    player = this.physics.add.sprite(100, 300, "player"); //joueur
    player.setScale(1);
    player.body.setSize(30, 35);
    player.setCollideWorldBounds(true); //collision avec la bordure

    doorLeft = this.physics.add.staticSprite(200, 400, "wall"); //Porte de tp

    var platforms = this.physics.add.staticGroup();

    var wall = this.add.sprite(400, 500, "wall"); //mur
    

    this.physics.add.collider(platforms, player); //collision

    platforms.add(wall);
    
    function collision() {
      this.scene.start("sceneGauche");  
    }
    
    this.physics.add.collider(player, doorLeft, collision);
  }

  update() {

  // Tous les mouvement sont controler par ce code

    if (cursor.left.isDown){
      player.setVelocityX(-200); //vitesse de deplacements
      player.anims.play("playerWalkLeft", true); //animations du personnage
      player.setFlip(false, false); //oriantation de l'image
    } else if (cursor.right.isDown){
      player.setVelocityX(200);
      player.anims.play("playerWalkLeft", true);
      player.setFlip(true, false);
    } else if (cursor.up.isDown){
      player.setVelocityY(-200);
      player.anims.play("playerWalkUp", true);
      player.setFlip(false, false);
    } else if (cursor.down.isDown){
      player.setVelocityY(200);
      player.anims.play("playerWalkUp", true);
      player.setFlip(false, true);
    } else {
      player.setVelocity(0);
      player.setTexture("player");
    }

    if ((cursor.left.isDown && cursor.up.isDown) || (cursor.left.isDown && cursor.right.isDown) || (cursor.left.isDown && cursor.down.isDown) || (cursor.right.isDown && cursor.up.isDown) || (cursor.right.isDown && cursor.down.isDown)){
      player.setVelocity(0);
      player.setTexture("player");
    }

  //--------

}}

class SceneGauche extends Phaser.Scene {

  constructor() {
    super({key: "SceneGauche"});
    scene: {
      preload: this.preload;
      create: this.create;
      update: this.update;
    }
  }

  preload() {
    this.load.image("player", "javascript/assets/player.png");
    this.load.image("run1", "javascript/assets/run1.png");
    this.load.image("run2", "javascript/assets/run2.png");
    this.load.image("playerLeftRun1", "javascript/assets/playerLeftRun1.png");
    this.load.image("playerLeftRun2", "javascript/assets/playerLeftRun2.png");
    this.load.image("wall", "javascript/assets/wall.png");

  }

  create() {
    cursor = this.input.keyboard.createCursorKeys();

    var w = config.width;
    var h = config.height;

    this.anims.create({
      key : "playerWalkUp",
      frames : [
        {key : "run1"},
        {key : "run2"}],
      frameRate : 7,
      repeat : 0
    })

    this.anims.create({
      key : "playerWalkLeft",
      frames : [
        {key : "playerLeftRun1"},
        {key : "playerLeftRun2"}],
      frameRate : 7,
      repeat : 0
    })

    player = this.physics.add.sprite(100, 300, "player");
    player.setScale(1);
    player.body.setSize(30, 35);
    const border = player.setCollideWorldBounds(true);

    var platforms = this.physics.add.staticGroup();

    var wall = this.add.sprite(400, 500, "wall");
    platforms.add(wall);

    this.physics.add.collider(platforms, player); 

    player.onCollide = new Phaser.signal(); 
    border.onCollide.add(changeMapGauche, this);

  }

  update() {

    if (cursor.left.isDown){
      player.setVelocityX(-200);
      player.anims.play("playerWalkLeft", true);
      player.setFlip(false, false);
    } else if (cursor.right.isDown){
      player.setVelocityX(200);
      player.anims.play("playerWalkLeft", true);
      player.setFlip(true, false);
    } else if (cursor.up.isDown){
      player.setVelocityY(-200);
      player.anims.play("playerWalkUp", true);
      player.setFlip(false, false);
    } else if (cursor.down.isDown){
      player.setVelocityY(200);
      player.anims.play("playerWalkUp", true);
      player.setFlip(false, true);
    } else {
      player.setVelocity(0);
      player.setTexture("player");
    }

    if ((cursor.left.isDown && cursor.up.isDown) || (cursor.left.isDown && cursor.right.isDown) || (cursor.left.isDown && cursor.down.isDown) || (cursor.right.isDown && cursor.up.isDown) || (cursor.right.isDown && cursor.down.isDown)){
      player.setVelocity(0);
      player.setTexture("player");
    }
  }

}

var config = {
  type: Phaser.AUTO,
  width: window.innerWidth - 20,
  height: window.innerHeight - 100,
  backgroundColor: "#EDEED0",
  physics: {
    default : "arcade",
    arcade : {
      debug : true,
    }
  },
  scene: [SceneMilieu, SceneGauche]
};

let game = new Phaser.Game(config);

var cursor;
var player;
var doorLeft; 

<!-- begin snippet: js hide: false console: true babel: false -->
<!DOCTYPE html>
<html lang="fr-FR">

  <head>

    <meta charset="utf-8" />
    <meta name="description" content="Page web du projet de NSI. Ce site regrouppe quelque jeux en ligne programmer par nous même en javascript" />
    <meta name="author" content="Thorvald Helbling, Alexis STOCK, Lionel FUCHS" />
    <title>Thoralial</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>

  </head>

  <header>

    <img id="LogoThoralial" src="info/image/LogoThoralial.png" alt="Logo du site" />

    <div>
      <h1>Bienvenue !</h1>
      <p>C'est votre tableau de bord.</p>
    </div>

  </header>

  <body>

    <script id="js" type="text/javascript" src="javascript/main.js"></script>
    <script></script>

  </body>

  <footer>
    
    <div id="personne">
      <p>
        Ce projet a étais réalisé par : <a href="***"> Thorvald HELBLING</a>, <a href="***"> Lionel FUCHS </a> et <a href="***"> Alexis STOCK </a>
      </p>
    </div>

  </footer>
</html>

I would like to understand where my error comes from and common fixed it. I use Phaser3 The error comes from the site console. (Local)


Solution

  • The problem is this line of code:

     this.physics.add.collider(player, doorLeft, collision);
    

    You only need to pass the scene as context to the collider function. Here is a link to the documentation, especially for the collider function and parameters. https://newdocs.phaser.io/docs/3.52.0/focus/Phaser.Physics.Arcade.Factory-collider

    With other words, you just have to pass the scene context (as parameter 5) and a should process function (parameter 4, in this case undefined, since there is no function)

    Just replace the current line, with this line (or add the two parameters), and it should work

      this.physics.add.collider(player, doorLeft, collision, undefined, this);
    

    Or you can use the javascript function bind:

      this.physics.add.collider(player, doorLeft, collision.bind(this));
    

    Might not be as obvious, but it is shorter and works fine (Link to bind documentaion). This would be my prefered mehtod, if I don't use the parameter 4, since the code likes much cleaner and shorter this way.

    Update: Alternativly if you want to use Closures you could change only the function definition, to a arrow function expression, then you would not have to pass any extra parameter, do the collider function:

       let collision = () => {
           this.scene.start("sceneGauche");  
       }
    

    I'm in usually no fan of defining functions inside of function/methods (especially with the function keyword), but with the arrow function expression, it's looks even abit cleaner.