I have a Array of Characters objects (extends Sprite).
public static var charlist:Array;
When a Character die, I set a flag to indicate that.
char.die = true;
When I spawn a new player, I check against this flag, to reuse the slot. This is where the problem comes.
What is the best way to do that? Actually I have this approach:
char = new Char();
/* ... */
for (var i:Number = 0; i < Char.charlist.length; i++) {
if (Char.charlist[i].death) {
Char.charlist[i] = char;
return;
}
}
But the problem is that I come from C++ and I think calculating the index every iteration is wasteful.
I would do this, but this doesn't work in AS3, since I can't access by reference the item:
char = new Char();
/* ... */
for (var i:Number = 0; i < Char.charlist.length; i++) {
var char_it:Char = Char.charlist[i];
if (char_it.death) {
char_it = char;
return;
}
}
Just a note: charlist is a static member of class Char.
Do you have any ideas or better approaches?
Thanks!
The "optimized" version doesn't optimize much, I think.
YOur code does not perform 2 accesses in every iteration. It does just when you happen to find a dead Char; and after that you return. So, no big deal, I think.
Personally, I don't think reusing array slots is going to make a big difference either. And, maybe it could be degrade (but the worst part is that your code could be simpler if you avoid it). Suppose you have 100 chars, 60 of which are dead, and you have a loop that runs every frame and performs some check / action on every live char. You'd be looping over 100 chars, when you could loop over 40 if you mantained a list of live objects and a separte list of dead objects, ready to reuse them. Also, the "dead list" could be handled as a stack, so no iteration is needed to get a char.
Anyway, I see 2 things you could easily optimize in your code:
1) retrieve the list length outside the loop:
Do this:
var len:int = Char.charlist.length;
for (var i:Number = 0; i < len; i++) {
Instead of this:
for (var i:Number = 0; i < Char.charlist.length; i++) {
The compiler won't optimize away the call to length (following the ecmascript spec).
2) Avoid static access (for charlist). It's known to be considerably slower than instance access.
Edit:
Re-reading your question, I realize I misunderstood part of it. You're not trying to reuse Char objects, but rather array slots. Still, I don't think reusing array slots is worth it (arrays in Actionscript are non fixed); but something that could help performance is reusing the Char objects themselves. Reseting a Sprite is generally cheaper than creating a new one.
You could manage this with a pool of "dead" objects, from which you can take one and "bring it back to life" when you need, instead of creating a new one.
This post talks about object pools (the blog itself is a good source for Actionscript stuff, especially for performance and data structures topics; worth taking a look):
http://lab.polygonal.de/2008/06/18/using-object-pools/
Why not to use a list instead of array and simply remove dead ones from the list and add new one when needed?
Is there a good reason to try to reuse the slot?
What are you trying to optimize?
Is there a reason you can't just splice out the desired character and push a new character onto the array?
var characters:Array = ["leo", "raph", "don", "mike"];
characters.splice(1, 1);
trace(characters);
characters.push("splinter");
trace(characters);
If you're looking for storage by reference, checkout AS3's Dictionary object or even Flash 10's Vector (if storage is consistent by type; quite fast):
http://www.gskinner.com/blog/archives/2006/07/as3_dictionary.html
Related
When hiding nodes, the performance seems to slow down quite a lot with larger IFC HVAC models (80000 nodes and upwards). On a standard computer this takes almost 10 seconds. I have two models and want to hide one of them. Currently this is done with rootId. Is there any modifications to be made to make this faster? What would be the fastest way to hide all the nodes?
var vm = new Autodesk.Viewing.Private.VisibilityManager(viewer.impl, viewer.model);
var instanceTree = viewer.model.getData().instanceTree;
var rootId = instanceTree.getRootId();
vm.hide(rootId);
vm.setNodeOff(rootId, true);
When showing parts of the same file, with few thousand nodes this seems to be quite a bit faster. Eventhough the nodes are shown one by one.
var totalNodes = nodesToIsolate.length;
for (var i = 0; i < totalNodes; i++) {
vm.show(nodesToIsolate[i]);
vm.setNodeOff(nodesToIsolate[i], false); // True = hide completely
}
So you are saying that the second approach is quite faster than the first one... in that case what prevents you to use the second approach over the first? You could traverse the model structure from rootId to determine all the node and then use second approach, or am I missing something?
I am guessing that a faster approach would be to affect a custom ShaderMaterial to each fragment of the model and control the visibility from the shader code, however traversing the model to affect the material would also take time, but the operation could potentially be performed at an earlier stage.
Also you could completely unload the model from the scene with viewer.impl.unloadModel(model), obviously if you need to restore it later it will take time.
I have been trying to learn actionscript 3 for a while now and there are somethings that get me. Like when should I use a loop(for, while, etc)? I watch videos and read articles on the subject and I always run into this example witch really doesn't help me that much:
for(var i:Number = 0; i < 10; i++)
{
trace(i);
}
If anyone can help me on the subject and maybe let me pick there brain a little I would really appreciate it.
Thank you.
You use loops anytime you need to do repetitive tasks.
So if you had 1000 objects that you needed to perform the same operation on, it will be more practical to use a loop instead of writing variations of the same code 1000 times.
A flash example: Let's say you had 10 movieClips that you wanted to all play on a given action.
you could do this:
mc1.play();
mc2.play();
mc3.play();
mc4.play();
mc5.play();
mc6.play();
mc7.play();
mc8.play();
mc9.play();
mc10.play();
For 10 it's just annoying but not a huge deal. If you had 100, or 1000, or 10000 it would be insane. Plus then what if you need to change your code later?
A better way would be to use a loop. Lets say those 10 clips (or any number of clips) were all the children of a parent object called clips.
for(var i:int=0; i<clips.numChildren;i++){
var mc:MovieClip = clips.getChildAt(i);
mc.play();
}
That code would do the exact same thing. You're looping through all the children of the clips parent, and telling everyone to play. Need to change it to gotoAndPlay(3)? then you just have one line to update.
This is a very simple example (and just one of many reasons you'd use a loop), you can probably guess when you get into working with more complex data and objects how loops help you code repetitive tasks.
In general, I use a for loop when I need an index.
For example I might want an array of indexes that represents which MovieClips in a given array are visible :
var visibleClips:Array = new Array;
for (var index:int = 0;index < arrayOfClips.length;index++)
{
var clip:MovieClip = arrayOfClips[index];
if (clip.visible)
{
visibleClips.push(index);
}
}
A while loop I commonly use for something like removing all the children from a DisplayObject like this :
while (container.numChildren > 0)
{
container.removeChildAt(0);
}
As you can see, I really did not need an index in that situation, so it's simpler to use the while loop.
As my old programming teacher said:
"Use for loops when you know how many iterations you want/need to do"
I.e looping through a list, array, vector etc.
"And use while loops when you are not sure."
I.e looping through a whole file (for reading binary data) or doing continuous events that stops for a certain condition.
That being said you could probably apply both for and while loops for most cases. Personally I mostly use for-loops.
Like prototypical said the while loops is great when removing all children of a container but this could also be achieved using a for loop like:
for(var i:int = 0; i < numChildren; i++)
{
removeChildAt(i); i--;
}
I have just been trying to fix a few memory leaks in my project and have discovered an interesting problem. It seems like a vast majority of my 'Point' objects are not being picked up by the Garbage Collector. Each frame it creates about 5000 new Point objects and less than 10% of them seem to ever get picked up. Even when you use code like this:
var tempPoint :Point = new Point();
tempPoint = null;
Even if I repeat it over 500 times, only a tiny fraction seem to be erased. This is really stating to get on my nerves now and I was wondering if anyone has encountered this before, knows how to solve it / get around it, or cares to enlighten me on what exactly I am doing wrong.
Would love to know anyone's thoughts on this
ps. I am using The Miner to check the resource usage
Edit: Have now done a quick check where I had the program running for about an hour and although the memory usage went up about 140MB it did start garbage collecting at this point and did not go past that. So they will be picked up but not until you have several million created ;)
How long are you waiting for them to be erased?
If you are creating 5000 new objects per frame, it's probably a good idea to use an object pool.
class PointPool {
private var _points:Vector.<Point>;
public function PointPool() {
_points = new Vector.<Point>();
}
public function createPoint(x:Number, y:Number):Point {
var p:Point = null;
if( _points.length > 0 )
p = _points.pop();
else
p = new Point();
p.x = x;
p.y = y;
return p;
}
public function returnPoint(point:Point):void {
_points.push(point);
}
}
Just a thought :)
I will quote Grant Skinner to answer your question:
A very important thing to understand about the Garbage Collector in FP9 is that it’s operations are deferred. Your objects will not be removed immediately when all active references are deleted, instead they will be removed at some indeterminate time in the future (from a developer standpoint).
[...]
It’s very important to remember that you have no control over when your objects will be deallocated, so you must make them as inert as possible when you are finished with them.
So, what's happened with your code? FP created something near 5000 instances of Point. If you look the memory usage over time you may notice that it will drop to the initial value after a few seconds.
The best way to avoid this behaviour is to pool the created objects and reuse them instead of creating a new one.
I am uploading files using the upload() method of the FileReference class. I want to display the current connection speed and I was wondering what was a good way to do that.
My current technique is to use a Timer every 1 mili second such as follows:
var speed:Function = function(event:TimerEvent):void {
speed = Math.round((currentBytes - lastBytes) / 1024);
lastBytes = currentBytes;
}
var speedTimer:Timer = new Timer(1000);
speedTimer.addEventListener(TimerEvent.TIMER, uploadSpeed);
and currentBytes gets set into the ProgressEvent.PROGRESS. This technique seems imprecise. I was wondering what other ways I could use to calculate the upload speed while uploading and display it in real time.
Any ideas or opinions are welcomed!
Thank you very much,
Rudy
If that code block is a copy and paste it certainly won't work as you have expected it to. You declare speed as a function within which you appear to redefine it as a number. I appreciate the Flash IDE let's you get away with sketchy grammar, but code like that is going to lead you into all kinds of trouble. Try to be explicit when writing your code.
Try something like this, replacing yourLoader with whatever identifier you assigned to the uploader:
private var speed:Number = 0;
private var lastBytes:uint = 0;
private function uploadSpeed(event:TimerEvent):void
{
speed = Math.round((yourLoader.currentBytes - lastBytes) / 1024);
lastBytes = yourLoader.currentBytes;
}
private var speedTimer:Timer = new Timer(1000);
speedTimer.addEventListener(TimerEvent.TIMER, uploadSpeed);
That should calculate how many bytes moved in 1 second intervals.
Edit:
You might like to make the interval a little smaller than 1000ms and calculate an average speed for your last n samples. That would make the number your users see appear more stable than it probably does right now. Make speed an Array and .push() the latest sample. Use .shift() to drop the oldest samples so that you don't lose too much accuracy. Trial and error will give you a better idea of how many samples to hold and how often to take them.
You can moniter the upload speed on the server and then send that data back to the client. This technique is often used for ajax file upload forms.
I've been looking to clear an array in ActionScript 3.
Some method suggest : array = []; (Memory leak?)
Other would say : array.splice(0);
If you have any other, please share.
Which one is the more efficient?
Thank you.
array.length = 0 or array.splice() seems to work best for overall performance.
array.splice(0); will perform faster than array.splice(array.length - 1, 1);
For array with 100 elements (benchmarks in ms, the lower the less time needed):
// best performance (benchmark: 1157)
array.length = 0;
// lower performance (benchmark: 1554)
array = [];
// even lower performance (benchmark: 3592)
array.splice(0);
There is a key difference between array.pop() and array.splice(array.length - 1, 1) which is that pop will return the value of the element. This is great for handy one liners when clearing out an array like:
while(myArray.length > 0){
view.removeChild(myArray.pop());
}
I wonder, why you want to clear the Array in that manner? clearing all references to that very array will make it available for garbage collection. array = [] will do so, if array is the only reference to the array. if it isn't then you maybe shouldn't be emtpying it (?)
also, please note that`Arrays accept Strings as keys. both splice and lenght operate solely on integer keys, so they will have no effect on String keys.
btw.: array.splice(array.length - 1, 1); is equivalent to array.pop();
array.splice(0,array.length);
this has always worked pretty well for me but I haven't had a chance to run it through the profiler yet