Adding movie clips with for loop action script 3 - actionscript-3

Hey wondering if anybody can help me, i am trying to add a load of move clips and make them clickable to the stage in action script 3,i can work out the spacing of them later i just keep getting errors while trying to add them using this :
for(var x:int = 1; x <= 10; x++)
{
var this["cardPrint"+x] :MovieClip = new this["card_"+x]();
this.addChild(this["cardPrint"+x]);
this["cardPrint"+x].addEventListener(MouseEvent.CLICK, this["click_"+x]);
}
a point in the right direction would help alot
thank you

this is a scope indicator that indicates the current class. So this["cardPrint"+x] is actually trying to find a variable with that name, but you can't declare a variable that is already a reference.
The only way to do what you want is like this:
public dynamic class Foobar
{
public function Foobar()
{
for(var x:int = 1; x <= 10; x++)
{
this["cardPrint"+x] = new this["card_"+x]();
this.addChild(this["cardPrint"+x]);
this["cardPrint"+x].addEventListener(MouseEvent.CLICK, this["click_"+x]);
}
}
}
The key is making the class dynamic. That allows you to create variable names at run time and to create them in string form using the scope["varName"] syntax. If you are doing this on the timeline in Flash Pro, as I get the feeling you are, this is simply not possible the way you want to do it. You would be better off creating objects in the loop and storing them in an array to access them that way instead of using the syntax described above.
The datatype of each object created will be the same as whatever is instantiated, so you won't be able to set it to be MovieClip or similar.
"card_"+x also needs to be an instantiable object (a Class). If it is not, you cannot instantiate it and it will always error out.
I do want to caution you that is a very poor way of putting this together. The room for error is incredibly large and using this syntax will be difficult to do and difficult to read in your code.

Related

Implement an Undo Redo in flex

How to implement Undo Redo operation in flex 4 for maintain history?
I'm working with flex UIComponent and DisplayObjects for creating and editing diagrams,but
in flex there is no way to handle user operation history directly.
there is any idea to achieve this?
You could implement the Command Pattern for all actions with execute and undo methods, and queue them up.
so when the user wants to do some thing - lets say create an AddFiveToTotal class and executes:
public method execute():void{
totalModel.add( 5 );
}
This class would then be stored on a FIFO queue.
if the user needs to undo the command would be popped and the undo function called:
public method undo():void{
totalModel.subtract( 5 );
}
for redoability, don't pop, just iterate the queue
also take a look at the Memento Pattern
If you are using any of the currently popular MVC(S) frameworks you will undoubtably find a util that some one has already created
You can acheive with help of memento pattern. It hard to track all properties better you can what are property need to use for undo/redo operation.
Memento Design pattern
Memento pattern
Demo sample with source code http://www.flairpy.com/mementoPattern/MementoSample.html
There are several ways you can address to this problem. First is to keep the states of your whole canvas in a Vector (I mean have a listener for all the things user can do on the stage and saving the state after a change) and then have an index of current state saved, so that you could move through your Vector and put the needed state on the stage. This is the easiest way to approach undo/redo functionality, but beware that you'll have to make clones of objects a lot and this will become a memory hog if you're going to deal with a lot of objects or a lot of undo/redos.
The second approach is to only keep what changed in that vector, so that you won't have to create and clone a lot of objects, but only save one object in your Vector which will contain all the properties that have changed and their last values. This will get you something like this:
private var mHistory:Vector.<Object> = new Vector.<Object>();
private var mCurrentIndex:int = -1;
public function storeState(state:Object)
{
mHistory.push(state);
mCurrentIndex++;
}
public function undo():void
{
if(mCurrentIndex < 1)
return;
mCurrentIndex--;
//here you could test for values that could have changed
var item:DisplayObject = this.getChildByName(mHistory[mCurrentIndex].name);
if(mHistory[mCurrentIndex].x != undefined)
item.x = mHistory[mCurrentIndex].x;
// etc. you get the point. Note that this is only comfortable if only several things can change
}
And the call for storeState function would be like this:
var state:Object = { name:DisplayObjectName, x:120, y:20 };
storeState(state);
Again, you will have to listen to all movement and changes if you want to record them.

when is a good time to use a loop?

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--;
}

Dynamically instantiate a typed Vector from function argument?

For a game I'm attempting to develop, I am writing a resource pool class in order to recycle objects without calling the "new" operator. I would like to be able to specify the size of the pool, and I would like it to be strongly typed.
Because of these considerations, I think that a Vector would be my best choice. However, as Vector is a final class, I can't extend it. So, I figured I'd use composition instead of inheritance, in this case.
The problem I'm seeing is this - I want to instantiate the class with two arguments: size and class type, and I'm not sure how to pass a type as an argument.
Here's what I tried:
public final class ObjPool
{
private var objects:Vector.<*>;
public function ObjPool(poolsize:uint, type:Class)
{
objects = new Vector.<type>(poolsize); // line 15
}
}
And here's the error I receive from FlashDevelop when I try to build:
\src\ObjPool.as(15): col: 18 Error: Access of undefined property type.
Does anybody know of a way to do this? It looks like the Flash compiler doesn't like to accept variable names within the Vector bracket notation. (I tried changing constructor parameter "type" to String as a test, with no results; I also tried putting a getQualifiedClassName in there, and that didn't work either. Untyping the objects var was fruitless as well.) Additionally, I'm not even sure if type "Class" is the right way to do this - does anybody know?
Thanks!
Edit: For clarification, I am calling my class like this:
var i:ObjPool = new ObjPool(5000, int);
The intention is to specify a size and a type.
Double Edit: For anyone who stumbles upon this question looking for an answer, please research Generics in the Java programming language. As of the time of this writing, they are not implemented in Actionscript 3. Good luck.
I have been trying to do this for a while now and Dominic Tancredi's post made me think that even if you can't go :
objects = new Vector.<classType>(poolsize);
You could go something like :
public final class ObjPool
{
private var objects:Vector.<*>;
public function ObjPool(poolsize:uint, type:Class)
{
var className : String = getQualifiedClassName(type);
var vectorClass : Class = Class(getDefinitionByName("Vector.<" + className + ">"));
objects = new vectorClass(poolsize);
}
}
I tried it with both int and a custom class and it seems to be working fine. Of course you would have to check if you actually gain any speed from this since objects is a Vector.<*> and flash might be making some implicit type checks that would negate the speed up you get from using a vector.
Hope this helps
This is an interesting question (+1!), mostly because I've never tried it before. It seems like from your example it is not possible, which I do find odd, probably something to do with how the compiler works. I question why you would want to do this though. The performance benefit of a Vector over an Array is mostly the result of it being typed, however you are explicitly declaring its type as undefined, which means you've lost the performance gain. So why not just use an array instead? Just food for though.
EDIT
I can confirm this is not possible, its an open bug. See here: http://bugs.adobe.com/jira/browse/ASC-3748 Sorry for the news!
Tyler.
It is good you trying to stay away from new but:
Everything I have ever read about Vector<> in actionscript says it must be strongly typed. So
this shouldn't work.
Edit: I am saying it can't be done.
Here see if this helps.
Is it possible to define a generic type Vector in Actionsctipt 3?
Shot in the dock, but try this:
var classType:Class = getDefinitionByName(type) as Class;
...
objects = new Vector.<classType>(poolsize); // line 15
drops the mic
I don't really see the point in using a Vector.<*>. Might as well go with Array.
Anyhow, I just came up with this way of dynamically create Vectors:
public function getCopy (ofVector:Object):Object
{
var copy:Object = new ofVector.constructor;
// Do whatever you like with the vector as long as you don't need to know the type
return copy;
}

Best way to reuse an element from an Array?

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

AS3 Object Filtering

Ok. so I'm working on an app that retrieves items from a db and builds a gallery. I've done this a ton of times, and it should be simple.
I'm running into problems, because in this gallery, I get results from a db that includes both image files, and other files. Let's just say I can't change anything but the flash, so I need to detect if it's an image, and only display it if it is.
My question is: How the hell can I delete a property from an object without the object staying the same size? I use a count() function to generate pagination data, so I can't just 'null' them, and as I understand it, delete() is not an option either.
My solution for this was to just create another object, filter the good items with a for in loop, then pop them in to another object, but each item in the object is an object, and I have no push() function for objects.
So, in desperation, I am using an increment to add the objects to the new object using an index (goodItemsObject[index] = allItemsObject[object]), but that seems like a really gruesome way of getting around this problem.
Here's some code:
var filteredMO = new Object();
var newFile = 0;
for each(var file in mediaObject){
if(check_file(file)){
filteredMO[newFile] = file;
newFile++;
}
}
mediaObject = filteredMO;
check_file() just returns true or false, mediaObject is all full of objects.
I'd much prefer to be doing this:
for each(var file in mediaObject){
if(check_file(file)){
//remove_from_object_for_reals(mediaObject[file]);
}
}
I realize that might not be possible (would it throw off the for loop?), but something similar would be sweet. I'd love to be able to let the gc grab all these useless objects hanging out.
any ideas?
thanks,
Jesse
What you are using to store your object now is called an associative array. You cannot remove a key-value from an associative array. What you need is a dictionary (which as3 has a build-in one http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/utils/Dictionary.html).
import flash.utils.Dictionary;
var dict:Dictionary = new Dictionary();
then you can remove a key from your dictionary by calling
delete dict["myKey"]