Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error removing sprite with inputEnabled that has mouse over it #746

Closed
jflowers45 opened this issue Apr 21, 2014 · 15 comments
Closed

Error removing sprite with inputEnabled that has mouse over it #746

jflowers45 opened this issue Apr 21, 2014 · 15 comments

Comments

@jflowers45
Copy link
Contributor

If your mouse is over a sprite that has input enabled, and that sprite is removed while the mouse remains over it, you will start seeing errors in the console with Phaser's signal library when you either click or move the mouse

I've created a live example that is as simple as I can think of. The only relevant code is in the MainMenu.js file. I've pasted its contents below, but I figured the live example would make it as easy as possible for you to see the error. To test the live example, just move your mouse over the maroon "scoreboard" after you click to show the scoreboard and before the timer destroys it. After the timer destroys it, you will see the error in the console.

If you need me to strip out the preloader etc I'm happy to do that, but I'm fairly confident you can very quickly see what I'm talking about.

https://www.flashysubstance.com/phaser_203_GroupDestroy/

============THE ERROR YOU SEE==============
Uncaught TypeError: Cannot read property 'length' of undefined phaser.js:14411
Phaser.Signal.dispatch phaser.js:14411
dispatch phaser.js:14197
Phaser.InputHandler._pointerOutHandler phaser.js:24474
Phaser.Pointer.move phaser.js:21708
Phaser.Mouse.onMouseMove phaser.js:21016
_onMouseMove
============END OF ERROR==============

Here's the code:

BasicGame.MainMenu = function (game) {

};

BasicGame.MainMenu.prototype = {
    showScoreboard:function() {
        console.log("showScoreboard")
        this.scoreboard=this.game.add.sprite(0, 0, 'maroonBG');
        this.scoreboard.inputEnabled=true;
        this.scoreboard.scale.setTo(0.5,0.5);
        this.scoreboard.anchor.setTo(0.5,0.5);
        this.scoreboard.x=this.game.width/2;
        this.scoreboard.y=this.game.height/2;
    },
    hideScoreboard:function() {
        console.log("hideScoreboard");
        this.scoreboard.destroy();

    }, 
    hideClick:function() {
        //after clicking hide, put your mouse over the scoreboard and after it hides, move the mouse around
        this.game.time.events.repeat(Phaser.Timer.SECOND * 1, 1, this.hideScoreboard, this);
    },
    create: function () { 
        console.log("MAIN MENU STATE CREATE"); 
        this.add.sprite(0, 0, 'darkBG');
        var btnShowScoreboard=this.add.button(100, 500, 'sheet1_misc', this.showScoreboard, this, 'btnShowScore_on.jpg', 'btnShowScore_off.jpg', 'btnShowScore_on.jpg');
        var btnHideScoreboard=this.add.button(400,500, 'sheet1_misc', this.hideClick, this, 'btnHideScore_on.jpg', 'btnHideScore_off.jpg', 'btnHideScore_on.jpg');
    }
};
photonstorm added a commit that referenced this issue Apr 22, 2014
…uld throw Signals dispatch errors (thanks @jflowers45, fix #746)

InputHandler._setHandCursor private var wasn't properly set, meaning the hand cursor could sometimes remain (during destroy sequence for example)
All Game Objects have a new property: destroyPhase (boolean) which is true if the object is in the process of being destroyed, otherwise false.
The PIXI.AbstractFilter is now included in the Phaser Pixi build by default, allowing for easier use of external Pixi Filters.
@photonstorm
Copy link
Collaborator

Ahh this bloody bug again. This (and variations on it) are making me re-think how object destruction takes place, but for now it's resolved in the dev branch so please test and let me know.

@jflowers45
Copy link
Contributor Author

hmmm...so I built the dev branch and while it did fix the bug, it seems to have introduced a new one. The next time that I try to change states after running the test, I get this error

TypeError: 'null' is not an object (evaluating 'this.last.next = child') -- line 14143

I haven't worked it into my simple example yet - I actually tried and failed - but do you have any idea what could be causing this?

@jflowers45
Copy link
Contributor Author

ok I can actually re-create the problem now in my simple example.

to recreate: click 'show scoreboard', click 'hide scoreboard', mouse over scoreboard while the timer runs for 1 second and it destroys the scoreboard. At that point, once you try to click 'go' to go to another state, it fails.

If you don't run the scoreboard sequence before that, you can click 'go' and go to the other state with no problem.

https://www.flashysubstance.com/phaser_203_GroupDestroy/

@jflowers45
Copy link
Contributor Author

FYI just ran into it in one other spot - I have a confirm window with yes/no buttons that destroys itself when you click one of the two buttons, and after destroy, going to the next scene fails. which didn't happen in 2.0.3

@photonstorm
Copy link
Collaborator

Yes the issue is the input handler linked list, am trying out a few things now.

@photonstorm
Copy link
Collaborator

There's a brand new version up in dev - could you please test against this? (you'll need to build from source), but I'm using this successfully now across a massive multi-state changing project from within callbacks and elsewhere. It uses the new ArrayList structure for interactive objects, no more linked list. Also the interactive state of an object can persist across state changes now (providing the sprite isn't destroyed).

@jflowers45
Copy link
Contributor Author

Have been able to make 2 errors happen with new one

=====ERROR 1=====
Here's one that's easily reproducible: create the scoreboard and then destroy it
https://www.flashysubstance.com/phaser_203_GroupDestroy/

Uncaught TypeError: Cannot read property '_releasedHandler' of undefined phaser.js:14381
Phaser.ArrayList.callAll phaser.js:14381
Phaser.Pointer.stop phaser.js:22196
Phaser.Mouse.onMouseUp phaser.js:21426
_onMouseUp

=====ERROR 2=====
In my full game I create a 'confirm window' with yes/no buttons that have a callback. I'm getting this error after I call the callback. Let me know if you want me to try to isolate a simple example, or if this is something you understand just be looking at the error message.

phaser.js:14381 TypeError: 'undefined' is not an object (evaluating 'this.list[i][callback]')

@photonstorm
Copy link
Collaborator

Interesting, it must be being deleted before it has a chance to clear its InputHandler.

Have just done another small push to make callAll more solid. Please give this one a test with the same as before and it should resolve error 1, not sure about error 2 though.

@jflowers45
Copy link
Contributor Author

Still getting error 1 in my 'easy' sample -

https://www.flashysubstance.com/phaser_203_GroupDestroy/

Uncaught TypeError: Cannot read property '_releasedHandler' of undefined phaser.js:14396
Phaser.ArrayList.callAll phaser.js:14396
Phaser.Pointer.stop phaser.js:22214
Phaser.Mouse.onMouseUp phaser.js:21444
_onMouseUp

@photonstorm
Copy link
Collaborator

... and take 3, please pull + rebuild.

@jflowers45
Copy link
Contributor Author

woohoo! that fixed both errors.

@photonstorm
Copy link
Collaborator

Sweet. I'll close this one off for now, but please keep an eye on it and don't hesitate to open another issue if you manage to make it break in a different way :)

@jflowers45
Copy link
Contributor Author

I will def keep an eye out. Thanks for the fix!

@totty90
Copy link

totty90 commented Jun 10, 2014

I've done like this:

// Required because if not it will throw an
// error because the this.parent.sprite is
// not found. (Phaser.Inpute.checkPointerOver)
var scheduledItemsToRemoveNextFrame = [];
var scheduleRemoval = function(item){
    scheduledItemsToRemoveNextFrame.push(item);
}
// This should not called directly, is called from
// the loop.
var removeScheduledItems = function(){
    scheduledItemsToRemoveNextFrame.forEach(function(item){
        item.inputEnabled = false;
        item.parent.remove(item);
    })
    scheduledItemsToRemoveNextFrame = [];
}

And when you want to remove a sprite you do: scheduleRemoval(sprite).
Then in your update method call: removeScheduledItems ();

This method can be improved of course for some edge cases.

@totty90
Copy link

totty90 commented Jun 19, 2014

Still an annoying problem...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants