AS3 How to use addChild() in a separated as file - actionscript-3

How can I add the MovieClip I have put into the array to the Stage?
The following code is a separated .as file and located at the same level with the main.fla
I have tried many times but I got the error message -
"ReferenceError: Error #1065: Variable stage is not defined. at Set1()
at main_fla::MainTimeline/frame1()"
How can I do? Thank for any help!!
package
{
import flash.display.MovieClip;
import flash.display.Stage;
public class Set1
{
private var map:Array=new Array();
public function Set1()
{
for (var i:Number=0; i<5; i++)
{
var cell_mc=new cell();
cell_mc.x = 50+ i*cell_mc.width;
cell_mc.y = 50;
cell_mc.className=i;
map[i] = cell_mc;
trace(map[i].className);
stage.addChild(map[i]);
}
}
}
}

You are a little mixed up. stage is not a magic variable, instead it is a property that is inherited from the DisplayObject base class. That property gets set internally when a display object is added to the stage. So in your case your class needs to either inherit from a DisplayObject– probably Sprite class. Or simply inject a reference to the Stage from the outside when you invoke your function

First you need to set the Main flash file class.You'll do that by clicking on stage in your fla. file and edit you class in properties(should look like this(class:Set1))
Code below should work fine
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
public class Set1 extends Sprite
{
private var map:Array=new Array();
public function Set1()
{
for (var i:Number=0; i<5; i++)
{
var cell_mc=new cell();
cell_mc.x = 50+ i*cell_mc.width;
cell_mc.y = 50;
cell_mc.className=i;
map[i] = cell_mc;
trace(map[i].className);
addChild(map[i]);
}
}
}
}

Related

AS3: how to convert a string to a DisplayObject

This is driving me crazy.
In Main.as I have a button that, when pressed, trigger some stuff.
In arrayTambores I define an array with some Strings in it.
What I want to achieve is to create a big movieclip container with several mc inside, whose names are picked from that array.
Thanks you guys!
So this is what I have in ArrayTambores:
package
{
public class arrayTambores
{
public static var tempArray: Array = new Array();
public static var bigArrayTambor1: Array = new Array();
public static var randomPos:Number = 0;
public static var a:int = 0;
public static var z:int = 0;
tempArray[0] = "heladeraIcon";
tempArray[1] = "comodinIcon";
for (a = 0; a < 2; a++)
{
tempArray.unshift("microondasIcon");
}
for (a = 0; a < 5; a++)
{
tempArray.unshift("duchaIcon");
}
bigArrayTambor1.length = tempArray.length;
for (var z: int = 0; z < bigArrayTambor1.length; z++)
{
randomPos = int(Math.random() * tempArray.length);
bigArrayTambor1[z] = tempArray.splice(randomPos,1)[0];
}
public function arrayTambores()
{
}
}
}
And this is my Main.as:
package
{
import flash.display.*;
import flash.events.*;
import flash.utils.*;
public class Main extends MovieClip
{
public function Main():void
{
var Tambor1_mc:MovieClip = new MovieClip();//This is the container mc
/*I already convert some bitmaps to movieclips in my Library, and assign each of one a class name. I.e., for the var comodinIcon, the class to the comodin.jpg in the Library is comodin. And of course I set each one to Export for ActionScript and Export in frame 1.*/
var comodinIcon:comodin = new comodin();
var duchaIcon:ducha = new ducha();
var heladeraIcon:heladera = new heladera();
var microondasIcon:microondas = new microondas();
// BUTTON
makeButton(my_mc, my_mc_click);
function my_mc_click(evt: MouseEvent):void
{
Tambor1_mc.x = 132;
Tambor1_mc.y = 250;
var clipA1:String = new String();
clipA1 = arrayTambores.bigArrayTambor1[0];
// HERE is where it fails, because it can´t convert clipA1, which is a String, //to a flash.display.DisplayObject
Tambor1_mc.addChild(DisplayObject(clipA1));
stage.addChild(Tambor1_mc);
}
function makeButton(which_mc: MovieClip, clickFunction: Function):void
{
which_mc.buttonMode = true;
which_mc.useHandCursor = true;
which_mc.mouseChildren = false;
which_mc.addEventListener(MouseEvent.CLICK, clickFunction);
}
}
}
}
This answer makes the assumption that you have two library objects with 'export for actionscript' enabled and class names of heladeraIcon & comodinIcon.
To instantiate those in your code, you can't use strings because AS3 doesn't reference classes via strings (Though you can obtain a Class reference from a string using flash.utils.getDefinitionByName() but that isn't necessary here).
You actually just reference them by whatever value you put in as the class, so in your case heladeraIcon (no quotes because it's not a string, it's a class). When you check Export for actionscript, that class name becomes available in your program just like built-in classes.
So your code should look something like this:
tempArray[0] = heladeraIcon; //match whatever you put in the library object's properties as the class name
tempArray[1] = comodinIcon;
//you have get a reference to the class
var clipClass:Class = arrayTambores.bigArrayTambor1[0] as Class;
//then instantiate that class
var clipA1:DisplayObject = (new clipClass()) as DisplayObject;
Tambor1_mc.addChild(clipA1);
stage.addChild(Tambor1_mc);
Here is an example how to properly setup your library object(s) with AS3 Class linkage:
In Flash/AnimateCC, right-click (or ctrl+click on Mac) your symbol and choose properties.
In the properties window, check the Export for ActionScript & Export in frame 1 checkboxes in the ActionScript Linkage section.
Also in the ActionScript Linkage section, enter in a unique class name (in this example I've put in MyCustomClass.
Close the properties window.
In the library, you should now see the Class name that was given under the Linkage column. Keep in mind, the object name and Class/Linkage name can be different.
Now with the above linkage setup, I can do the following:
var clipClass:Class = MyCustomClass;
var clipA1:DisplayObject = (new clipClass()) as DisplayObject;
addChild(clipA1);

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.

Get global coordinate of a dynamically created nested component?

In the code below, I have created 4 sprites (picn) inside a sprite (noteholder). How can I get the absolute values of the picn instances that I create? I know about the localToGlobal function, but I can't figure out how to use that in this case. At this point, I think I need the container because I need to be able to move the sprites after creation. Any help is greatly appreciated. Thanks!
package
{
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import Main;
public class Notes extends Sprite
{
private var speed:int = 14;
[Embed(source="../lib/Dodgethis.jpg")]
private var picn:Class;
private var noteholder:Sprite = new Sprite();
public function appear() {
trace ("appear ran")
var arr1:Array = new Array;
var numnotes:Number = 4;
Main.StageRef.addChild(noteholder);
trace (noteholder.x, noteholder.y);
for (var i = 0; i < numnotes; i++)
{
//trace (i);
var nbm:Bitmap = new picn;
noteholder.addChild(nbm);
nbm.y = i * 50;
arr1.push(nbm);
You need to hold a reference to the display objects you dynamically create — you don't need a "name" which is just an abstraction of instance variables when creating visual assets in the Flash IDE.
I've updated your code to demonstrate the concept:
package
{
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.display.Stage; // added this
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle; // added this (see below)
import Main;
public class Notes extends Sprite
{
private var speed:int = 14;
[Embed(source="../lib/Dodgethis.jpg")]
private var NoteBMP:Class;
private var display:Sprite = new Sprite();
private var notes:Array = []; // make notes an instance variable, so it's accessible throughout the class
// I renamed appear to 'build' because I'm a pedantic moron
public function build():void
{
trace ("build ran");
var noteCount:int = 4;
Main.StageRef.addChild(display);
for (var i:int = 0; i < noteCount; i++)
{
var nbm:Bitmap = new NoteBMP;
display.addChild(nbm);
nbm.y = i * 50;
notes.push(nbm); // by adding the display objects to an array you can reference them later
then at some later point in the Notes class you can reference your bitmaps by looping through the notes array
// initialize variables outside the loop
var localPos:Point
var globalPos:Point;
var bounds:Rectangle;
var n:DisplayObject;
var stage:Stage = Main.StageRef;
for (var i:int = 0; i < notes.length; i++)
{
trace( 'note' + i );
n = notes[i] as DisplayObject; // cast during assignment since array items have ambiguous type
// getBounds() returns a Rectangle representing the bounding box of the display object
bounds = n.getBounds(stage);
trace(
'getBounds:',
bounds.top, bounds.left, bounds.bottom, bounds.right
);
// localToGlobal() returns a Point which is just the position
localPos = new Point( n.x, n.y );
globalPos = display.localToGlobal(localPos)
trace(
'localToGlobal:',
globalPos.x, globalPos.y
);
}
A few points:
I refactored some names to make the intention more clear
I wonder why your Notes class extends Sprite, since it adds display (what you called "noteholder") to the stage. Assuming that's correct just make Notes a generic object i.e. doesn't seem to need to extend another class.
You can use getBounds about getBounds
// call this after added to stage
if (stage) {
var r:Rectangle = nbm.getBounds(stage);// r's x and y is the global pos
}
And I think localToGlobal should work in your case. Move the sprites don't have effect on localToGlobal

AS3 using addChild() with a variable taken from a XML

I made a function that would add a child from my library using a variable made from an xml.
var ChosenGraphic:String = units.unit.(#titel==k1).graphic;
var mc:MovieClip = new ChosenGraphic;
addChild(mc);
I know I can't use :String for this, but I don't have a clue what to use. I'm trying to get it to work for 2 hours now, and it's getting really frustrating.
Everything else works, I've tested that.
You want to use the getDefinitionByName() top level function.
Below is an example of using it, lifted straight from the documentation that I linked to. Note that the class name string must be the fully qualified class name (ie: it includes the package name as well as the class).
package {
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.utils.getDefinitionByName;
public class GetDefinitionByNameExample extends Sprite {
private var bgColor:uint = 0xFFCC00;
private var size:uint = 80;
public function GetDefinitionByNameExample() {
var ClassReference:Class = getDefinitionByName("flash.display.Sprite") as Class;
var instance:Object = new ClassReference();
instance.graphics.beginFill(bgColor);
instance.graphics.drawRect(0, 0, size, size);
instance.graphics.endFill();
addChild(DisplayObject(instance));
}
}
}

Control loaded swish animation in AS 3.0

I'm developing an AS 3.0 wrapper to add some extra stuff that has to load some old and plain frame to frame SwishMax 3 animations and then be able to stop them, play them, and so...
Here is my code:
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.net.URLRequest;
import flash.events.*;
[SWF(backgroundColor="#ffffff", frameRate="17", width="300", height="250")]
public class SwishMaxWrapper extends Sprite {
function SwishMaxWrapper() {
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
addChild(loader);
var request:URLRequest = new URLRequest("swishy.swf");
loader.load(request);
}
private function completeHandler(event:Event):void {
var movie:MovieClip = event.target.content;
movie.stop();
}
}
}
The animation load works as expected but the movie.stop() doesn't. What is wrong?
I tested your code and it works on my machine. The SWF that I loaded had its animation in the main timeline. Is it possible that the swishy.swf has animation that is not on the main timeline? Perhaps the animation is in another symbol instead, and an instance of that symbol is on the stage. Anyway, when you call stop() in your code above, it's just telling the main timeline to stop, but other movie clips on the stage will keep on going.
I think that's what Simsoft was pointing out.
I tested your code using a SWF that had a symbol on the stage that had animation in it, and I got the problem that you are describing. I fixed it by modifying completeHandler() as follows:
public function completeHandler(event:Event):void {
var movie:MovieClip = event.target.content;
movie.stop(); //doesn't work - main timeline is only one frame long
for(var i:int = 0; i<movie.numChildren; i++) {
var child:MovieClip = movie.getChildAt(i) as MovieClip;
if(child) { //need this test - if the cast to MovieClip fails, child will be null
child.stop(); //works
}
}
}
Hopefully you don't have more animations nested at deeper layers. If that's the case, you'll have to modify this to keep peering into the children of each child and trying to stop their timelines as well.
Anyway, hope that helps. Good luck!
stop() isn't recurive, I think the problem is here.
function ruleThemAll(target : DisplayObjectContainer, doStop : Boolean = true) : void
{
for(var i : uint = 0; i < target.childNum; ++i)
{
var child : DisplayObject = target.getChildAt(i);
// If it's a container, go into to stop children
if(child is DisplayObjectContainer)
ruleThemAll(child as DisplayObjectContainer, doStop);
if(child is MovieClip)
{
if(doStop)
MovieClip(child).stop();
else
MovieClip(child).play();
}
}
}