Creating instances in loop freezes app - actionscript-3

I have a movie clip exported for ActionScript as a class and I am creating many instances from it inside a loop and adding it to stage.
when I test the app on mobile, it freezes for a second when the loop starts and then everything works back.
The following is an example of how it looks:
for(var i:int = 0; i < 20; i++)
{
var mc:MC = new MC();
mc.textField.text = "mc"+i;
mc.y = i * mc.height;
addChild(mc);
}
So, I am asking if there is a better way to do it without freezing?
Thanks.

One way to improve the performance would be to utilize the "object pool pattern" to reuse the already generated objects over time:
It is a software creational design pattern that uses a set of
initialized objects kept ready to use – a "pool" – rather than
allocating and destroying them on demand. A client of the pool will
request an object from the pool and perform operations on the returned
object. When the client has finished, it returns the object to the
pool rather than destroying it; this can be done manually or
automatically.
More information and a working sample code on the "object pool pattern" is available on the Adobe's website :)

Related

ActionScript 3 & Runtime Resources

So, I've been working on a project in AS3 and I've come across yet another peculiar bit of behavior.
Background: It's a turned based game. I've been optimizing it for the past week and now it runs like butter (consistently!);
Issue: However, when I try to continue playing from a saved game, it runs less consistently. Specifically, it will run the first few turns normally, then it will begin to degrade in performance dramatically until it freezes my computer. Please note, this only happens during battle, not during the menus or during any other time.
Is there something regarding Actionscript that I'm missing? I'm saving the game with cookies using the built in SharedObject class. The code I'm using to save and load the data is below (I also use the byte array class).
public static function saveGame():void
{
/// save the game using byte array
registerClassAlias("Mob", Mob);
registerClassAlias("Skill", Skill);
var ba:ByteArray = new ByteArray();
var savedData:* = Main.glblPlayer.setSaveObject();
ba.writeObject(savedData);
ba.position = 0;
so.data.game5 = ba;
so.flush();
}
public static function loadGame():Boolean
{
if (so.data.hasOwnProperty("game5"))
{
var ba:ByteArray = new ByteArray();
ba = so.data.game5;
ba.position = 0;
var loadedData:Object = ba.readObject();
glblPlayer.loadSaveObject( loadedData );
return true;
}
else
{
so.data.game = new Object();
return false;
}
}
I just double checked the above code and tested it a bit more with some variation. If it's loaded 1-3 times, it's fine, but after that the performance degrades during battle with each turn. I have no idea how the technical stuff of ActionScript works or how it saves resources aside from that it's cookies and it's in the cache.
Can anyone shed some light on this by maybe going a bit more into how saving/loading with flash games are done in AS3? Or is "use sharedObject" all there is?
Use a profiler (like Adobe scout) to see what causes the problem.
If I had to guess, it's because your (de-)serialisation routines do not work properly and have a memory leak. But again arguing about this or looking at the code wondering what might be the problem is a pointless endeavour. Use a profiler to see exactly what the problem is.

Embedded image assets and the memory consumption

I have a few contradicting misconceptions about how Flash handles image assets. I'm going to write them down here, please correct me where I'm wrong.
I have an embedded image
[Embed(source = "../../lib/images/myImage.png")]
public var embeddedImage:Class;
How do I use it in my app without using unreasonable amounts of operating memory?
I was going to do this:
var bData:BitmapData = (new embeddedImage() as Bitmap).bitmapData;
And from that point on use bData if I ever want to display this picture anywhere, ensuring that there is only one bitmapdata per image.
But what worries me is that embeddedImage still stays, doesn't it? There are basically two copies of this image in the operating memory, right?
What should I do instead? May be I should instantiate new embeddedImage() each time I want to use it? But that looks even worse, now I'm clearly instantiating a bunch of unneeded copies.
If I loaded the image using the Loader class I would end up with only one copy of the bitmapdata if I wanted to, provided GC did a good job clearing the loader after it was done.
The [Embed] block embeds the image into the application. This doesn't use RAM*, it increases the size of the application itself (the .swf or whatever format you export to).
When you use new EmbeddedImage(), you create an instance of the embedded image. This instance is what consumes RAM. Each instance of that image will consume additional RAM.
When you access the bitmapData property of that embedded image, it does not create a new instance or consume additional RAM, it refers to existing data which is already consuming RAM.
Because the BitmapData is the data which represents an image, it is obviously the largest. Knowing this, we look at ways to use a single instance of BitmapData for any graphics we want to display. Depending on the display architecture you've opted to use, there are different ways to go about referring to that BitmapData when drawing multiple instances of the same image.
As an example, we have your instance of EmbeddedImage created:
var embeddedImage:EmbeddedImage = new EmbeddedImage();
And we have a 'canvas', which is a single Bitmap added to the stage:
var canvas:Bitmap = new Bitmap();
canvas.bitmapData = new BitmapData(500, 500, false, 0xFFFFFF);
addChild(canvas);
Using the method copyPixels(), we can copy across a section of data from the embeddedImage, to the canvas without needing to make another instance of BitmapData, which would consume RAM equivalent to the source for each time we want to draw the graphics. Example:
var drawPosition:Point = new Point();
var sourceRect:Rectangle = embeddedImage.bitmapData.rect;
// Draw the embeddedImage 50 times.
canvas.bitmapData.lock();
for(var i:int = 0; i < 50; i++)
{
canvas.bitmapData.copyPixels(embeddedImage.bitmapData, sourceRect, drawPosition);
drawPosition.x += 10;
}
canvas.bitmapData.unlock();

Loading an XML in ActionScript 3 before an event listener happens

I'm trying to fill some data from an xml feed we made into my Flash movie. The main action of this is in the constructor for MediaElementJS's .as file.
Anyway, the main problem is that I keep reading there is no way to load a URL synchronously in AS3 (which i still find hard to believe). This constructor calls both parse('url') and a function addEventListener(EVENT.ADDED_TO_STAGE, initializeAds);
Now the ads need info from the XML but the XML aint ready yet. I tried to call the ads at the end of the XML parser when I knew it would be prepped but it messes them up and the ad values never change from their defaults..
Oh wherefor art thou actionscript locking mechanism..
So is there anyway to preload data from a URL?
CODE:
public function LoadXML(e:Event):void
{
removeEventListener(Event.COMPLETE, LoadXML);
var xmlData:XML = new XML(e.target.data);
episodeData.pre.type = xmlData.episode.pre.ad.#type;
episodeData.pre.url = xmlData.episode.pre.ad.text();
episodeData.video = Number(xmlData.episode.video.#id); /*************** I CAN'T REMEMBER ***********/
episodeData.pageTitle = xmlData.episode.video.#pagetitle;
episodeData.title = xmlData.episode.video.#title;
episodeData.source = xmlData.episode.video.source.text();
episodeData.post.type=xmlData.episode.post.ad.#type;
episodeData.post.url=xmlData.episode.post.ad.text();
episodeData.nextEpisode=xmlData.episode.post.nextepisode.text(); //if not empty redirect to this
xmlLoading = false;
//THIS IS WHERE I TRIED TO CALL THE FUNCTION I NEED TO LOAD LATER
}
public function parse()
{
var xmlLoader:URLLoader = new URLLoader();
//var xmlData:XML = new XML();
xmlLoader.load(new URLRequest(rootURL + '/episode.aspx?associd=' + _episode));
//xmlLoader.addEventListener(Event.COMPLETE, processXML);
xmlLoader.addEventListener(Event.COMPLETE, LoadXML);
}
I've tried it with a static URL address and whatnot of course but no dice.
The code in the constructor works if I dynamically assign a static value but if I try chaining to events together to get the dynamic value and dynamic assignment it crunches.
In the constructor, definitely runs both by themselves:
parse();
// Google IMA EventListener
addEventListener(Event.ADDED_TO_STAGE, initialize);
Loading URLs is always asynchronous, so add the event listener in the response function for the URL loader.
Now your question sounds like you tried that but had some problem, so post that code and let us take a look.
Edit START
When I have multiple asynchronous calls that happen and I need something to happen after both of them are done I usually use booleans to store if each one has happened yet, then in a third function they both call I check both the booleans.
Here's how I'd do that:
protected function viewnavigatorapplication1_preinitializeHandler(event:FlexEvent):void
{
var loader1:Loader = new Loader();
var loader2:Loader = new Loader();
loader1.addEventListener(Event.COMPLETE, loader1_completeHandler);
loader1.load(new URLRequest("http://www.whitehouse.gov"));
loader2.addEventListener(Event.COMPLETE, loader2_completeHandler);
loader2.load(new URLRequest("http://www.nasa.gov"));
}
private function loader1_completeHandler():void
{
loader1Done = true;
//Maybe do some stuff here
moveOn();
}
private function loader2_completeHandler():void
{
loader2Done=true;
//Maybe do some stuff here
moveOn();
}
private function moveOn():void
{
if(!loader1Done||!loader2Done)
return;
//Do whatever needs to be done once both asynchronous events have completed
}
If this isn't your problem I think you need to provide more of the code in place of the comments that indicate other things happen, because it is a bit unclear.
For example I'm not sure what you mean by "The code in the constructor works if I dynamically assign a static value but if I try chaining to events together to get the dynamic value and dynamic assignment it crunches." Also since there's no example of the data or what the rootURL is there's no way to debug from here to understand what's going wrong.
Since there's no error we would need to be able to re-compile some portion of your code locally to give any better feedback.
Edit END
Blocking or synchronous calls are a horrible idea with regard to network communications due to the lack of reliability of networks and/or servers. If a front end application locked up to wait for a response before doing any other processing it would result in a horrible user experience, this is why there is no synchronous remote calls.
What happens with a synchronous call when the server bombs out, the client remains locked even though no response will result, the user can't interact with anything else in the front-end because it's waiting for said response which will never come? It's much better that remote calls of any sort are done in an asynchronous fashion, the same is true with local disk access in Java (or otherwise) where using asynchronous non-blocking calls is generally a better way to go to allow the other processes within an application to continue regardless of the state or use on the disk.
What you're doing should work just fine, you make a call to a remote service, it responds with some result and hits your "listener" or "callback" function then you want to do something with the results you can call another function, and the data is there.
It sounds to me like the only thing that's not happening is updates after the fact aren't being reflected in the UI, this is probably due to a lack of Bindable metadata/event dispatching for the properties. Have you inspected the result in the event that returns, have you put breakpoints in the method that is meant to be called after the data has returned? What you're doing is completely possible and it even looks like you have most of it right, but there's definitely something your doing wrong that's resulting in you not being able to make this work. If you can explain the behavior a bit clearer that will help, also what do you do here:
//THIS IS WHERE I TRIED TO CALL THE FUNCTION I NEED TO LOAD LATER

Adobe AIR. Get MD5 of a file

I've done it this way, but Adobe Air hangs for several seconds.
private function test():void
{
fileStream = new FileStream();
fileStream.addEventListener(IOErrorEvent.IO_ERROR, fileError);
fileStream.addEventListener(Event.COMPLETE, opened);
fileStream.openAsync(filePath, FileMode.READ);
}
protected function opened(event:Event):void
{
var bytes:ByteArray = new ByteArray();
fileStream.readBytes(bytes);
fileStream.close();
// MD5Stream from package com.adobe.crypto.MD5Stream https://github.com/mikechambers/as3corelib/blob/master/src/com/adobe/crypto/MD5Stream.as
var md5stream:MD5Stream = new MD5Stream;
trace(md5stream.complete(bytes)); // md5
}
How to make the process of getting md5 without hanging?
Try using Bloody's MD5 implementation. It's apparently a lot faster.
While it will speed up the hash calculation, perhaps even adequately, you're not really solving the underlying problem, which is that you want a non-blocking operation in a single threaded application model. In Flash/AIR, this is generally done by breaking the work up into smaller chunks, and doing only one chunk's worth of processing each frame, instead of all at once during one frame. There's even a cool framework to simplify this!
I noticed that the library you're currently using, MD5Stream, is built for incremental updates -- so you can easily feed it little chunks of the file each frame until the entire file is processed. This will allow the frame rate to stay relatively constant while the hash is computed.

Does ActionScript have an equivalent of a "core dump"?

Here's my situation: I'm working on an AS3-based game and I'd like to have a "Report a problem!" function within the game so that users can submit feedback to me.
When my user reports a problem, I'd like to get as much information as I can about the state of their game; basically what objects are in memory, what the values are of all those variables inside all those objects; essentially the same information I can get when I hit a breakpoint in the debugger.
Is there a simple way of doing this? I'm afraid that I'll spend several days trying to write a bunch of functions that gets all this information for me, only to have somebody tell me afterwards, "Oh, why didn't you just call ASUtils.getSnapshot()"?
There is no generic way in AS3 to dump the state of your variables, but there are several things we do that you might find useful:
Capture a log of recent click activity. Use stage event listener to log clicks and trace the object "path" up the parent chain to the stage. The object path is just all the DisplayObject names, like: screenMain.dialogBuyItem.buttonBuy
Capture a screenshot, reduce it to a small thumbnail, JPEG encode it, and upload it to your server along with their feedback. We also do this when there is an exception (see #4). as3corelib has JPEG encoding functions in com/adobe/images
Write a command-line pearl or PHP script you can run on your AS3 code before you publish it that will inject call tracing at the top of each function call. This allows call history to be logged. While it's not as good as a full stack, it will give you some indication of what your code has been doing recently.
Trap asserts and unhandled exceptions and log them to your server with click activity and call history trace. Unhandled exception listeners are new in flash 10.1, but most users have this feature. You can check for that support and add a listener like this:
// Check for the presence of the Flash 10.1 global Error event (exception) handler class.
// If it exists, we'll listen for it and it will allow us to report errors to our server.
if ( loaderInfo.hasOwnProperty( 'uncaughtErrorEvents' ) )
loaderInfo.uncaughtErrorEvents.addEventListener( "uncaughtError", onUncaughtError ); // UncaughtErrorEvent.UNCAUGHT_ERROR
If you have global state variables that you want to log with feedback, you can write a function to dump them to a string for uploading with the user feedback. While you can enumerate class and object properties using for each, this only works for public members. Google around and you'll find some functions people have written to dump objects and array data recursively using this enumeration trick.
i'd like to add it as a comment, but don't want to lose code formatting
this is what i'm using to trace complex objects:
private function parseObject(o:Object, prefix:String = '>'):String {
var retStr:String = '';
for (var s:String in o) {
retStr += prefix + s + ' = ' + o[s] + '\n';
if (typeof(o[s]) == 'object') {
retStr += parseObject(o[s], prefix + '>');
}
}
return retStr;
}
hope it'd be helpful