Should you explicitly declare an instance name in the code? - actionscript-3

I am new to ActionScript.
When I create a MovieClip and attach an instance name to it, I have access to it via the class of the stage.
However, I saw some tutorials that explicitly declare a variable with the instance name.
Is there any particular reason for that?

There's a lot of confusion in your post, so let me clarify things for you, maybe.
You can instantiate (create an instance of) class with new operator. Yes, with the new operator you can omit () if there are no mandatory arguments, it's not an error.
new MovieClip;
You can assign the result of that operation to a variable, declared as the variable of exact class.
var M:MovieClip = new MovieClip;
Or any superclass of the class you instantiate.
var D:DisplayObject = new MovieClip;
var E:EventDispatcher = new MovieClip;
Or an untyped variable.
var U:* = new MovieClip;
The variable type is what compiler looks at when you work with the referenced object (with no regard to actual object's class):
// Fine, DisplayObject.name is a valid property.
D.name = "Movie1";
// Error, EventDispatcher does not have a name property.
E.name = "Movie2";
Then. Setting an instance name is meaningful if you are going to access that instance as a child of some container with getChildByName(...) method. Or, maybe, if you are going to have a lot of different children in one container and you want to store their meta-essence in their names, like "Enemy2" or "Bullet15".
But it is not mandatory. If you can/want organize your app so that all references are stored as variables or in Arrays, there's no need to name instances.

Related

Accessing variables on Document class from a child class

There is a lot of confusion online about this topic, and I am amongst the confused.
Every time I try to change a variable on the Main.as from another class it fails.
What's worse? I remember doing this in the past in as3.
public var mainVar:String = "CHANGE ME"; //on Main.as
Types of things I try:
MovieClip(root).mainVar = "changed"; //error #1009
parent.mainVar = "changed"; //error #1119
this.parent.mainVar = "changed"; //error #1119
Main..mainVar = "changed"; //error #1119
I try to call a function and get similar results using the same language.
Thanks in advance for anyone who tries to help.
There have been so many times that it seems like the best idea to store the functions in the class and have them work off the main.as vars once they are called, but I can never find a reliable way to do this, and end up adding children and setting event listeners dynamically, and only working with vars from the main.as. It's easy to do the opposite, changing a var stored on the class from main.as.
Your "problem" is that AS3 is OOP, which means that classes work separately and you need to connect them. The old "way" of doing this (using root) is absolutely wrong when dealing with bigger projects.
There are many ways to do the connection between classes. First, your Main class acts like root (if defined as base class through Properties in Flash IDE). So if you create a class that is DisplayObject and add it to the main class (using addChild();), then you will be able to do much like before:
MovieClip(parent).myFunction();
I don't recommend this, but instead more reliable solution - pass the main class to the classes that must use it:
var somethingCustom:MyClass = new MyClass(this); // inside Main.as
Then in your newly created class save this as a variable and call functions from it:
var _root:DisplayObject;
public function MyClass(root:DisplayObject) { // MyClass.as
_root = root;
_root.callPublicFunction();
}
There are many resources that can help you understanding classes (saying so because this is the normal way they should work):
How Actionscript 3 Classes Work
http://www.untoldentertainment.com/blog/2009/08/25/tutorial-understanding-classes-in-as3-part-1/

AS 3.0 Creating instances

I started programming with Java, then I moved to as 3.0 to enhance my experience in UI.
Something I don't get in as 3.0 is the difference between MovieClip Object and instance.
To clarify, because I don't know if I have used the correct terminology:
The difference between: var name : ObjectName = new ClassName(); and the movie clip created on stage and give it an instance name.
I assume there are differences because I can use assign the movie clip's instance to the tween's object parameter, but cannot assign the one defined using variable.
I don't know if I am making any sense, but thank you in advance.
A MovieClip is one of three types of symbols available in Flash. Those three are MovieClip, Graphic, and Button. All MovieClip and Button symbols have the ability to have instance names set for them so that you can reference them from your ActionScript code. If you choose not to set an instance name for a Button or a MovieClip, Flash will automatically assign an instance name to it during runtime, regardless if you plan on referencing it from your ActionScript.
So for arguments sake, let's say you have a MovieClip on the stage with an instance name of "my_icon_mc". You could reference it in your code like so:
By calling the instance name itself, "my_icon_mc", or by storing a reference to it in a variable like so: (doing it this way has many advantages)
var myIcon:MovieClip = my_icon_mc;
In this example, I am storing a reference to a MovieClip on the stage with an instance name of "my_icon_mc" in the variable named myIcon. This allows me now to use the various MovieClip methods and properties of the MovieClip class in my code to manipulate the MovieClip on the stage.
So let's say I want to change the x coordinate of my movieclip on the stage to be at point 100, I could do the following:
my_icon_mc.x = 100
OR
var myIcon:MovieClip = my_icon_mc;
myIcon.x = 100;
It is important to note that if you create MovieClip via ActionScript, you can set the instance name of that MovieClip by using the name property of the MovieClip class like so:
var myIcon:MovieClip = new MovieClip();
myIcon.name = 'my_icon_mc';
Reference: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/MovieClip.html

AS3 create a variable in root from within a function

I have a fairly big swf right now with a bit of coding already. Most vars are created in the root, but now I have a problem.
I want to reload the flash swf (reset), and for that, I need to create a function that destroys all the vars and another one that creates them. At the moment, I have a javascript function that reloads the page, but that really isnt a good solution.
The problem is that when I create a var inside a function, it doesn't get created in "MovieClip(root)", and instead is only related to the function, thus rendering my swf unable to work.
Is there a way to create vars in MovieClip(root) from within a function? Or is there an alternative to what I'm trying to do?
EDIT: Added some example code.
function SetVar():void{
var test:String= new String("foobar");
}
SetVar();
trace(test);
...and the output is:
Scene 1, Layer 'Layer 1', Frame 1, Line 7 1120: Access of undefined property test.
Which is normal, because the "var test" is not global, so it was lost when the function ended. I want to make it so the function "SetVar()" adds the vars to the root, or global.
You need to read up on how scope works.
Basically:
An object declared within another object (be it a Class, Function, Object, or Loop), is only available within that specific object or loop iteration.
Object scope is inherited by children, not by parents. So a function within a class has access to an object declared within that class, but a class does not have access to an object declared within a function
A parent (or any other object) can access objects declared within child classes, but only if it is a public object
So looking at those basic rules (they are very, very basic. If you are just starting out, I urge you to do some proper research into object scope in OOP. It is the basis of everything you will do in dozens of languages), you are declaring an object in a function and trying to access it from outside that function. This breaks Rule #1 from above.
Instead, try this:
var test:String;
function setVar():void{
this.test = 'foorBar';
}
trace(test); //output: null (undeclared)
setVar();
trace(this.test); // output: fooBar
Looking at this, I did two things:
I moved the declaration of test into global space, meaning any object in that object will have access to it
I renamed SetVar to setVar. This has nothing to do with your question, but in AS3, the standard naming conventions dictate you use lowerCaseCamelCase for all objects (including functions), UpperCaseCamelCase for all Class names, and lowercasename for all package names. Again, unrelated but it is good to learn.
Now, ideally, you would probably want to do that setVar function slightly differently. To allow for better abstraction (basically making your code as generic an reusable as possible), you would want to return the value from the function rather than manually set the variable in the function.
var test:String;
var anotherTest:String;
function setVar():String {
return 'foorBar';
}
this.text = setVar();
this.anotherTest = setVar();
trace(this.test); // output: fooBar
trace(this.anotherTest); // output: fooBar
So that allows you to use that function with any String variable imaginable. Obviously, that is not very useful here since it doesn't do any logic. But I am sure you can see how that could be expanded with more code to make it more dynamic and much more useful
EDIT: As an afterthought, I used the this keyword. In AS3 (and a few other languages), this refers to the scope of the current class (or current frame, in case of timeline frame coding). So this.test refers to a variable test declared in the scope of the frame or class.
I am not entirely sure what you are looking for because there is no code associated with your question. However I will impart a bit of information I feel relates to the subject.
if you declare your variables in the class then you can reference them from a function as such:
package{
import flash.display.MovieClip;
public class DocumentClass extends MovieClip{
public var example:String = 'dog';
public function DocumentClass(){
trace(example); // dog
testFctn();
trace(example); // frog
}
public function testFctn(){
example = 'frog'
}
}
}
if you want to reference the variable of a parent class this.parent['variableName'] can be useful too. or a sibling of your working class sharing a parent class, this.parent['childClass']['variableName'] ...
Since you are declaring the variable within the function, its scope is restricted to that function only.
Try declaring the variable outside the function and initializing it in the function instead.
You should then be able to access it from root.
But if you wish to declare a variable on root from within a function (highly unusual requirement) then you can try doing:
document["variableName'] = value;
or
root["variableName'] = value;
inside the function.

How do I change subclass' variable from superclass?

For some time now I have been making a very easy game for iPhone in flash using as3.
Recently I came in contact with a small problem, which is why I am posting this!
The problem:
I have a superclass from which everything derives. In the superclass I initiate and place an Object on stage.
1. var myObject:typeA = new typeA();
2. stage.addChild(myObject);
As you can see this object follows the class 'typeA' which, ocf, has its own actionscript file. Inside of this file I have declared a global variable of type string.
What I want to do is change the varbiable on the new object from the superclass. Therefor I tried as following:
1. myObject.myVariable = 'someSortOfString';
Unfortunatly it didn't work and so I wonder how to do this; change a subclass' variable from the superclass.
You need to declare the variable that is being accessed from the subclass as protected (Or public), by default the variable is private so only accesible by the superclass.
e.g. protected var myObject:typeA = new typeA();
BTW did you mean change the superclass variable from the subclass instead of "change the subclass variable from the superclass"?

AS3 - Parametrized Factory method using actual class name

Rather than use a hard-coded switch statement where you pass it the string name of a class and it then instantiates the appropriate class, I'd like to pass the actual name of the class to my factory method and have it dynamically create an instance of that class. I thought it would be trivial and am surprised it is not working. I must be missing something quite basic:
sample code:
createProduct(50, "Product1Class");
createProduct(5, "Product2Class");
private function createProduct(amount:uint, productClassName:String):void {
var productReference:Class;
try {
productReference = getDefinitionByName(productClassName) as Class;
for (var i:uint = 0; i < amount; i++) {
var product = new productReference() as ProductBaseClass; // throws reference error!
}
} catch (error:ReferenceError) {
throw new ReferenceError(error.message + " Have you linked a library item to this class?");
}
}
The only thing that may be a little odd (not sure) is that these "products" are actually linked Library items (ie: I have a movieClip in the Library that has a linkage to Product1Class and another to Product2Class both of which extend ProductBaseClass, which in turn extends MovieClip.
Why the ReferenceError?
If you have a runtime loaded library then the Class's are not compiled into the main swf, so you get the runtime reference error when you try to create them.
To work around this you can declare "dummy" vars of the classes you want to compile, or if using the flex compiler there are options to include the classes you are missing.
e.g. declare these anywhere in your project
private var p1:Product1Class;
private var p2:Product2Class;
Its a frustrating problem, if your classes extend MovieClip which is a dynamic class you might be able to access the properties etc by doing something like this:
var product:MovieClip = new productReference() as MovieClip;
p1["someCustomProperty"]; //Dot notation might work here as it is a dynamic class
Chris is absolutely right, the ReferenceError is actually being thrown during the call to getDefinitionByName, meaning that the reflection method cannot find Product1Class or Product2Class in your application domain. You can always check if a definition is available by checking the application domain directly, like:
// inside your createProduct method, yields 'false'.
ApplicationDomain.currentDomain.hasDefinition( productClassName );
Are these library assets loaded in at runtime? If so, you can either make sure that the library swf is loaded into the current application domain by adding an appropriately configured LoaderContext to your Loader, or you can replace the call to getDefinitionByName with the loaded swf's application domain's getDefinition method.
getDefinitionByName() and ApplicationDomain.currentDomain.hasDefinition() require full qualified class names. The example code in the original post works when Product1Class and Product2Class are in the default package. However, if you move the product classes to another package, you have to make sure that you are supplying the fully qualified class name to getDefinitionByName().
So if we put our product classes in com.example.products, then the call becomes:
productReference = getDefinitionByName("com.example.products.Product1Class") as Class;
I'm not really sure what the best practice is with this kind of dynamic factory class, but what I ended up doing (since all products were in the same package) was to create a constant within my factory class that defines the package for my products:
private const PRODUCT_PACKAGE:String = "com.example.products."; // note the trailing period
So that way your client code doesn't need to know (nor define) the product package. You just prepend this constant to your product class name when using getDefinitionByName().