Cannot read property 'play' of undefined

I’m having trouble getting a sprite animation to work. I’m trying to play a sprite animation the same why as in the “creating your first game” tutorial … but I’m getting this error: Cannot read property ‘play’ of undefined

Any ideas?

Play.js

import Phaser from 'Phaser';

class PlayScene extends Phaser.Scene {
    constructor() {
        // pass a key/identifier of this scene to super
        super('PlayScene');
    }

    preload() {
        this.load.image('background', 'assets/background.png');
        // load zombie sprite
        this.load.spritesheet('zombie', 'assets/zombie.png', { frameWidth: 35, frameHeight: 35 });
   }

   create() {
        // config variables
        this.width = 800;
        this.height = 600;
         // background config
        this.add.image(0, 0, 'background').setOrigin(0,0);
        // zombie config
        this.zombie = this.physics.add.sprite(this.width/2, this.height/2, 'zombie')
            .setOrigin(0,0)
            .setBounce(0)
            .setCollideWorldBounds(true)
            .body.setGravityY(300)
        // zombie animations
        this.anims.create({
            key: 'left',
            frames: this.anims.generateFrameNumbers('zombie', { start: 0, end: 1 }),
            frameRate: 10,
            repeat: -1
        });
        this.anims.create({
            key: 'turn',
            frames: [ { key: 'zombie', frame: 2 } ],
            frameRate: 20
        });
        this.anims.create({
            key: 'right',
            frames: this.anims.generateFrameNumbers('zombie', { start: 3, end: 4 }),
            frameRate: 10,
            repeat: -1
        });
        // enable keyboard listeners
        this.cursors = this.input.keyboard.createCursorKeys();
    }

    update() {
        var cursors = this.cursors;
        var zombie = this.zombie;

        var canJump = zombie.velocity.y == 0;
        var left = cursors.left.isDown;
        var right = cursors.right.isDown;
        var zombieAnimation = zombie.anims;

        if (left) {
            zombie.setVelocityX(-160);
            zombieAnimation.play('left', true);
        }
        else if (right) {
            zombie.setVelocityX(160);
            zombieAnimation.play('right', true);
        }
        else {
            zombie.setVelocityX(0);
            zombieAnimation.play('turn');
        }
        if (cursors.up.isDown && canJump) {
            zombie.setVelocityY(-530);
        }
    }
}

export default PlayScene;

index.js

import Phaser from "phaser";
import PlayScene from "./scenes/Play";

const config = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
  physics: {
    default: 'arcade',
    arcade: {
      gravity: { y: 200 }
    }
  },
  scene: [PlayScene]
};

new Phaser.Game(config)

‘this’ refers to the scene. You should not add zombie or cursors to ‘scene’ itself. Make them global. like in the tutorial.

The problem is in this statement:

this.zombie = this.physics.add.sprite(this.width/2, this.height/2, 'zombie')
    .setOrigin(0,0)
    .setBounce(0)
    .setCollideWorldBounds(true)
    .body.setGravityY(300)

this.physics.add.sprite returns a sprite. All of the methods you call next return the same sprite. body.setGravityY, however, returns the physics Body, which is then stored as this.zombie.

In update, it looks like you expect this.zombie to be the original sprite. zombieAnimation is undefined, which creates the error. None of the other code errors because Arcade Sprites and Bodies have similar methods.

Assuming you want this.zombie to be the sprite and not its body, separate the statement so that you store the sprite in this.zombie:

this.zombie = this.physics.add.sprite(this.width/2, this.height/2, 'zombie')
    .setOrigin(0,0)
    .setBounce(0)
    .setCollideWorldBounds(true);
this.zombie.body.setGravityY(300);

This will create another error in update when trying to access zombie.velocity.y - in this line, you treat the object as a body. If zombie is a sprite, use zombie.body.velocity.y to access its body.

There shouldn’t be a problem keeping the references on the scene itself as long as you’re careful not to overwrite any of the existing properties. However, if you’re having trouble figuring out what’s what, it might indeed be easier to store your objects as globals for the time being.

1 Like