I've done this a million time, but here it didn't work.
I have a game_mc inside a animate.fla. inside this clip I generate a view targetareas to place stones on it. ok, the TargetArea is a simple Movieclip inside my lib.
I can see everything, I can click on the area an get the propper name, I can get the names of the clips inside game_mc.
but I can't access it by using game_mc[clipname]
for (var i:int = 1; i<= 20; i++){
var targetArea:TargetArea = new TargetArea();
targetArea.txt.text = String(i);
var modu = ((i-1) %5);
targetArea.x = 100 + modu * 340;
var abs = int((i-1) / 5);
targetArea.name = "targetarea_" + String(i)+ "_mc";
targetArea.mouseChildren = false;
targetArea.y = 100 + (abs * 200) ;
game_mc.addChild(targetArea);
}
for(var x:int=0;x < game_mc.numChildren;x++) {
trace (game_mc.getChildAt(x).name);
}
for (var i:int = 1; i< 20; i++){
var targetName:String = "targetarea_" + i + "_mc"
trace( game_mc[targetName].x);
}
I think the name you assign your TargetArea instances isn't automatically converted
into a property of the DisplayObject you attach it to. As far as I remember though this
nonchalant way of accessing MovieClips using array access used to work prior to AS3.
The more elegant solution is to retrieve the child using getChildByName().
trace(game_mc.getChildByName(targetName).x);
Additionally, in case game_mc is an instance of MovieClip or a dynamic class you can make the TargetArea instances a property of it using:
game_mc[targetArea.name] = targetArea;
This way you can access them using game_mc[name].property afterwards.
Related
I have four Movieclips inside four movieclip containers, and a filter called "myShadowFilter", like so:
option1BlueBox
is a movieclip inside
option1Container
and
option2Container
is a movieclip inside
option2BlueBox
and so on. I want to do this:
option1Container.option1BlueBox.filters = [myShadowFilter]; //line1
option2Container.option3BlueBox.filters = [myShadowFilter]; //line2
option3Container.option4BlueBox.filters = [myShadowFilter]; //line3
option4Container.option5BlueBox.filters = [myShadowFilter]; //line4
except with a loop, becuase I'm probably going to add more containers, each with a movie clip inside. A sudo-code of what I want to do is:
var containers:int = 1;
for (var i:int = 1; i<containers + 1, i++) {
'option' + i + 'Container.option' + i + 'BlueBox.filters = [myShadowFilter];';
}
Basically, I just want one loop which will run all the 4 commands. How do I make it work? It is giving me errors (as I expected) saying that there are syntax errors and colons are expected.
Use the Array access operator. For more details, see this.
var containers:int = 1;
for (var i:int = 1; i<containers + 1, i++) {
this['option' + i + 'Container']['option' + i + 'BlueBox'].filters = [myShadowFilter];
}
You could probably simplify this further by giving the blue box clip the same instance name (it only needs to be unique within the current scope). Then you could do something like this:
// Create an array of containers
var containers = [
option1Container,
option2Container,
option3Container,
option4Container
];
// Loop through each container and apply the filter
// to the blue box container clip
for (var i = 0; i < containers.length; i ++)
{
containers[i].option1BlueBox.filters = [myShadowFilter];
}
I am adding moiveClips and putting their position accordingly. I am placing all the dynamically added clips in one new movie clip and then centering that on stage. As a test, I see I can control the alpha in the main container but I can not access the children. How can I assess each flagButton separately? There would be several in this loop example below.
var flagButton:MovieClip;
var flagArray:Array = new Array;
var flagDisplayButtons:MovieClip = new MovieClip();
function displayFlagButtons()
{
for( var i = 0; flagArray.length > i; i++)
{
var flagButton:MovieClip = new roundButton();
flagButton.x = (flagButton.width + 10) * i;
flagButton.y = stage.stageHeight - flagButton.height;
addChild(flagButton);
flagDisplayButtons.addChild(flagButton);
}
addChild(flagDisplayButtons);
// Works
flagDisplayButtons.x = stage.stageWidth/2 - flagDisplayButtons.width/2;
// Does not see flagButton
flagDisplayButtons.flagButton.alpha = .5;
}
GETS ERROR:
TypeError: Error #1010: A term is undefined and has no properties.
In your example code, you have created a bunch of button instances, and one by one you have added them to the display list of flagDisplayButtons. They are on that display list in the order that you placed them.
first instance is at index 0
second instance is at index 1
third instance is at index 2
and so on.
So if you want to access the third button you added, you could do this :
var flagButton:RoundButton = flagDisplayButtons.getChildAt(2) as RoundButton;
Now that you have created variable to reference that button, you can do any of these :
flagButton.alpha = .5;
flagButton.x = 100;
flagButton.y = 200;
You need to use getChildAt or getChildByName to get the children of a DisplayObjectContainer
IE:
flagDisplayButtons.getChildAt(0).alpha = 0.5;
Yay, another simple noobie as3 question.
How can I reference a movieclip by its ".name" ?
I tried searching for a solution, but I couldn't find anything. Basically I have a set of movieclips added to the stage using a loop, so the way I found to diferentiate them was by giving them a .name of "something" + the Loop's "i". So now they are named something like "something1", "something2", "something3", and so on.
Now, I need to send some to a specific frame. Usually I would do something like:
something1.gotoAndStop(2);
But "something1" isnt the instance name, just the ".name". I cant find a way to reference it.
you want to use getChildByName("name") more info
import flash.display.MovieClip;
// create boxes
for(var i:int = 0 ; i < 4; i++){
var box:MovieClip = new myBox(); // myBox is a symbol in the library (export for actionscript is checked and class name is myBox
box.name = "box_" + i;
box.x = i * 100;
this.addChild(box);
}
// call one of the boxes
var targetBox:MovieClip = this.getChildByName("box_2") as MovieClip;
targetBox.gotoAndStop(2);
Accessing things by name is very prone to errors. It's not a good habit to get into if you're a newbie. I think a safer way to do this would be to store references to the things you're creating in the loop, for example in an array, and reference them by their indexes.
Example:
var boxes:Array = [];
const NUM_BOXES:int = 4;
const SPACING:int = 100;
// create boxes
for(var i:int = 0 ; i < NUM_BOXES:; i++){
var box:MovieClip = new MovieClip();
// You can still do this, but only as a label, don't rely on it for finding the box later!
box.name = "box_" + i;
box.x = i * SPACING;
addChild(box);
// store the box for lookup later.
boxes.push(box); // or boxes[i] = box;
}
// talk to the third box
const RESET_FRAME:int = 2;
var targetBox:MovieClip = boxes[2] as MovieClip;
targetBox.gotoAndStop(RESET_FRAME);
Note, I've also replaced many of the loose numbers with constants and vars which will also help your compiler notice errors.
You can use the parent to get the child by name. If the parent is the stage:
var something1:MovieClip = stage.getChildByName("something1");
something1.gotoAndStop(2);
I have a bunch of movie clips I created in flash CS5 and are all placed within the stage. I control each one of them dynamically with code using ActionScript 3. However I want to control all of them at the same time using a for loop and just change the width of each element but its not working.
Here is my code:
for(var i:Number = 0; i < 100; i++)
{
leftBar+i.width = ( Math.round(channel.rightPeak * 1.1) ) + 60;
}
So I have 100 bars each called leftBar and their number. So the firstBar is leftBar1, then leftBar2 and so on. I cant get it to work however. I have tried "leftBar"+i and also leftBari but none of them seem to work.
The correct way to select each of those MovieClips in your loop is:
this["leftBar" + i]
New code:
// Note: We've changed the initial value of i to 1 because you mentioned that
// your first MovieClip was called 'leftBar1' rather than 'leftBar0'.
for(var i:int = 1; i <= 100; i++)
{
var current:MovieClip = this["leftBar" + i];
current.width = Math.round(channel.rightPeak * 1.1) + 60;
}
Basically you want to select the property leftBar0, leftBar1, etc from this using square brackets. It is the same as doing this:
this.leftBar0
And can also be used for any properties or methods of any other class:
// Example of Square Bracket notation.
var sprite:Sprite = new Sprite();
sprite["x"] = 10;
trace(sprite.x);
this["addChild"](sprite);
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.