phaserjs / phaser-ce

Phaser CE is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
http://phaser.io
MIT License
1.34k stars 491 forks source link

Error calling destroy in objects #630

Closed leandrop20 closed 5 years ago

leandrop20 commented 5 years ago

Uncaught TypeError: Cannot read property 'enabled' of undefined

here: Phaser.Input.callAll = function(handler, pointer) { var list = this.interactiveItems.list; var i = list.length;

while (i--)
{
    var item = list[i];

    if (item.enabled) <========================= HERE!!!
    {
        item[handler](pointer);
    }
}

};

when:

calling method destroy in objects;

version: 2.13.0

samme commented 5 years ago

When does it happen?

leandrop20 commented 5 years ago

I have two functions;

  1. create => create a container group and add 5 sprite image;
  2. destroyAll => remove children and container with method destroy;

first: call create(); next: destroyAll(); next: call create(); again; and now, when I try to call destroyAll again, so happen the error;

samme commented 5 years ago

Can you post your code?

leandrop20 commented 5 years ago

import Sprite from '../com/script4/display/Sprite'; import ImageSuper from '../com/script4/display/ImageSuper'; import SimpleButton from '../com/script4/display/SimpleButton'; import Event from '../com/script4/events/Event';

import EventType from '../enums/EventType';

export default class Menu extends Sprite {

constructor(_loadOptions, _loadGame) {
    super();
    Menu.this = this;

    this.loadOptions = _loadOptions;
    this.loadGame = _loadGame;

    var bg = new ImageSuper("bgMenu");
    this.addChild(bg);

    var title = new ImageSuper("spriteAll.title");
    title.y = -70;
    this.addChild(title);
    TweenMax.to(title, 2.0, { y:10, repeat:-1, yoyo:true, ease:Linear.easeInOut });

    this.btPlay = new SimpleButton("spriteAll.btPlay");
    this.btPlay.name = "play";
    this.btPlay.x = (this.btPlay.width * 0.5) + 21;
    this.btPlay.y = (this.btPlay.height * 0.5) + 378;
    this.addChild(this.btPlay);

    this.btOptions = new SimpleButton("spriteAll.btOptions");
    this.btOptions.name = "options";
    this.btOptions.x = (this.btOptions.width * 0.5) + 237;
    this.btOptions.y = (this.btOptions.height * 0.5) + 449;
    this.addChild(this.btOptions);

    this.events(EventType.ADD);
}

onClick(e) {
    Menu.this.events(EventType.REMOVE);

    switch (e.target.name) {
        case "play":
            Menu.this.loadGame();
            break;
        case "options":
            Menu.this.loadOptions();
            break;
    }
}

events(_type) {
    this.btPlay[_type.name + "EventListener"](Event.TRIGGERED, this.onClick);
    this.btOptions[_type.name + "EventListener"](Event.TRIGGERED, this.onClick);
}

destroy() {
    this.events(EventType.REMOVE);
    super.destroy();
}

}

samme commented 5 years ago

Thanks. Can you post the error trace?

What class do Menu and Sprite extend?

If you're extending a game object, you should avoid overwriting this.events.

leandrop20 commented 5 years ago

VM58121:17334 Uncaught TypeError: Cannot read property 'enabled' of undefined at Phaser.Input.callAll (eval at module.exports (addScript.js:NaN), :17334:22) at Phaser.Pointer.stop (eval at module.exports (addScript.js:NaN), :20083:15) at Phaser.MSPointer.onPointerUp (eval at module.exports (addScript.js:NaN), :18511:37) at HTMLCanvasElement._onMSPointerUp (eval at module.exports (addScript.js:NaN), :18351:26)

samme commented 5 years ago

I can't reproduce this but I guess I can fix it.

You could add this to troubleshoot:

console.assert(game.input.interactiveItems.list.every(Boolean))
samme commented 5 years ago

I'm going to leave Phaser CE's behavior unchanged (as of v2.13.0) on this unless I can reproduce the issue.

game.input.interactiveItems shouldn't contain any undefined values so it's normal to get an error. Maybe check your remove/destroy code.

XWILKINX commented 5 years ago

I get this same error on 2.13.1 when changing a sprite's inputEnabled to false from true. It's only on one particular button in my code, which has no difference from other buttons. A separate instance of the same button only sometimes triggers the error, so it's pretty random.

It does not happen in 2.12.0 for me.

samme commented 5 years ago

@XWILKINX can you post a code sample?

ts1985 commented 5 years ago

I have the same error. The problem is, if I set the button to inputEnabled = true; But not with every button. Seems to be where the button is in the list.

The interactiveItems changed during the while loop. I deactive 3 Buttons with inputEnabled = true; But the list starts with all 28 items. The first i loops are correct, then the list changed to 25 items and then, the exception throws, because i is 25 and list[25] doesn't exist anymore.

I think, it's a timing problem.

var list = this.interactiveItems.list; var i = list.length;

    while (i--)
    {
        var item = list[i];

        if (item.enabled)
        {
            item[handler](pointer);
        }
    }
samme commented 5 years ago

OK, it's worth changing, then.

You can try a workaround by setting input.enabled = false instead.