AS3 - Using a For Loop to Update Multiple Points and Their Values in an Array - actionscript-3

I'm a bit new with AS3 (but not really with coding) so please forgive my ignorance. I'm creating a small function that will be called by a Main Function to update the position of 52 Pointers that have the x and y position of multiple point objects (empty movie clips). It will also then update two global arrays with those values (one array for the x and one for the y).
The problem is, as there are 52 of them, and they will probably grow in quantity, I'd like to be able to use a FOR function to do it, but I can't seem to be able to figure it out.
I get this error: Access of undefined property _point.
Here is a piece of the code that dream about:
function happyFunc():void
{
var avpointers:int = 52;
var vpointx:Array = new Array();
var vpointy:Array = new Array();
for (aa=0; aa<vpointers; aa++)
{
vpointx[aa] = _point[aa].x;
vpointy[aa] = _point[aa].y;
}
}
And this is the code that I'm stuck with...
function reallySadFunc():void
{
_point1 = localToGlobal(new Point(point1.x,point1.y));
//...
_point52 = localToGlobal(new Point(point52.x,point1.y));
vpointx[0] = _point1.x;
vpointx[1] = _point2.x;
//...
//oh god there are 104 lines of this why do I have to suffer
}
Thank you!

If I read your question correctly, I think this is what you need:
public static const CLIP_COUNT:int = 52;
// ...
private function happyFunc(parentClip:DisplayObjectContainer):void
{
var vpointx:Vector.<Number> = new Vector.<Number>(CLIP_COUNT, true);
var vpointy:Vector.<Number> = new Vector.<Number>(CLIP_COUNT, true);
var clipPoint:Point = new Point ();
var globalPoint:Point;
for (var i:int = 0; i < CLIP_COUNT; i++)
{
var childClip:DisplayObject = parentClip.getChildByName("point" +
(i + 1).toString());
clipPoint.x = childClip.x;
clipPoint.y = childClip.y;
globalPoint = parentClip.localToGlobal(clipPoint);
vpointx[i] = globalPoint.x;
vpointy[i] = globalPoint.y;
}
// do something with vpointx and vpointy - they're local variables
// and will go out of scope unless you declare them as class members
// or somehow return them from this function.
}
This function works by taking the parent display object (the one that contains the 52 movie clips - this could be the Stage) and iterates through them by getting each movie clip by name. The code assumes that your movie clips are called point1, point2, ..., point52.
To speed up the local-to-global coordinate conversion, two Point objects are created and then reused during the for loop to avoid creating many temporary Point instances.
Instead of using Array, use Vector.<Number> - this class has better performance than Array does.

Related

Can anyone help me change this code from AS2 to AS3

This will be a simple clock. I've been using AS2 since I learned Flash in early 2000s. It's time to move on.
for (a=1; a<60; a++) {
duplicateMovieClip("dot0", "dot"+a, 10+a);
_root["dot"+a]._rotation = a*6;
_root["dot"+a].gotoAndStop(1);
}
Adobe published ActionScript 2.0 Migration that helped me tremendously back in the day.
Some specifics related to your code:
Properties aren't prefixed with underscores, ex _rotation is now rotation, and _root is now root.
root is not global, it is a property of display objects, and it is null if the display object is not in the display list.
duplicateMovieClip does not exist anymore. You should export your symbol to a class and use new operator and addChild() to create an instance and add it to the display, ex:
var dot:Dot = new Dot();
addChild(dot);
Display objects created in code are not automatically given a name and assigned to a property on its parent when added to the display. You can set the name and use getChildByName on its parent. Example:
var dot:Dot = new Dot();
dot.name = "dot" + i;
addChild(dot);
var n:int = 10;
var dot10:Dot = getChildByName("dot" + n) as Dot;
But this is a bit cumbersome, so in most cases it makes more sense to just store your display objects in your own array and reference them by index:
var dots:Array = [];
var dot:Dot = new Dot();
addChild(dot);
dots.push(dot);
var firstDot:Dot = dots[0];
That should get you started.
Thanks to help here and elsewhere, this is what works for me:
var i:Number = 1;
var dots:Array = [];
for (i=0; i<60; i++) {
var dot:Dot = new Dot;
addChild(dot);
dots.push(dot);
dot.x=683;
dot.y=436;
dot.rotation = i*6;
dot.gotoAndStop(1);
}
The clock I'm making don't have hands but the dots change color for the hours minutes and seconds. Thanks everybody who helped

AS3 Best way to declare variables inside loop

Is it possible better to declare variables without having to write one by one?
I need 200 but... no way.
My code i have:
var var0:Array = new Array();
var var01:Sprite = new Sprite();
var var02:Sprite = new Sprite();
var var03:Sprite = new Sprite();
etc to 200...
And inside for loop:
for( var i:Number = 0; i < arrayBig.length; i++ ){
var0[i] = new Sprite();
...
}
But Why cant I write var var0[i]:Sprite = new Sprite(); in the statments?
The error is Error #1086 Syntax error: expecting semicolon before
Thank you very much!!
You cannot index independent variables and you cannot concatenate variable names to form names of other variables (well, not the way you attempted).
You need to create an array of Sprite objects. An array is a data structure that stores several things at once. (A one-dimensional array is called a vector.)
To store sprites in a vector, you'd write:
var sprites:Vector.<Sprite> = new Vector.<Sprite> ();
for ( var i:int = 0; i < 200; i++ )
{
sprites.push ( new Sprite () );
}
This loop creates 200 Sprite instances and stores all of them in the sprites array (really, Vector). You can then access individual sprites by simply indexing them:
sprites[n]....
where n goes from 0 to N-1 if the Vector has N total elements.
i will answer for your question.
"But Why cant I write var var0[i]:Sprite = new Sprite(); in the statements?"
we cant override one object with that of the other same object in the class. thats the reason, we are declaring as "var0[i] = new Sprite();". spl case for sprite object in flex.

AS3 Can't access MC on Stage

I have 54 MC's on stage, generated dynamically. Now I want to get their x and y positions when rolling over but I am having problems getting the path correct e.g.
function copyFlightCellData():void {
var r; var s;
var cellData:Array = new Array ();
for (r = 0; r < 54; r++){
//var copyCellData = new MovieClip();
cellData[r] = Object(root).mc85.name; //["mc"+r+r];
trace("$$$$$$$$$$$$$$$$$$$$$" + cellData[r]);
}
}
I used the list objects in debug and they are listed in _level0 e.g.
Movie Clip: Frame=1 Target="_level0.mc85"
Not sure why I can't access their properties.
This is the code that created the MC's
// Create copies of flightCell for board grid
var my_mc = new flightCell();
my_mc.name = "mc" + i + j;
trace("^^^^^^^^^^^^^^****************" + my_mc.name);
addChild(my_mc);
Answer is pretty simple, use the DisplayObjectContainer object's, in this case root, getChildByName() method, for example:
var sprite1:Sprite = new Sprite();
sprite1.name = "sprite1";
addChild(sprite1);
trace((root as DisplayObjectContainer).getChildByName("sprite1").name); // output : sprite1
It's probably a better idea to store the movieclips you have on your stage in an array to begin with.
To access it by name you have to assign a name to them when you create them.
mc85.name = "mc85";
As an alternative that I recommend, you can use getChildAt(index) : http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObjectContainer.html?filter_flash=cs5&filter_flashplayer=10.2&filter_air=2.6#getChildAt()
Also, I highly recomend you to create an empty movieclip or sprite and add all of this mcs to them instead of the root.

Unloading a Loader with actionscript 3

Hello and thank you very much for looking at this. I've spent too many hours struggling.
The code below loads a slideshow of four images, along with thumbnails for those images. It works fine.
I've added a button called "invis_button", that when pressed is supposed to remove the 3 loaders that make up the slideshow, using the removeChild command for each loader.
But this is the problem, there are 3 loaders involved in the slide-show. The removeChild command successfully removes one of the loaders (named "loader3"), but not the other two ("container3", and "thumbLoader3"). It returns an error stating "access of undefined property thumbLoader3" or "Container3".
Can someone tell me why this is ? Or better still, how to make that button (invis_button) unload the entire slide-show.
var images3:Array = ["ad_bona1.jpg", "ad_bona2.jpg", "ad_darkhawk1.jpg", "ad_darkhawk2.jpg"];
var thumbX3:Number = -375;
var thumbY3:Number = 220;
var loader3:Loader = new Loader();
loader3.load(new URLRequest("assets/ad_bona1.jpg"));
addChild(loader3);
loader3.alpha = 0;
loadThumbs3();
function loadThumbs3():void
{
var thumbLoader3:Loader;
var container3:Sprite = new Sprite();
addChild(container3);
container3.buttonMode = true;
for(var i3:uint = 0; i3 < images3.length; i3++)
{
thumbLoader3 = new Loader();
thumbLoader3.load(new URLRequest("assets/thumbs/" + images3[i3]));
thumbLoader3.x = thumbX3;
thumbLoader3.y = thumbY3;
thumbX3 += 85;
container3.addChild(thumbLoader3);
thumbLoader3.addEventListener(MouseEvent.CLICK, thumbClicked3);
}
}
function thumbClicked3(event:MouseEvent):void
{
var path3:String = event.currentTarget.contentLoaderInfo.url;
path3 = path3.substr(path3.lastIndexOf("/") + 1);
loader3.load(new URLRequest("assets/" + path3));
}
///PROBLEM BELOW, button removes only "loader3" and not the other two for some reason
invis_button.addEventListener(MouseEvent.CLICK, unload_loaders);
function unload_loaders(event:MouseEvent):void{
removeChild(loader3);
removeChild(thumbLoader3);
removeChild(container3);
}
Not sure if this is the entire reason behind what you're observing... but for starters, "thumbloader3" and "container3" are scoped locally to the loadThumbs3() method, which means once you finish executing the function, Flash's handles to those objects are lost (not to mention being in an entirely different scope)... try creating class-level properties for those two. Once that's done you should be able to successfully remove them from the stage later on.
I hope that you're also properly destroying your objects, and for the sake of brevity you just chose to omit that code above.
I've edited the code you had above & put the properties into the proper scope. (the multiple copies of thumbLoader3 are now collected inside of a vector (specialized array) so that they can be properly addressed when it comes time to destroy them)
I also wrote you a proper destroy method. ;)
I haven't tried it on my own machine, but give it a spin & see how it goes.
var images3:Array = ["ad_bona1.jpg", "ad_bona2.jpg", "ad_darkhawk1.jpg", "ad_darkhawk2.jpg"];
var thumbX3:Number = -375;
var thumbY3:Number = 220;
// begin new instance properties..
// created a new property, allowing you to group (and hold on to) the multiple thumbLoaders
var thumbLoader3Vector:Vector.<Loader> = new Vector.<Loader>();
var container3:Sprite;
// end new instance properties
var loader3:Loader = new Loader();
loader3.load(new URLRequest("assets/ad_bona1.jpg"));
addChild(loader3);
loader3.alpha = 0;
loadThumbs3();
function loadThumbs3():void
{
// this is where container3 used to be declared
container3 = new Sprite();
addChild(container3);
container3.buttonMode = true;
for(var i3:uint = 0; i3 < images3.length; i3++)
{
var tPtr:int = thumbLoader3Vector.length;
thumbLoader3Vector.push(new Loader());
// this is where thumbLoader3 used to be declared & instantiated
thumbLoader3Vector[tPtr].load(new URLRequest("assets/thumbs/" + images3[i3]));
thumbLoader3Vector[tPtr].x = thumbX3;
thumbLoader3Vector[tPtr].y = thumbY3;
thumbX3 += 85;
container3.addChild(thumbLoader3Vector[tPtr]);
thumbLoader3Vector[tPtr].addEventListener(MouseEvent.CLICK, thumbClicked3);
}
}
function thumbClicked3(event:MouseEvent):void
{
var path3:String = event.currentTarget.contentLoaderInfo.url;
path3 = path3.substr(path3.lastIndexOf("/") + 1);
loader3.load(new URLRequest("assets/" + path3));
}
///PROBLEM BELOW, button removes only "loader3" and not the other two for some reason
invis_button.addEventListener(MouseEvent.CLICK, unload_loaders);
function unload_loaders(event:MouseEvent):void{
// since the thumbLoader3 Loaders are children of container3 in the display list, we need to remove them first
for(var $i:uint = 0;$i<thumbLoader3Vector.length;$i++)
{
removeChild(thumbLoader3Vector[$i]);
// also make sure you remove the listener, so that the object will be picked up by garbage collection
thumbLoader3Vector[$i].removeEventListener(MouseEvent.CLICK, thumbClicked3);
}
// and then just set the entire vector to null
thumbLoader3Vector = null;
// remove the loader3 object & set it to null
removeChild(loader3);
loader3 = null;
// remove the container3 object & set it to null
removeChild(container3);
container3 = null;
}

Add multiple movieclips, not replacing the old ones

So, in short, my problem is this. I am using a variable which is a movieclip loaded from an external swf. I want to "spawn" multiple instances of the movieclip that all react to the same code, so for example if I say var1.x = 100, they all are at 100x. But my problem is when I run addChild(var1) multiple times(I'm not actually typing in addChild(var1) over and over, I just have it set to add them at random times), the new child just replaces the old one, instead of making multiple movieclips. Should I do something like
var var1:MovieClip
var var2:MovieClip = new var1 ?(which doesnt work for me btw, gives me errors)
Oh, heres the code, and also, I am pretty new to as3 fyi, still don't even know how arrays work, which was my second guess to the problem.
var zombieExt:MovieClip;
var ldr2:Loader = new Loader();
ldr2.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoaded2);
ldr2.load(new URLRequest("ZombieSource.swf"));
function swfLoaded2(event:Event):void
{
zombieExt = MovieClip(ldr2.contentLoaderInfo.content);
ldr2.contentLoaderInfo.removeEventListener(Event.COMPLETE, swfLoaded2);
//zombieExt.addEventListener(Event.ENTER_FRAME, moveZombie)
zombieExt.addEventListener(Event.ENTER_FRAME,rotate2);
function rotate2 (event:Event)
{
var the2X:int = playerExt.x - zombieExt.x;
var the2Y:int = (playerExt.y - zombieExt.y) * 1;
var angle = Math.atan(the2Y/the2X)/(Math.PI/180);
if (the2X<0) {
angle += 180;
}
if (the2X>=0 && the2Y<0) {
angle += 360;
}
//angletext.text = angle;
zombieExt.rotation = (angle*1) + 90;
}
playerExt.addEventListener(Event.ENTER_FRAME,spawn1);
function spawn1 (event:Event)
{
if(playerExt.y < 417)
{
var someNum:Number = Math.round(Math.random()*20);
if(someNum == 20)
{
addChild(zombieExt)
zombieExt.x = Math.round(Math.random()*100)
zombieExt.y = Math.round(Math.random()*100)
}
}
}
}
addChild() does not create new instances. It is used to add an already created instance to the display list. If you call addChild() multiple times on the same instance then you are just readding itself.
Also each instance is unique, you can not globally change the x position of an instance by changing another one of them. What you would do is as Henry suggests and add each new instance of a MovieClip into an array, then whenever you change something you can loop through the array and apply the changes to each instance.
You can not go var2:MovieClip = new var1 either since var1 is an instance and not a class.
Here's a different method of receiving loaded MovieClips, which i use when i need many copies of the item.
in the swf you are loading, give the target movieclip a linkage name in the library, for this example i will use "foo"
private var loadedSwfClass:Class
private var newZombie:MovieClip;
private var zombieArray:Array = new Array();
function swfLoaded2(event:Event):void
{
loadedSwfClass = event.target.applicationDomain.getDefinition("foo");
for(var n:int = 0; n<100; n++){
newZombie = new loadedSwfClass()
zombieArray.push(newZombie);
addChild(newZombie);
}
}
as per this tutorial
http://darylteo.com/blog/2007/11/16/abstracting-assets-from-actionscript-in-as30-asset-libraries/
although the comments say that
var dClip:MovieClip = this;
var new_mc = new dClip.constructor();
this.addChild(new_mc);
will also work.
It sounds like you might be accessing the same instance some how in your code. It would be helpful to see your code to figure this one out.
If I wanted to load in one swf files and add a MovieClip multiple times I would place it in the library of that SWF file. And then instantiate it and store it into an object pool or a hash or some list.
// after the library were finished loading
var list:Array = [];
for(var i:int=0; i<10; i++) {
var myCreation:MySpecialThing = new MySpecialThing();
addChild(myCreation);
list.push(myCreation);
}
where my library would contain a linkage to the class MySpecialThing.
Calling addChild(var1) multiple times on the same parent doesn't have any effect (unless you have added another child to the same parent in between, in which case it will change the child index and bring var1 to the top). If you call it on different parents, it will just change the parent of var1, doesn't duplicate. Call addChild(new MovieClassName()) at random times instead to add new copies of it. Use an array as suggested here to access them later.
Wow, thanks there henry, just using an array did exactly what I needed, and made things alot simpler.
when you load in using a loader you only get 1 instance, however you can do some funky reflection to determine what class type the given loader.content is, and then instantiate them using that. For Example:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loader_completeHandler);
loader.load(new URLRequest("ZombieSource.swf"));
var classType:Class;
function loader_completeHandler(evt:Event):void
{
var loadInfo:LoaderInfo = (evt.target as LoaderInfo);
var loadedInstance:DisplayObject = loadInfo.content;
// getQualifiedClassName() is a top-level function, like trace()
var nameStr:String = getQualifiedClassName(loadedInstance);
if( loadInfo.applicationDomain.hasDefinition(nameStr) )
{
classType = loadInfo.applicationDomain.getDefinition(nameStr) as Class;
init();
}
else
{
//could not extract the class
}
}
function init():void
{
// to make a new instance of the ZombieMovie object, you create it
// directly from the classType variable
var i:int = 0;
while(i < 10)
{
var newZombie:DisplayObject = new classType();
// your code here
newZombie.x = stage.stageWidth * Math.random();
newZombie.x = stage.stageHeight * Math.random();
i++;
}
}
Any problems let me know, hope this helps.