How to clear object from previous frame in Flash with AS3? - actionscript-3

I have an object (MovieClip) on stage at some frame, and at the next frame, even though the object is visually removed, it is still there (it has an internal function that generates something on stage periodically, and the stage objects are being generated). I know I can simply stop the action while leaving the frame, but the object will eat up memory and maybe even CPU time for some background actions (and this is a AIR to iOS project so I care about memory and performance). How can I get rid of the object entirely? I expect everything to be removed when I navigate to another frame if it's a designer-placed object (if the object is not generated by ActionScript) and this is the case, but it only gets visually removed.
Thanks,
Can.

Just null your object reference and it's listeners.
...
myMovieClip.removeListeners();//class function
myMovieClip.parent.removeChild(myMovieClip);
myMovieclip = null;
...

Related

On the use of frames and functions in Flash AS3

My question is, in a flash game I use different frames for levels. And I am confused on how functions work for this. My first frame works fine but I need help with using functions on other frames and keeping functions specific to one frame. Any help is appreciated, just a quick simple explanation
You cannot associate a function with a specific frame.
When you execute code on a frame, what actually happens is the MovieClip containing that frame will call a function called addFrameScript(), passing to it a representation of the code you write on the frame.
This means:
Until you visit a frame that defines a function, you cannot call said function.
Once you have visited a frame that defines a function, that function is attached to the parent MovieClip, and you are able to call the function at any point in the timeline that is earlier or later.
If you try to define a new function with the same name on a different frame, you will get a 1021: Duplicate function definition error.
Instead of making a new function for every frame or level, you should make a single function that is able to handle different information that is representative of a level, e.g.
function loadLevel(level:int):void
{
// Do stuff with the value of level.
// For example, this function might look at a data source that maps
// the level numbers to some level data representing tile placement.
}
This could be defined on the first frame, then on each subsequent frame:
loadLevel(1); // Frame 2
loadLevel(2); // Frame 3
// ...etc
All of this of course is not ideal and could be done better avoiding the timeline and instead using to OOP paradigm that AS3 provides.
I have found using multiple levels within the same scene causes no end to headaches for me.
I'm no expert & i'm sure its possible to do so in many cases and I have seen some great games created using 1 frame 1 scene & all code in an external .as.
However I find it much easier myself to just use 1 frame per level and put each level in a different Scene.

as3 symbol variables not initialized yet

I'm initializing symbols in my timeline, and trying to access the variables within those symbols, but they return 0 or undefined even though I set the variables in the symbol's timeline. For some reason the variables haven't been set yet, though the main timeline can see that they exist. How do I make the program wait until the variables have been set?
Best practice to work with classes, not coding in timeline and frames of MovieClip.
I assume you have MovieClip from designer and you want inject some logic to the specific frame. There are many options.
Events
You can trigger event in the specific frame, and you work in normal way (with classes and class members).
//Frame code
import flash.events.Event;
this.dispatchEvent(new Event("IntroDidFinish", true, true));
stop();
//Somewhere in class
myContainer.addEventListener("IntroDidFinish", onIntroFinish, false, 0, true);
function onIntroFinish(e: Event):void{
//Do your stuff
}
Events help you decouple logic from the design(predefined complex MovieClip, etc.)
Waiting for initialisation
As MovieClip reaches some frame, you should wait extra time for initialisation. Thats why 99.9% of AS3 developers don't like MovieClip as holder for any critical data or logic. It means if you call myMovieClip.goToAndStop(8); you can't get myMovieClip.someValue declared in 8 frame after goTo operation. If you still want to go with such approach, easiest solution for you will be Event.ENTER_FRAME, after goTo subscribe for ENTER_FRAME event, for only one update, and do your work ;)

Loader.as returning blank bitmap

I have an application which pulls in Bitmap resources from a server - currently I use the Loader class to do this, then, once they're loaded, generate a BitmapData based on the loader dimensions and draw the instance of Loader directly to it (the BitmapData is used for Away3D textures as well as Bitmap instances, so I have no need for the Loader once fetched).
This has always worked for me, but recently I started getting 0x0 Loaders, and invalid BitmapData as a result.
I stopped doing this:
this.imageBitmap = new BitmapData(this.imageLoader.width, this.imageLoader.height, true, 0);
..and started doing this:
this.imageBitmap = new BitmapData(event.target.content.width, event.target.content.height, true, 0);
Where event is the Event.COMPLETE event fired by the loader. This fixed the dimension problem, but the BitmapData is just a plain white bitmap (and it's set to transparent by default, so this is being drawn into it). Frustratingly, this doesn't happen every time, if I refresh the application it works as it should around 25% of the time, otherwise it plays up like this.
I've got a tight deadline and I'm really screwing about this, if anyone could help or suggest a better way of doing it you'd really be saving my neck!
Sounds like you need to adjust the image decoding policy for the loader - to ensure it decodes the image before COMPLETE fires - then the width and height etc should be reliable.
To do it, just add a suitable LoaderContext object to the Loader.load method:
var loaderContext:LoaderContext = new LoaderContext();
//set decode policy
loaderContext.imageDecodingPolicy = ImageDecodingPolicy.ON_LOAD;
//load image
loader.load(yourUrl, loaderContext);
The default decode policy is ImageDecodingPolicy.ON_DEMAND - which doesnt decode the image until it is actually required.
Lang docs: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/ImageDecodingPolicy.html
Fixed it, stupid oversight and bit of an obscure situation but I'll leave an answer in case anyone runs into something similar.
My loader is contained in an Asset class - when another object requires the internal bitmap, it queries this class - if the bitmap's present, it returns it, if not it loads it with a loader and registers a callback for a COMPLETE event which is fired when the Loader has loaded and transferred its contents to a BitmapData instance.
The stupid mistake I'd made was that, if several objects were querying the same (as-yet-unloaded) asset, it would start reloading the asset each time, creating a new Loader as it did so...so when the first Loader was complete, it would fire an event but no reference to it would exist, not only creating a memory leak but causing the Asset class to extract the BitmapData from the most-recently-created Loader, which was not complete! The asynchronous nature of Loader is the reason it worked sometimes, as on occasion the final Loader would be ready in time for BitmapData extraction.
Simple solution was to create an internal boolean, _isLoading, which is set to true the first time load() is called - any subsequent calls are ignored if it's true, but callbacks still registered, works a treat!

AS3: Major Slowdown

I'm working on a Flash game, and after running my game for a while there is a huge drop in frame rate. There aren't a lot of MovieClips onscreen at once, but MovieClips are being replaced using removeChild and addChild often.
How can one test for problems such as memory leaks? And what are some good AS3 programming standards on this matter?
It seems like you're not preparing your instances of MovieClip for garbage collection. This thread could be extremely helpful to you.
Some of the basic things you want to cover when discarding a MovieClip (or any other Object) properly are:
Remove the object from the DisplayList (if it's a DisplayObject). This is done via what you're doing already, removeChild()
Remove any event listeners that have been applied to the Object. Best thing to do is keep on top of this right from the beginning; by that I mean, when you call addEventListener(), be sure to somewhere in the very near future add a sister removeEventListener() as well.
Remove reference to your Object. This includes, but is not limited to: reference to the Object via being part of an Array/Vector, reference via being stored in a property of another Object, etc.
A suggestion that I can offer is to have in the base class of your objects a method that handles all of this, eg remove() or deconstruct().
Here's an example:
public function deconstruct():void
{
if(parent)
parent.removeChild(this);
removeEventListener(MouseEvent.CLICK, _onClick);
}
And when you extend this class and need other dereferencing features, just build on your deconstruct() method:
override public function deconstruct():void
{
removeEventListener(MouseEvent.MOUSE_OVER, _mouseOver);
var i:int = someArray.indexOf(this);
someArray.splice(i, 1);
super.deconstruct();
}
http://gskinner.com/talks/resource-management/

Flash debugger behaving differently from the player with AS3 and Events

Why this works on flash professional's debugger, but brings null on the compiled SWF?
var firstParameter:SomeObject = new SomeObject();
someLoader = new Loader();
someLoader.contentLoaderInfo.addEventListener(
Event.COMPLETE
, function(evt) {
onLoaded(evt, firstParameter);
}
, false
);
function onLoaded (evt:Event, param:SomeObject):void {
mcOnSceneForTracing.text = param; // this is used for SWF debugging
}
For the record:
To make it work without any issues this can be "solved" by creating a separate scope. However, here I'm wondering why, then, this example even works on the debugger at least.
And, please, if you have a better way other than using two anonymous functions to pass parameters, variables, values, whatever through an Event, do tell! I'm not willing to extend the Event, tho. Too 2005.
mcOnSceneForTracing is what I'm using to "trace" outside the debugger. Suggestions are also accepted here for better (and simpler) ways to do it! I've heard Vizzy is good, but haven't tried it yet.
My guess would be: When loading your resource from the debugger player, the operation finishes instantly, and thus firstParameter is available when your anonymous listener function is called, but when running the swf elsewhere, the load operation takes longer, and then the reference to firstParameter is lost, since it is a local variable.