2

I am facing a problem during my development in javascript with Phaser. I try to call a method inside a method of a class but I have an error.

Here is my class :

import Enemy from '../classes/Enemy';
import Turret from '../classes/Turret';
import Bullet from '../classes/Bullet';


class GameScene extends Phaser.Scene {

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

    preload()
    {
        this.load.image('turret', './www/assets/tour_simple.png');
    }

    drawGrid(graphics)
    {
        graphics.lineStyle(1, 0x0000ff, 0.8);
        for(var i = 0; i < 8; i++)
        {
            graphics.moveTo(0, i * 64);
            graphics.lineTo(640, i * 64);
        }
        for(var j = 0; j < 10; j++)
        {
            graphics.moveTo(j * 64, 0);
            graphics.lineTo(j * 64, 512);
        }
        graphics.strokePath();
    }

    canPlaceTurret(i, j)
    {
        return this.map[i][j] === 0;
    }

    placeTurret(pointer)
    {
        var i = Math.floor(pointer.y/64);
        var j = Math.floor(pointer.x/64);
        if(this.canPlaceTurret(i, j)) {
            var turret = this.turrets.get();
            if (turret)
            {
                turret.setActive(true);
                turret.setVisible(true);
                turret.place(i, j);
            }
        }
    }

    damageEnemy(enemy, bullet)
    {
        // only if both enemy and bullet are alive
        if (enemy.active === true && bullet.active === true) {
            // we remove the bullet right away
            bullet.setActive(false);
            bullet.setVisible(false);

            //todo mettre dans une classe constante
            var BULLET_DAMAGE = 25;
            // decrease the enemy hp with BULLET_DAMAGE
            enemy.receiveDamage(BULLET_DAMAGE);
        }
    }



    create() {
        this.add.text(200, 230, 'good!', { fill: '#0f0' });

        var graphics = this.add.graphics();

        this.map = [[ 0,-1, 0, 0, 0, 0, 0, 0, 0, 0],
            [ 0,-1, 0, 0, 0, 0, 0, 0, 0, 0],
            [ 0,-1,-1,-1,-1,-1,-1,-1, 0, 0],
            [ 0, 0, 0, 0, 0, 0, 0,-1, 0, 0],
            [ 0, 0, 0, 0, 0, 0, 0,-1, 0, 0],
            [ 0, 0, 0, 0, 0, 0, 0,-1, 0, 0],
            [ 0, 0, 0, 0, 0, 0, 0,-1, 0, 0],
            [ 0, 0, 0, 0, 0, 0, 0,-1, 0, 0]];

        //TODO creer une classe qui dessine le path
        // the path for our enemies
        // parameters are the start x and y of our path
        this.path = this.add.path(96, -32);
        this.path.lineTo(96, 164);
        this.path.lineTo(480, 164);
        this.path.lineTo(480, 544);

        graphics.lineStyle(3, 0xffffff, 1);
        // visualize the path
        this.path.draw(graphics);

        this.enemies = this.physics.add.group({ classType: Enemy, runChildUpdate: true });

        this.nextEnemy = 0;

        var graphics = this.add.graphics();
        this.drawGrid(graphics);

        this.turrets = this.add.group({ classType: Turret, runChildUpdate: true });
        this.input.on('pointerdown', this.placeTurret);

        this.bullets = this.physics.add.group({ classType: Bullet, runChildUpdate: true });

        this.physics.add.overlap(this.enemies, this.bullets, this.damageEnemy);
    }

    update(time, delta) {
        if (time > this.nextEnemy)
        {
            var enemy = this.enemies.get();
            console.log(enemy);
            if (enemy)
            {
                enemy.setActive(true);
                enemy.setVisible(true);
                // place the enemy at the start of the path
                enemy.startOnPath();

                this.nextEnemy = time + 2000;
            }
        }
    }


}

export default GameScene;

And an error occurs during my game :

TypeError: this.canPlaceTurret is not a function

The error is from the placeTurret method where I call the canPlaceTurret method.

I have tried some things like adding an attribute to my class : self = this; and call my function with self.canPlaceTurret but there is always the problem. I think it is a scope problem but I don't know how to solve that.

Another important information : we are using Webpack

Thanks for reading :).

Gama11
  • 31,714
  • 9
  • 78
  • 100
Buisson
  • 479
  • 1
  • 6
  • 23

2 Answers2

3

Try replacing:

this.input.on('pointerdown', this.placeTurret);

with:

this.input.on('pointerdown', pointer => this.placeTurret(pointer));

(slighthy edited following your comment below)

Basically, when you pass your method as a callback, it becomes a simple function reference. When that function is called later, this won't refer to the class instance you're expecting, because it's no longer called in the context of your class.

By using the fat arrow syntax, you create a specific callback instead, and explicitly tells it to call the method in the context of the current (as in, at the time said callback is defined) this.

Alternatively, you can also do:

this.input.on('pointerdown', this.placeTurret.bind(this));

Instead of creating a new anonymous function, this takes your method as a reference (like it was doing to begin with) but manually binds the current this to it.

Please refer to this post for a more detailed explanation.

Jeto
  • 14,596
  • 2
  • 32
  • 46
  • 1
    Yes it was that ! Thank you very much. Just I have replace with that : `this.input.on('pointerdown', (pointer) => this.placeTurret(pointer));` Because I need the pointer object for the function :) – Buisson Dec 22 '18 at 23:49
  • Like the answer mentions, this binds up a new function reference, which needs more memory for something unnecessary. You need to bind the scope of the function so that "this" isn't the event: `this.input.on('pointerdown', this.placeTurret.bind(this));` would be the more performant solution I believe. Please let me know if I'm wrong! – Fredrik Schön Dec 23 '18 at 12:45
0

Won't it work without using the this keyword at all in your placeTurret() method when calling the canPlaceTurret()?

 placeTurret(pointer)
        {
            var i = Math.floor(pointer.y/64);
            var j = Math.floor(pointer.x/64);
            if(canPlaceTurret(i, j)) {
                var turret = this.turrets.get();
                if (turret)
                {
                    turret.setActive(true);
                    turret.setVisible(true);
                    turret.place(i, j);
                }
            }
        }
SabU
  • 603
  • 6
  • 4