AS3 using addChild() with a variable taken from a XML - actionscript-3

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

Related

Gettling starling to work with box2d and debugdraw with as3

This topic has been raised before, but not one of the examples I've found online seem to work for me! I am trying to get starling to work with box2d, and also for the box2d debugdraw.
I have tried a bunch of different methods, and my code is now a bit of a mess due to commenting out to try different mixes of the "solution". Does anyone know how to do all this properly? I would be greatly in dept if someone could explain it.
Here is the last attempt I tried:
In my Startup class:
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
//import flash.events.Event;
import starling.core.Starling;
//import starling.display.Sprite;
import flash.events.Event;
[SWF(width="640", height="480", frameRate="60", backgroundColor="#000000")]
public class Startup extends Sprite {
public static var mStarling:Starling;
public static var debugSprite:Sprite;
public function Startup() {
//addChild ( new Stats() );
super();
//stage.align = StageAlign.TOP_LEFT;
//stage.scaleMode = StageScaleMode.NO_SCALE;
// create our Starling instance
mStarling = new Starling(Game, stage);
// set anti-aliasing (higher the better quality but slower performance)
mStarling.antiAliasing = 1;
mStarling.showStats = true;
// start it!
mStarling.start();
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContextCreated);
}
private function onContextCreated(e:Event):void{
////debug mode
// debugSprite=new Sprite();
// //addChild(debugSprite);
// Starling.current.nativeOverlay.addChild(debugSprite);
//var debugSprite:Sprite=new Sprite();
addChild(debugSprite);
(mStarling.stage.getChildAt(0) as Game).DebugDraw(debugSprite)
}
I call the debugdraw like this:
debugDraw(Startup.debugSprite);
Here is a heavily commented out debugdraw:
private function debugDraw(debugSprite:flash.display.Sprite):void {
/*var worldDebugDraw:b2DebugDraw=new b2DebugDraw();
//var debugSprite:flash.display.Sprite = new flash.display.Sprite();
var debugSprite:Sprite = new Sprite();
addChild(debugSprite);
//mStarling.current.nativeOverlay.addChild(debugSprite);
//worldDebugDraw.SetSprite(debugSprite);
//debugDraw.SetSprite(Starling.current.nativeOverlay); //DOESN'T SEEM TO WORK
worldDebugDraw.SetDrawScale(worldScale);
worldDebugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
//worldDebugDraw.SetFillAlpha(0.0);
//worldDebugDraw.SetAlpha(0.0);
//visible
worldDebugDraw.SetFillAlpha(0.8); //for testing
worldDebugDraw.SetAlpha(1); //for testing
world.SetDebugDraw(worldDebugDraw);*/
var worldDebugDraw:b2DebugDraw = new b2DebugDraw();
worldDebugDraw.SetSprite(debugSprite);
world.SetDebugDraw(worldDebugDraw);
}
DebudDraw works with ONE classic Flash Sprite (you keep creating new ones for some reason). Only one b2DebugDraw should be created and set with that ONE Sprite.
Starling pretends to own the stage and all displaylist but it doesn't. Use simply your StartUp instance or even directly the stage itself without passing through Starling it will avoid some confusion.
The right way to do all this:
public var debugSprite:Sprite;//no static var
Starting what?
//don't start it!
mStarling.start();
You star something that cannot be started. At this point you are trying to create a valid Context3D so be patient. Remove that line.
Now in onContextCreated:
mStarling.start();//now you can start
debugSprite = new Sprite();//create your sprite
addChild(debugSprite);
var game:Game = mStarling.stage.getChildAt(0) as Game;//Game? somebody is following a tutorial ...
if(game)
{
game.setDebug(debugSprite);//this is a new public method to create in Game
}
In Game in method setDebug (with one parameter Sprite):
var worldDebugDraw:b2DebugDraw = new b2DebugDraw();
worldDebugDraw.SetSprite(myspriteparameter);
world.SetDebugDraw(worldDebugDraw);
That's it, don't create new Sprite, don't create new debugdraw, you are good to go that's all you need.

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 How to use addChild() in a separated as file

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

embedded font flash.text.engine

I've completely run out of ideas on this. It follows, and is part of my previous question:
embedding a font in a swf using as3
I just don't seem to be able to get the flash.text.engine to use my embedded font. NB the font has to be loaded into the application (as embedded in swf) after the user has chosen the two languages (for translation to and from). There seems to be a little info implying that it is now necessary to use the fontswf application which is in the sdk. I have tried this and produced loadable swf files but I can't find any info on how these are then loaded (i.e. the getDefinition and registerFont bits below don't work as there are no classes in these swf) and applied to text.engine objects. The source for the embedding is in my answer to my question above. This is a test as3 which demonstrates how it doesn't work!
package
{
import flash.display.Loader;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.text.engine.ElementFormat;
import flash.text.engine.FontDescription;
import flash.text.engine.TextBlock;
import flash.text.engine.TextLine;
import flash.text.engine.TextElement;
import flash.net.URLRequest;
import flash.text.Font;
public class Main extends Sprite
{
private var loader:Loader;
private var tl:TextLine;
public function Main():void
{
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,fontLoaded);
loader.load(new URLRequest("EnglishF.swf"));
}
private function fontLoaded(evt:Event):void {
var FontClass:Class
FontClass = evt.target.applicationDomain.getDefinition("EnglishF") as Class;
try {
Font.registerFont(FontClass.myFont);
trace("successfully loaded " + FontClass);
// gives 'successfully loaded EnglishF'
} catch (err:Error) {}
var fontList:Array = Font.enumerateFonts();
for (var i:int = 0; i < fontList.length; i++) {
trace(fontList[i].fontName, fontList[i].fontType);
// gives 'EnglishF embeddedCFF'
}
var block:TextBlock = new TextBlock();
var font:FontDescription = new FontDescription("EnglishF");
var formt:ElementFormat = new ElementFormat(font, 30);
trace(FontDescription.isFontCompatible("EnglishF","normal","normal"), formt.fontDescription.fontName);
// gives 'true EnglishF'
formt.color = 0x882233;
var span:TextElement = new TextElement("Hello World. This is certainly NOT in the Font provided!", formt);
block.content = span;
tl = block.createTextLine();
tl.x = 10;
tl.y = tl.ascent + 10;
addChild(tl);
}
}
}
Am I doing anything wrong, or is this impossible?
Hopefully this will help. Under this line:
var font:FontDescription = new FontDescription("EnglishF");
add the following line:
font.fontLookup = FontLookup.EMBEDDED_CFF;
This will let the text framework know that you're using a CFF font (used in the new text framework), instead of a regular embedded font (used in TextFields).
Hope this helps.
Jordan

how do I access the main class's stage? + Can I pass functions as arguments like this?

There are two files in my actionscript project named "TestAPP", TestAPP.as and Draggable.as
TestAPP.as:
package {
import flash.display.Sprite;
import flash.display.Stage;
public class TestAPP extends Sprite
{
var _mainStage:Stage;
public function TestAPP()//This is where we test the UI components.
{
var sp:Sprite = new Sprite();
_mainStage = stage;
_mainStage.addChild(sp);
sp.graphics.beginFill(0x00FF00);
sp.graphics.drawCircle(0,0,10);
sp.graphics.endFill();
sp.x = 50;
sp.y = 50;
var draggable1:Draggable = new draggable(sp,_mainStage,limitingfunc);
}
public function limitingfunc(x:Number,y:Number):int{
return 0;
}
}
}
And for the draggable.as:
package
{
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.MouseEvent;
public class Draggable
{
private var _limitingFunc:Function;
private var _which:Sprite;
private var _MouseSavedX:Number;
private var _MouseSavedY:Number;
private var _stage:Stage;
public function Draggable(which:Sprite,stage:Stage,limitingfunc:Function)
{
_limitingFunc = limitingfunc;
_which = which;
_stage = stage;
_which.addEventListener(MouseEvent.MOUSE_DOWN,begin_drag);
}
//limiting func: returns 0 when the object is free to move that place.
//returns -1 when the user wants to block X coordinate changes (but maintain Y free)
//returns -2 when the user wants to block Y ...
//returns -3 or less when the user wants to block both X and Y from changing.
//returns
private function Return_0(x:Number = 0,y:Number = 0):int{
return 0;
}
private function begin_drag(ev:MouseEvent):void{
var xTo:Number = _stage.mouseX - _MouseSavedX + _which.x;
var yTo:Number = _stage.mouseY - _MouseSavedY + _which.y;
var limitingFuncReturnValue:int = _limitingFunc(xTo,yTo);
if(limitingFuncReturnValue == 0){//free to move.
_which.x = xTo;
_which.y = yTo;
}
else if(limitingFuncReturnValue == -1){//free to move Y
_which.y = yTo;
}
else if(limitingFuncReturnValue == -2){
_which.y = yTo;
}
//else:do nothing.
}
}
}
In "my actionscript theory", I'm supposed to see a circle that follows the mouse when I click it. (The draggable is not fully implemented) But the circle doesn't even budge :(
...I've been trying to figure out how to access the main class's stage property. I've googled for it, but still no progress.
Please help this helpless newb!!! I'll really appreciate your help:)
Thank you!
You're implementing your 2nd class as "draggable", when you named it (and it has to be named) "Draggable" with an upper case. Change it and see if that works. You seem to be passing in the parent classes stage correctly though.
If TestAPP is your document class. You can access to the stage thru the stage property (like your are doing in your example).
If TestAPP is not the document class, you should listen first to the ADDED_TO_STAGE event and then access to the stage property.
There is no need to add _mainStage property because you already have the stage property.
In order to move objects around, you need to use the ENTER_FRAME event.
You can access the main class' stage property the same way you do it for any DisplayObject on the stage: Use this.stage.
So just this should be enough:
var sp:Sprite = new Sprite();
stage.addChild(sp);
You could then pass the sprite and the main class' stage as a parameter, the way you did - but I would recommend creating a subclass Draggable extends Sprite and instantiate the whole thing using new Draggable() instead.
The new object will automatically have its own reference to stage as soon as it is added to the display list, and limitingFunc could be a member of Draggable, as well.
Also, you can use the startDrag() and stopDrag() methods, no need to implement your own: You can specify a Rectangle as a parameter to startDrag() to limit the permitted movement.
if you need it so much you may:
private static var _instance: TestAPP;
//...
public function TestAPP(){
_instance = this;
//...
}
public static function get instance():TestAPP{
return _instance;
}
public static function set instance(newVal: TestAPP):void{
_instance = newVal;
}
and you'll be able to reference its stage from any class where your TestAPP will be imported just with TestAPP.instance.stage.
but _instance is a property of the class TestAPP itself, not its instances