AS3 reference movieclip by .name property - actionscript-3

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

Related

How to make housie / bingo game in Flash AS3

It shows an error when written this script has a package that cannot be nested how can I resolve the problem.
If not can anyone give me a new code so that I can try to make the new file?
I have this file in previous stack AS3 Bingo ticket generator
but i couldnt understan how to use it.
package {
import flash.display.Sprite;
import flash.text.TextField;
public class Main extends Sprite{
public var boards:Array = new Array();
private static const AMAUNT_BOARDS:uint = 6;
private static const NUMBER_FIELD_SIZE:uint = 20;
public function Main() {
for(var i:uint = 0; i < AMAUNT_BOARDS; i++)
{
var numbers:Array = genNumbers();
numbers = deleteFields(numbers);
var board:Sprite = getBoard(numbers);
board.y = NUMBER_FIELD_SIZE * 4 * i;
boards.push(board);
addChild(board);
}
}
//generates a 2 Dimensional Array (3x9) with TextFields
//populates the according Numbers and returns a board Sprite
private function getBoard(n:Array):Sprite
{
var s:Sprite = new Sprite();
var a:Array = new Array();
for(var i:uint = 0; i < 3; i++)
{
var b:Array = new Array();
for(var k:uint = 0; k < 9; k++)
{
//create TextFields
var tf:TextField = new TextField();
tf.x = k * NUMBER_FIELD_SIZE;
tf.y = i * NUMBER_FIELD_SIZE;
tf.border = true;
tf.width = NUMBER_FIELD_SIZE;
tf.height = NUMBER_FIELD_SIZE;
if(n[k][i] != 0) // adds the number if the value isn't 0
tf.text = n[k][i]; // Note that i am switching k & i because the number Array is 9x3
b.push(tf);
s.addChild(tf);
}
}
return s;
}
// Turns 4 random numbers out of the lines into 0 And returns the Array
private function deleteFields(a:Array):Array
{
for(var i:uint = 0; i < 3; i++)
{
var r:RandomPlus = new RandomPlus(8,0);
for(var k:uint = 0; k < 4; k++)
{
var t:uint = r.getNum();
a[t][i] = 0;
}
}
return a;
}
// Generates and returns a 2 Dimensional Array (9x3) with random numbers
private function genNumbers():Array
{
var a:Array = new Array();
var st:uint = 1;
var en:uint = 9;
for(var i:uint = 0; i < 9; i++)
{
var line:Array = new Array();
var ran:RandomPlus = new RandomPlus(en,st);
if(i == 0)//accounting for the number differnenz at start
st--;
if(i==7)//accounting for the number differnenz at end
en ++;
st += 10;
en += 10;
for(var e:uint = 0; e < 3; e++)
line[e] = ran.getNum();
a.push(line);
}
return a;
}
}
}
TL;DR: "Main" in the class definition may have to be changed conflict of already existing name. Extends sprite may need to be changed to extends movieclip. RandomPlus either needs an import you don't have or needs to be made into a symbol and exported to Actionscript.
Ok, so a few things:
If you are really putting the code into the stage code area, then you can't use the private identifier.
Unless RandomPlus is an object that you have defined in the stage it is probably either not a method you can use or you don't have the right imports for it. Look up what imports you need for RandomPlus or if it is an object defined in the stage then you may need to turn it into a symbol or if you have already export it to flash ActionScript I think. To do this you have to check the checkbox in the middle of the symbol creation page. It will always give you the error when you do this, but don't worry it is fine that way.
Third thing is that I never extend sprite in the class definition, I always do extends movieclip(not sure of the capitalization, but you can look that up). You may also be running into an error from using "Main" as the name because it may be a conflict with a name or method already defined in flash in general.
One last thing is for the variable declaration(mostly just for making the code more readable). While it is good to not declare variables as global when you don't have to, I tend to like having most of the variables up at the top, because I like to be able to see most of the declarations in one space. It's not necessary, really just a personal opinion, and I know a lot of experienced coders will say to do what you did, but if you want to use the arrays in multiple functions then sometimes it is easier to just declare them globally rather than having to pass a million things in the function call and then having to figure out later where all the variable declarations are called and where they are being passed as arguments. Again it's more of a coder's choice, but you can also just do whatever you feel more comfortable with rather than just following the already laid out rules by people who have more experience coding.
Another optional fix to the organization might be to name variables something meaningful so as to not forget what they are all doing. I am bad at naming as well, but I think it's really better to name them something better than just a single letter or two.
Another thing that can help is placing trace(code or "text"); in different places to see what's going wrong once you have the compiler happy.

problem accessing dynamic movieclips by name in adobe animate

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.

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 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.

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.