How to reference many objects at once in Actionscript? - actionscript-3

So, the question is as follows:
I have a set of objects and I want a function to use all those elements of a set in a function. What can I do?
For example:
I have many instances of the same MovieClip. I want the function NextFrame() to be executed only for the MovieClips whose name matches the keyCode of a key I've just pressed.
How can I reference all these symbols at once in an "if" statement?

You'll need to use a loop.
Assuming your clips are just placed on the timeline there are few ways you could do this.
Walk the display list and search for all clips that meet your criteria.
This way can be expensive if you have tons of clips on the stage.
var i:int=this.numChildren;
while(i--){
if(this.getChildAt(i).name == nameCriteria){
//do something here, it matches
}
}
Keep your movie clips of that class in an array, and loop through that array:
var myArray:Array = [mc1,mc2,mc3,mc4];//whatever your movie clips instance names are...
for each(var clip:MovieClip in myArray){
if(clip.name == nameCriteria){
//do something
}
}
Create a custom class that automatically adds any instance of this Movie Clip to an array you loop through.
Save the following code in a file called MyKeycodeClip.as (or whatever you'd like to call it) next to your .fla file.
package {
import flash.display.MovieClip;
import flash.events.Event;
public class MyKeycodeClip extends MovieClip {
public static var allClips:Array = new Array();
public function MyKeycodeClip(){
this.addEventListener(Event.ADDED_TO_STAGE, addedToStage, false,0,true);
this.addEventListener(Event.REMOVED_FROM_STAGE, removedFromStage,false,0,true);
}
private function addedToStage(e:Event):void {
allClips.push(this);
}
private function removedFromStage(e:Event):void {
for(var i:int=0; i < allClips.length;i++){
if(allClips[i] == this){
allClips.splice(i,1);
return;
}
}
}
}
}
Then you can attach that class to your library object. Go to your library objects properties, and choose "Export For Actionscript", in the class input box, put: MyKeycodeClip.
Now whenever you drop that library object on the stage, the code from that file will be attached to it (which automatically adds/removes it from an array). You could loop through each item like so:
for each(var clip:MovieClip in MyKeycodeClip.allClips){
if(clip.name == nameCriteria){
//do something
}
}

Related

Addchild - object not appearing on stage from external class

I'm having problem with "DiamondEnemy" objects created in external class "Level" not appearing on the stage. I'm trying to retrieve a random enemy from "EnemyNotReleasedArray" at intervals and add them to screen through "enemyOnScreen" sprite.
Please note I have not 100% finished with all the functionality; so it may seem a little weird. I don't want to go further until I can actually get it working.
update: I create a new "level" object from a separate document class called "main".
package {
import DiamondEnemy;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.display.Sprite;
import flash.display.MovieClip;
public class Level extends MovieClip {
private const START_DELAY_SECONDS:uint = 1000;
private var EnemyNotReleasedArray:Array = new Array();
private var startDelay:Timer;
private var enemyOnScreen: Sprite;
public function Level(NumberDiamonds:uint)
{
// load the required enemies into the array
loadEnemyArray(NumberDiamonds);
//setup up sprite, for enemies that will appear on the screen
enemyOnScreen = new Sprite();
addChildAt(enemyOnScreen, numChildren);
// create delay timer before enemies can start appearing on screen
startDelay = new Timer(START_DELAY_SECONDS,1);
// set eventlistener that once delay finishes
startDelay.addEventListener(TimerEvent.TIMER_COMPLETE, releaseRandomEnemy);
startDelay.start();
//setup up sprite, for enemies that will appear on the screen
enemyOnScreen = new Sprite();
addChild(enemyOnScreen);
}
// creates the requested number of enemies type into EnemyNotReleasedArray so they can be released later
private function loadEnemyArray(numDiamonds:uint)
{
// use requested number diamonds enemies - to create diamond enemy objects
for (var i:uint = 0; i < numDiamonds; i++)
{
var diamond:DiamondEnemy = new DiamondEnemy();
EnemyNotReleasedArray.push(diamond);
}
}
// selects a random enemy from EnemyNotReleasedArray and resizes the array so enemy is no longer in it
private function releaseRandomEnemy(evt:TimerEvent)
{
var arrayLength:uint = EnemyNotReleasedArray.length;
// check make sure array is not empty, if empy level is over
if (arrayLength > 0)
{
var randomArrayIndex = Math.ceil(Math.random() * arrayLength) -1;
/// adding random enemy to sprite object
enemyOnScreen.addChild(EnemyNotReleasedArray[randomArrayIndex]);
trace(EnemyNotReleasedArray[randomArrayIndex]);
//remove the enemy from array and make element null
EnemyNotReleasedArray.removeAt(randomArrayIndex)
//tempory array to store non-null values
var tempArray:Array = new Array();
// cycle through EnemyNotReleasedArray and store all values that are not null into temp array
for each(var enemy in EnemyNotReleasedArray)
{
if (enemy != null)
{
tempArray.push(enemy)
}
}
// save temp array value into EnemyNotReleasedArray
EnemyNotReleasedArray = tempArray;
}
else
{
trace("no more enemies left in array");
}
}
}
}
document class "Main":
package {
import Level;
import DiamondEnemy;
import flash.display.MovieClip;
public class Main extends MovieClip
{
public function Main()
{
var level:Level = new Level(1);
}
}
}
The display list is a hierarchical graph, often called a tree.
Everything that's directly or indirectly connected to the root node is displayed. The root node is the Stage object. While possible, nothing of your own code should actually addChild() to this object. (for reasons out of the scope of this answer)
The only child of the Stage is the instance of your document class that's created when your .swf file is executed. This instance is automatically added to the Stage object, too, which is why you never have to add the document class to anything but it's still visible.
The constructor of your Main class looks like this:
public function Main()
{
var level:Level = new Level(1);
}
The problem is that while you successfully create the Level object, it is never added to the above described hierarchy that's usually called the "display list". level is not connected to the root node, which is why it is not displayed. You can still add children to level, but they won't be visible either for the same reason: that is, level is not visible.
To fix this, add level to your document class like so:
public function Main()
{
var level:Level = new Level(1);
addChild(level);
}
Btw. you have this code twice:
//setup up sprite, for enemies that will appear on the screen
enemyOnScreen = new Sprite();
addChildAt(enemyOnScreen, numChildren);
and
//setup up sprite, for enemies that will appear on the screen
enemyOnScreen = new Sprite();
addChild(enemyOnScreen);
but you only need it once. The second one is all you need.
And neither one of your two classes should extends MovieClip as non of them have a time line. Use extends Sprite unless you are actually dealing with MovieClips.

Referring to a variable in the target file from a class AS3

I've researched this all day and I'm stuck! I want to know how to use a variable from a target path to move something. Here is the code:
// Target file
var speed:int = Number(1);
var container:MovieClip = new MovieClip;
var objects:Objects = new Objects();
container.addChild(objects);
and
// Class for Objects
package {
import flash.display.MovieClip;
public class Objects extends MovieClip {
public function Objects() {
this.x += speed;
trace(this.x);
}
}
}
When I run it, I get an error like this:
Objects.as, Line 6 1120: Access of undefined property speed.
Thanks!
The most simple way to do it is to pass the speed variable to that class. See, classes are like stand alone objects in the space, and they (mostly) don't know about each other, or at least they don't know about the variables that you define in them.
So if you create a class inside another one (new Objects()), the most easy way is this:
var objects:Objects = new Objects(speed);
Then, inside Objects class, you will have:
public class Objects extends MovieClip {
var _speed:Number;
public function Objects(speed:Number) {
_speed = speed; // save it to a local member variable
this.x += _speed;
// start working with the local one,
// which will be accessible in the whole class
}
It's like passing some defined values, so that class can use them. And the class saves them inside itself so it can be used through the whole file (scope).

want to change the code actionscript2 to actionscript3?

i am newbie to flash.i need to change the below actionscript code to actionscript 3.0 code.
i am currently working on drag and drop. so i want to duplicate the movieclip while dragging i found the code on internet but it is actionscript 2.0 so please convert it to as3. the box is a instance name of a movieclip.
the code blocks are:
var num:Number = 0
box.onPress = function(){
num++
duplicateMovieClip(box ,"box"+num, _root.getNextHighestDepth())
_root["box"+num].startDrag();
}
box.onReleaseOutside = function(){
trace(_root["box"+num])
stopDrag();
}
If you dont want to use seperate .as file, follow this steps:
1- assign AS linkage to box movieClip (in library panel):
2- Select frame 1 on the timeline, and paste this code in the Actions panel:
var boxes:Array=[];
//var box:Box=new Box();
//addChild(box);
box.addEventListener(MouseEvent.MOUSE_DOWN,generateBox);
function generateBox(e:MouseEvent):void{
var newBox:Box=new Box();
newBox.x = e.target.x;
newBox.y = e.target.y;
newBox.startDrag();
newBox.addEventListener(MouseEvent.MOUSE_UP,stopD);
newBox.addEventListener(MouseEvent.MOUSE_DOWN,startD);
boxes.push(newBox);
addChild(newBox);
}
function startD(e:MouseEvent):void{
e.target.startDrag();
}
function stopD(e:MouseEvent):void{
e.target.stopDrag();
}
Unfortunately, there's no duplicateMovieClip analog in AS3, so you'll have to create a Class for your box movieClip template. Let's say it will be called BoxTemplate. (You can google how to create Classes for your library object). Add a Class with this name and add this code (event subscription in the constructor and a private event listener). You'll get something like this:
package
{
public class BoxTemplate
{
public function BoxTemplate()
{
addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
}
private function onMouseUp(e:MouseEvent):void
{
stopDrag();
}
}
Leave your present instance of this symbol on the stage. This is your code in the frame:
import flash.event.MouseEvent
box.addEventListener(MouseEvent.CLICK, onClick);
function onClick(e:MouseEvent):void
{
var newBox:BoxTemplate = new BoxTemplate();
newBox.x = e.target.x;
newBox.y = e.target.y;
addChild(newBox);
newBox.startDrag();
}
It will allow you to infinitely clone your boxes. Of course, you can add all of them in the array to keep the references.

adding variables to movieClip in flash to be used in Flash builder

I have created a .fla in Flash professional with several rectangles. Each rectangle is a different color and is a separate movie clip. I then have a movie clip (RectContainer) with contains all the rectangles inside of it, and I have added 'AS Linkage' so I can create an instance of this container class in Flash builder (after I've exported as a .swc).
My question is this. What if I wanted to add a variable to each rectangle and how could I read this value from Flash builder.
For example, I want to add a string variable to the red rectangle with the word "red" , the blue rectangle with "blue" etc.
I then want to add listeners to the rectangles, so when they are clicked I can get the color string of the rectangle that was clicked.
for (var i:int = 0; i < rectContainer.numChildren; i++) {
rectContainer.getChildAt(i).addEventListener(MouseEvent.MOUSE_DOWN, fl_Click);
}
function fl_click(event:MouseEvent):void
{
event.currentTarget. ???
}
First, in flash you must set name following like image.
you can access following like it.
not use a currentTarget because a potential risk. If child object a overlap, Your expectations may different. For more information google it.
Exactly what you need to know the difference between target and currentTarget. this is very important concept.
public function Constructor()
{
var container:RectContainer = new RectContainer();
this.addEvent(container);
var i:int = 0;
while(i<container.numChildren)
{
container.addEventListener(MouseEvent.CLICK, onClick);
i++;
}
}
private function onClick(e:MouseEvent):void
{
var mc:MovieClip = e.target as MovieClip;
if(mc.name == "myCircle1")
{
}
else if(mc.name == "myCircle2")
{
}
else if(mc.name == "myCircle3")
{
}
trace(mc.name);
}
You should make a custom class for your rectangles to inherit from (or draw your rectangles in the custom class and forgo the .fla altogether). You can then give a public property to hold the value you desire, create any common functions like a click handler that does something with the color label.
public class MyRectangle extends Sprite {
public var label:String;
public function MyRectangle(){
this.addEventListener(MouseEvent.CLICK, clickHandler,false,0,true);
}
private function clickHandler(e:MouseEvent):void {
trace(label);
}
}
For your rectangles, if in the flash IDE, in their symbol properties put your custom class as the base class.

AS3 Event Race Condition

I'm having some trouble solving a race condition that exists when I instantiate new MovieClip classes with some custom events that fire back before I can store the instances in an associative object.
Main Class
var pages:Object = {
"page1":"page1",
"page2":"page2"
};
for(var pageName:String in pages)
{
pages[pageName] = buildPage(pageName, onReady);
}
function buildPage(pageName:String, onReady:Function)
{
var newPage:MovieClip = new (getDefinitionByName(pageClass) as Class)();
newPage.addEventListener("PAGE_READY", onReady);
newPage.dispatchEvent(new Event("PAGE_CREATE"));
return newPage;
}
function onReady(e:Event)
{
for(var pageName:String in pages)
{
trace(typeof pages[pageName]);
}
}
Page 1 & 2 Classes extends MovieClip
function pageX()
{
this.addEventListener("PAGE_CREATE",this.onCreate);
}
function onCreate(e:Event)
{
this.graphics.beginFill(0xFF0000);
this.graphics.drawRect(0,0,200x200);
this.graphics.endFill();
this.dispatchEvent(new Event("PAGE_READY"));
}
Unfortunatley when this all fires off I get:
string
string
object
string
The original string object still exists before I can store the MovieClip instance for later reference. Any suggestions on how to beat this?
The code you posted does not depict a standard class.
Is this code on the movieclip frames or in separate files?
But as far as posted code I can see your issue is with the PAGE_CREATE event firing before the object has been added to the array.
your are doing
newPage.dispatchEvent(new Event("PAGE_CREATE"));
before you return the object.
You did not post the full classes so I really can't help you rewrite your code but, from what you posted I would remove the buildPage method completely and put the code in loop then dispatch the event after the object has been added to the array.
Also, another reason, best practice would be not to call a function from a loopif that function does not have a lot of code in it.
for(var pageName:String in pages)
{
var newPage:MovieClip = new (getDefinitionByName(pageClass) as Class)();
newPage.addEventListener("PAGE_READY", onReady);
pages[pageName] = newPage;
newPage.dispatchEvent(new Event("PAGE_CREATE"));
}