mattlangr

Getting a reference to events

Recommended Posts

In other languages, libraries and frameworks, when using and event listener the event object would be be sent as an argument to the event handler. This is useful for getting the target, etc, but more important for removing the event. Typically one could then generate events dynamically, say needed in a for loop, in local variables and destroy the event and null the variable after it calls the handler/callback. I don't see this kind of thing in Phaser 3. Am I missing it? I have gotten around the issue in a current game by creating a stack/array of timer events then destroying the oldest. I was only able to do it this way because the events all had the same delay (basically they are delayed calls), so oldest out worked. Thinking forward I am wondering if there is a way to get the event object as an argument? I did try putting the timer event into a local variable and then including that variable in the arguments but it didn't work. I'm still new to phaser and probably missing something.

Thanks in advance.

Share this post


Link to post
Share on other sites

Early versions of v3 (while still in beta) used this approach, and it was replaced with the current way (of the actual values being passed to the callback), because in order to use the first approach you have to create new Event objects and then populate them with the relevant data every single time. As events were worked into some really hot areas of code (update loops, input handlers, tweens, animation, etc), this constant object creation and reallocation was taking up considerable CPU time for no tangible benefit. Now that every Game Object is an event emitter it's crucial they don't waste time doing this. Also, we use EE3 for event handling, which offers no control over event propagation or destruction (again, it's eschewed in favor of performance)

Had Phaser been a typical web app I'd have kept the original approach, but as it's for making games, every little bit counts - and when you have got a game with potentially tens of thousands of event emitters running around, it's important they're as lean as can be.

In short, the reason you can't get a reference to the event as such, is because there isn't one. This doesn't mean you can't emit your own events internally though. There's nothing stopping you from having your game create new Event objects and have those emitted and handled by the callbacks, it's just the internal Phaser generated events don't.

Share this post


Link to post
Share on other sites

Thanks for the fast reply. Yes performance is paramount and I appreciate the choices, and am impressed by Phaser 3. I think I confused my question by speaking about events in general when I really am asking about preventing memory leaks by destroying dynamically generated timer events. The response is really helpful offering info about the event system in general - thanks. I still need to dive deeper into the event emitter. Looking at: http://labs.phaser.io/view.html?src=src\time\remove timer event.js I saw one can use .remove(false) on the event object. Your example though used a single timer event in a global variable. 

Here's what I did. Included in the event handler each time a card is clicked, if it's the second card and not a match (concentration game) a timer is included to allow the user to see the cards before they flip back:

...
_flipBackTimerStack.push(
    this.time.addEvent({ delay: 1200, callback: this.returnCards, callbackScope: this, loop: false, args: [holdFirst,holdSecond ] })
);

 

and then

returnCards(firstCard, secondCard) {
    _flipBackTimerStack[0].remove(false);
     _flipBackTimerStack.splice(0,1);
    if (firstCard != null) firstCard.startFlip('back');
    if (secondCard != null) secondCard.startFlip('back');
}

Again this is a bit lame as it depends on the last in first out. Sorry this is another boring matching game, but it has the good example of generating lots of timer events that need to be removed from memory. They don't destroy themselves right? And no way to get a reference to the timer event if in a local variable, or no variable anonymous event, right? 

The alternative for this game would have been to use a single global and only one timer event, and if another pair is created while waiting the 1.5 seconds, override the delay and make the timer event trigger immediately, clearing the previous cards, then use the single global variable to hold a new timer event. I was going to ask this as a separate question but wanted to dig deeper, so far I have not found a method to override the delay in the docs. Of course if there is a way that's only a solution for this game mechanic and not the issue in general.

Thanks sorry to stretch out a simple question but maybe it's useful.

Share this post


Link to post
Share on other sites

When a TimerEvent has completed (i.e. reached its duration, or repeat limit) it will be moved to the `_pendingRemoval` array within the Clock class. This is purged at the start of every game step. Or, you can invoke it directly by calling the `removeAllEvents` method. If you do this, all TimerEvents are immediately flagged for deletion. The TimerEvents are a bit of a misnomer re: their naming, because they're not actually Events in the EE3 sense of the word, and aren't emitted in the same way internally. They do, however, self manage themselves. They hold no outside references other than the callback they invoke, so as long as you let the Clock class clean them up, they shouldn't linger in memory at all.

The only exception is when you set them to loop infinitely.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.