i'm currently using a dictionary to associate a boolean to my (non-dynamic) sprites, but i would like to know if there is a smarter way of doing this? i could just use MovieClips to assign my properties instead of Sprites since MovieClips are dynamic, but i will not be using any of the MovieClip properties or functions so it comes down to a best practice issue.
basically i want to create a state boolean property on my sprites - they are either on or off so my boolean variable is called isOn.
var mySprite:Sprite = new Sprite();
var isOn:Boolean = false;
var dict:Dictionary = new Dictionar();
dict[mySprite] = isOn;
then i will poll my sprite to check its "isOn" property. if it's on, i will turn it off - or set it to false.
if (dict[mySprite] == true)
{
dict[mySprite] = false;
}
this is the first time i'm actually using dictionaries, so please correct me if i'm using it wrong. and, of course, my original question stands: is this the best way of adding a boolean property to a non-dynamic object?
Can't you just write your own Sprite that has an isOn property? That seems like a much simpler way to achieve what you want, without using a MovieClip.
isOn could be a public var or a pair of getter/setter if you want to perform some logic when reading/writting it.
public class MySprite extends Sprite {
private var _isOn:Boolean;
public function get isOn():Boolean {
return _isOn;
}
public function set isOn(v:Boolean):void {
_isOn = v;
}
}
And then:
var mySprite:MySprite = new MySprite();
mySprite.isOn = false;
// at some later point...
if (mySprite.isOn)
{
mySprite.isOn = false;
}
Related
I got a .fla file, where inside I have some movieclip instances placed in the scene. I need to iterate through them and gather some data, like position, name, and custom properties.
These custom properties, I don't know how to pass them, I know one way that works so far is to use the accessibility properties panel (Flash Pro CC), and then in the code I can just read them. However there should be a better way I assume.
If I have understood correctly your question and what you have said in your comments about the answer of #Aaron, you have an swf file, which you load dynamically, and you want to get/set some of its MovieClips properties, if it's the case, take this example :
MyMC.as :
public class MyMC extends MovieClip
{
private var timer:Timer;
private var rotation_speed:int = 1;
public function MyMC() {
}
public function set_Rotation_Speed(_rotation_speed:int): void {
this.rotation_speed = _rotation_speed;
}
public function get_Rotation_Speed(): int {
return this.rotation_speed;
}
public function start_Rotation(): void {
this.timer = new Timer(500, 10);
this.timer.addEventListener(TimerEvent.TIMER, on_Timer);
this.timer.start();
}
private function on_Timer(e:TimerEvent): void {
this.rotation += this.rotation_speed;
}
}
Then, in my swf.swf I have an instance of that MovieClip.
I loaded the swf.swf using this code :
var loader:Loader = new Loader()
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, on_SWFLoad);
loader.load(new URLRequest('swf.swf'));
And to set/get some of my MovieClip properties, I did :
function on_SWFLoad(e:Event): void
{
var swf:DisplayObjectContainer = DisplayObjectContainer(loader.content);
var num_children:int = swf.numChildren;
for(var i:int = 0; i < num_children; i++)
{
var child:MovieClip = MovieClip(swf.getChildAt(i));
// get the name
trace('name : ' + child.name);
// set the position
child.x = child.y = 100;
// get the class name, in my case it's MyMC
var class_name:String = getQualifiedClassName(child);
// get all the details of the child
trace(describeType(child));
child.set_Rotation_Speed(45);
child.start_Rotation();
trace(child.get_Rotation_Speed()); // gives : 45
}
addChild(loader);
}
You can use the describeType() function To get all the properties of your instance.
Hope that can help.
First of all, you can set properties on timeline instances from code. There's nothing special about this. For example:
Place an instance of a library symbol on a keyframe
Give it an instance name in the Properties panel, for example "myInstance"
On the same keyframe put some code that refers to it, such as myInstance.color = "red"
You can also create and assign custom properties by making the symbol a component:
Right-click on the symbol in the library and choose "Component Definition"
Add custom properties in the Parameters table. It's now a component symbol.
On the timeline, place an instance of the symbol and use the Properties panel to set its parameters.
You can do a lot more with components if you want, such as live preview and compiled components. More info can be found here here: http://www.adobe.com/devnet/flash/learning_guide/components/part03.html
var test:*;
test = sMC // Some movieClip exported for ActionScript
var f = new test;
Sorry if the question's a bit lame, but I begin to wonder, what does this asterisk, and the snippet mean?
Answering your original question and your question asked in a comment:
An asterisk is a wildcard which means the variable will accept any type of info. Example:
var wildcard:*;
wildcard = "hello";
wildcard = 10;
wildcard = new MovieClip();
All of the above will work.
Variables should be typed as strictly as possible; by this I mean that when you want to assign a MovieClip to a variable, your variable should be typed as a MovieClip. Like so:
var mc:MovieClip = new MovieClip();
This works for anything. If you create your own class, then use that as your type for a variable that holds your class.
var thing:MyClass = new MyClass();
An error will be thrown if you try and assign an unrelated type to a variable, like so:
var thing:MovieClip = "hello";
But as long as your variable type is somewhere along the inheritance chain of what you're assigning to it, then it will work.
var thing:DisplayObject = new MovieClip();
This can be handy if you want to loop through an array containing an assortment of your own classes that extend MovieClip.
var ar:Array = [];
/**
* MyClass extends MovieClip
* MyOtherClass extends MovieClip
*/
ar.push(new MyClass());
ar.push(new MovieClip());
ar.push(new MyOtherClass());
var i:MovieClip;
for each(i in ar)
{
trace(i);
}
Overall the wildcard type is not a recommendation. At worst use Object as everything in flash extends this. One situation where a wildcard or Object can be useful is if you want to create a function that can accept any kind of data. Like so:
var myarray:Array = [];
function addToArray(data:Object):void
{
myarray[myarray.length] = data;
trace(data);
}
OR
function addToArray(data:*):void
{
myarray[myarray.length] = data;
trace(data);
}
Hope this all makes sense.
The asterisk means the variable type is undefined, or a wildcard.
Meaning you can define test as any sort of variable.
is it possible to obtain the instance name of a class from the class without having to manually pass the instance name as a string parameter to the class constructor?
//Create New SizeClass
var big:SizeClass = new SizeClass();
//-------------
package
{
public class SizeClass
{
public function SizeClass()
{
trace( //-- Instance Name "big" --// );
}
}
}
No, it is not possible to know anything about the containing code block during a constructor, save what you can learn from the stack trace (though that's not available except in the debugger version of Flash). Even if you had a global access point for the containing class, it still would not allow for that access.
Think of a constructor like a method call. In a line of AS, it will be called before the assignment. Eg: var a:Foo = new Foo() the Foo is created (the constructor completes), and then a is populated with whatever just happened. After that point a will remain agnostic of its context (because of encapsulation) unless it is told about it (this is even true on a DisplayObject -- try this( var mc:MovieClip = new MovieClip(); trace( mc.root ) //this will be null ).
I'm keeping this because it is useful albeit not useful to your original answer.
You can always get the name of a class with getQualifiedClassName from the flash.utils package. You can't get a DisplayObject's until well after it has been constructed, but you can simulate this by (I believe) overriding function set name( value:String ):void. If that doesn't work, then try finding it after Event.ADDED and/or Event.ADDED_TO_SAGE.
The instance name isn't very important. You'd better store references of the instances inside an array.
var sizes:Array = new Array();
var big:SizeClass = new SizeClass();
sizes.push( big );
When you want to access them, you can loop through the array.
for (var i:uint = 0; i < list.length; ++i)
{
var size:SizeClass = list[i] as SizeClass;
trace( size );
}
BTW: Instead of an instance name it is possible to add an automatic index to your class.
package
{
public class SizeClass
{
private static var global_index:int = 0;
public const INDEX:int = global_index ++;
}
}
Which you can access like this:
var big:SizeClass = new SizeClass();
trace(big.INDEX) // 0
var small:SizeClass = new SizeClass();
trace(small.INDEX)// 1
source: http://blog.stroep.nl/2010/08/auto-increment-as3-class/
I have the following function to set up cards in a game. I created one array to hold the kind of cards, and another array to hold the position of the cards.
private function setPlayerCard(cardNumber:int, cardPos:int):void{
for (var i:int = 1; i < _CardGridInstance.numChildren+1; i++) {
var _position:MovieClip = MovieClip(_CardGridInstance.getChildByName("Position_" + i));
cardPositions[i] = _position;
cardPositions[i].pos_name.text = "position" + i;
cardPositions[i].id = ["pos"+i];
}
for (var j:int = 1; j < numCards+1; j++) {
var _c:Class = getDefinitionByName("Card_" + j) as Class;
var _cardInstance:MovieClip = new _c();
cards[j] = _cardInstance;
}
cards[cardNumber].x = _CardGridInstance.x + cardPositions[cardPos].x - 1;
cards[cardNumber].y = _CardGridInstance.y + cardPositions[cardPos].y;
addChild(cards[cardNumber]);
}
So if I want to set the card number "3" in position "5" I just write:
setPlayerCard(3,5);
The problem I can see is that every time I'd like to place a card, I am creating two arrays every time. I would like to make the arrays "global" (i.e. create it in my constructor in my document class) and reuse it in the function "setPlayerCard" however I am getting errors when I try to do so.
Any suggestions?
This is a perfect case for a Singleton static class data model. You can get the instance of the Singleton from throughout the application as it is a static class, and it can contain the two arrays without duplication.
pixelbreaker has a nice basic Singleton AS3 example that you can build from.
It's a little difficult to answer accurately without knowing how you are creating the variables and what errors you're getting. Can you post the entire class and the errors?
I can, however, recommend that you do not use the Singleton pattern. This is not a perfect case for a Singleton. The Singleton pattern has no place in OOP, it's procedural programming wrapped up like OO, but that's an argument for elsewhere.
This is, though, a perfect case for a class level variables. The following is a simple example. There are a few missing variable declarations though (numCards), as I don't know where you're creating and setting them.
package{
import flash.display.Sprite;
public class CardGame extends Sprite{
private var cardPositions:Array = new Array();
private var cards:Array = new Array();
public function CardGame(){
for var i:uint = 1; i <= _CardGridInstance.numChildren; i++) {
var position:MovieClip = MovieClip(_CardGridInstance.getChildByName("Position_" + i));
cardPositions[i] = position;
cardPositions[i].pos_name.text = "position" + i;
cardPositions[i].id = ["pos"+i];
}
for(i = 1; i <= numCards; i++) {
var c:Class = getDefinitionByName("Card_" + i) as Class;
var cardInstance:MovieClip = new c();
cards[i] = cardInstance;
}
}
private function setPlayerCard(cardNumber:uint, cardPos:uint):void{
cards[cardNumber].x = _CardGridInstance.x + cardPositions[cardPos].x - 1;
cards[cardNumber].y = _CardGridInstance.y + cardPositions[cardPos].y;
addChild(cards[cardNumber]);
}
}
}
This way you only create and populate the arrays once and you can access them from anywhere within the CardGame Class. They are not global but they are within the scope of the setPlayerCard method.
You may get errors as objects might not be instantiated when the Document Class' constructor gets called, but that can be worked around.
What is the need for the variable to be public and static?
Static means that the variable is on the Class, not instances of the Class. So every "CardGame" instance will share the same static variable. I presume, because this is the Document Class, that you will not have more than one instance of it. So there is no reason for that.
The only other reason, because you declared it public, is to make the variable accessible from outside the Class through CardGame.cardPositions. This is bad practice as you shouldn't allow other objects to directly manipulate a Classes internal data. That breaks encapsulation. Since this is the Document Class and the top of the hierarchy, you should pass a copy of the data to whichever object needs it and wait for an event to retrieve the updated data. That way you can sanitise the data before using it and you're not just blindly trusting other objects to respect your data.
http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)
I tried using the Singleton class, but since I had to reference MovieClips that were already on the display list, I opted for a different solution from "Actionscript 3 Tip of the Day":
http://www.kirupa.com/forum/showthread.php?p=2110830#post2110830
package {
public class ClassName {
public static var myArray_1:Object = new Object;
public static var myArray_2:Object = new Object;
public function ClassName() {
//constructor
Whatever();
DoStuffWithWhatever();
}
private function Whatever() {
// put stuff into the array here
}
private function DoStuffWithWhatever():void {
// do stuff with the array values here.
}
}
}
Thanks very much for your time! Here is my question,...
public function addNewMc():void{
var newMC:MovieClip= new MovieClip();
this.addChild(newMC);
}
public function removeOldMc(newMC):void{
this.removeChild(newMC);
}
How can I create a new MovieClip within a method, which can be used throughout the class, without defining it at the top of the class? And for extra points, without using return.
I can get it to work, if the first function addNewMc returns the value newMC, and passing that to any other methods... but for what I am writing, I hope to use up my return with something else. Thanks!
Don't know if I'm understanding you completely but it sounds like you want access to a dynamically created Movieclip without explicitly defining it?! is that right?
If so, then you could do what you have now but add a method for retrieval:
public function addNewMc():void{
var newMC:MovieClip= new MovieClip();
this.addChild(newMC);
}
public function getMC():MovieClip
{
var len:uint = this.numChildren;
while(len--)
{
var tempObj:* = this.getChildAt(len);
if(tempObj is MovieClip)
return MovieClip(tempObj);
}
return null;
}
You could also add a name property to the dynamically created movieclip:
public function addNewMc():void
{
var newMC:MovieClip= new MovieClip();
newMC.name = "new_MC";
this.addChild(newMC);
}
you could then retrieve like this:
this.getChildByName("new_MC");
Again don't know if I'm understanding your exact requirements
cheers
erick ;)