I have a pretty complex game with many views and many controllers, and it works really well but periodically lags. I am trying to fix up my code so it's as efficient as i can make it, but i have some questions as to who AS3 handles events.
Now here is a very basic example:
AppController loads 5 different OverlayControllers. Each one of those OverlayControllers dispatch an Event.COMPLETE when they are done that my AppController listens to. I have a constant EventListener listening to those OverlayControlllers no matter where I am in the game.
Should i only have those listeners there when the Overlay is open? And Remove them when they close?
Should i bypass the event listener period and just pass the AppController to the OverlayControllers so it can just call a public function instead of requiring an EventListener?
Just to be clear these aren't objects that i'm removing from the stage. They are just being hidden. If i ever remove an object i always remove its event listeners before destroying them.
First of all download Adobe Scout (http://www.adobe.com/devnet/scout/articles/adobe-scout-getting-started.html) and see what's causing the "lags" - probably garbage collection ...then fix the issue. Removing as many listeners as possible is always a good thing but make sure that those are causing the issue. Profile memory usage and try to keep object creation/destruction to a minimum to avoid garbage collection (during the main game loop).
Related
Will make this brief, I have a game map with units on it and had finalized a fully interactive minimap where the units on the minimap have event listeners for rollover/rollout (displays a small popup unit data summary) and click (selects the "real" unit on the main game map and scrolls the viewpoint to that location). All done, tested, working.
I then implement an interactive scrollable unit list with more status summary data and dozens of objects with rollover/rollout/click listeners. All tested and working fine.
Then I go back and look at my minimap, and the listeners on the mini-ships aren't working anymore. Things tried:
Debug code to make sure listeners still being added
Debug to watch the one place where I remove those listeners to make sure that ain't happening unexpectedly
Debug to watch all the places I refresh that dialog to make sure every iteration adds the listeners back
Can't see that there is any transparent object on top intercepting
Checked mini-ship parents to make sure I didn't turn off mouseChildren or something like that somewhere
No added stage-level listener, in fact I killed all of them temporarily to test this
What happens when I debug with a breakpoint on the mini-ship listener handler is nada. It's no longer receiving mouse events. So either something I haven't thought of has stopped them from listening or something I don't know of is intercepting.
So what is the strategy here? How can I find the break in the chain?
Well knowing what the actual problem was certainly gives us the advantage of hindsight... that being said, you could have detected the error by adding a trace call inside your function that adds the listener and another one inside your function that removes it. Then you would have seen that it isn't getting re-added. Or you could set break points there.
yeah, I need to restart my application, my actioscript 3 code or at least remove all the content in stage to upload the beginning.
This is not movie, so playing with gotoandplays is not an option.
Thanks!
Best practice would be for each object that carries a strong listener to also listen for the Event.REMOVED_FROM_STAGE event, and destroy all its listeners and handle the properties you wish to save.
while(numChildren) removeChildAt(0);
Called from the root (or main timeline) will remove all symbols from the current container in scope. I assume what you're calling it in is added to the display list, so
while(MovieClip(root).numChildren) MovieClip(root).removeChildAt(0);
Is appropriate code.
First structure design.
For example: make a gameContainer the sprite variable add to stage. while the game progresses, all object add gameContainer. When the game is ended, remove the event, you do not need to remove all the objects. And calls the function that default settings you have made that.
// removeEventListener
// removeAllObjects about following
while (gameContainer.numChildren)
{
gameContainer.removeChildAt (0);
}
I'm working on a Flash project which is separated into separate scenes.
In Scene 1 I have multiple MovieClips (which include event listeners for RESIZE (and others) inside them).
In Scene 2 I have a few common MovieClips and new ones (which also include event listeners for RESIZE (and others) inside them).
After clicking a button from Scene 1 to go to Scene 2, it's fine, except for if I resize the stage and then I get the following error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
I know it's related to the event listeners, but it would be unrealistic to remove them each individually as it's expected there will be many.
If I undertand your situation correctly, I think you will in the end need to remove each listener individually, or add the resize listener only once. Since you mentioned scenes, am I right to assume you are working on the timeline? I also am assuming the null object reference error comes from a scene that has been removed from the stage, making reference to a display object that is no more, a ref to the stage after the scene has been removed, or just calling a function (the resize handler) on an object that no longer exists.
Some way to deal with this are:
Add some checking in the listener handler functions
if (!this.stage) return
To avoid the errors, but will not help if the object the function is a method of has been removed.
To avoid needing remember to remove hundreds of listeners, create removeAllListeners and addCustomEventListener functions. Instead of the usual addEventListener, call you addCustomEventListener which in turn will call addEventListener. Have addCustomListener store the target, listener function and event string in a dictionary or array of objects. removeAllListeners can loop through the dictionary or array and remove all your listeners. It is a bit like setting up an event hub, but does not go quite that far.
Instead of adding the RESIZE event listener to each scene, add it only once. Then in the listener function call a function on whichever scene is the active scene or view.
This last one is the approach I have seen most often, and is the most bullet proof. It may be tricky to implement on the time line, I have always been a little hazy on timeline variable scope.
Yes, so far as I know there is no good automated way to do this, however it would be a good practice to create a registerAllListeners and a removeAllListeners methods that manually add and remove the appropriate listeners to your object.
There was many discussions about this problem, but I want to pay attention on the situations that IMHO seems not so clear:
Yes the general rules are:
Remove chachedAsBitmap
Stop movieClip if playing
Remove events
Delete references
etc.
But let's look:
First Example:
I have nested sprite (ex: mainSprite), it contains other sprites with dynamic textFields in it (and are chached as bitmaps), just textFileds and MovieClips with event listeners on it (with weak reference).
When I need to remove this sprite I need first to remove all it's nested content via loops or just
removeChild(mainSprite);
mainSprite=null;
is just enough?
Second Example:
I have some sprite in which I'm loading bitmap and manipulating with bitmapData, later I'm just replacing content of this sprite with another bitmap, is allocated memory for older bitmap automatically erases and is overwritten or it still exists?
Third example:
I have some "graphics template" MovieClip (in library with Export for Actionscript property set on it) which I'm adding on the stage and filling with dynamic data (and adding event listeners), let's say that it's one scene of the app, on another scene I need same MovieClip with other dynamic data, but inbetween need to clear my stage (need something like transition animation which is also library MovieClip), what's the best way: to set this MovieClip visible property to false (while transition animation is plays) and then reuse it, or just remove it with removeChild and then add when add with addChild once more?
All I wrote is more about Air Mobile, cause in most cases for the desktop these situations aren't so problematic, but in case of mobile development they are.
You can visually monitor memory usage along with fps etc using this lib: http://code.google.com/p/flash-console/
hope that helps.
P.S. gc in flash is always a weird thing :)
First example: removing mainSprite from display list is enough if there are only weak listeners on its children.
Second example: I'd advice reusing the same object with visible = false. Recreating the same object is more resource expensive plus you get another instance of the same thing being in memory before it gets gc'ed.
I know the AS3 Loader's class unloadAndStop() supposes to unload and stop everything on a SWF's stage when I load one, but does it also changes objects within the library (even if they are not on stage?).
I'll describe my problem to clear it up: I am loading SWFs dynamically into my AS3 application and extract required symbols from them using applicationDomain and getDefinition. The stage of the SWF/FLA I am loading is empty, and all I have are exported symbols in my library.
The problem happens when I load symbols which have pre-compiled clips inside of them (in my case, a Partigen emitter, but I don't think it really matters), which probably has event listeners or timers - the code on these clips stops working and acts weird when unloadAndStop() is called by the Loader which loaded the clip's parent SWF. I assumed unloadAndStop() removes a required event listener from it, but not sure why (again, it's not on the stage).
I'd write my own kind of unloadAndStop() that filters these pre-compiled clips or checks what's truly going on there, but I am pretty sure that unloadAndStop() does things which are unavailable through the API.
What can explain this behavior? Anyone can think of a possible solution?
Thank you.
Make your loader in this way:
myLoader.contentLoaderInfo.addEventListener( Event.INIT , myLoaderHandler, false, 0, true);
It solves some problems due to unloadAndStop().