I have just started learning AS3 and my school has provided some Class files with the basic structure already written. Here is an example:
package {
//Add in your import statements here
//...
public class MathsQuiz extends MovieClip
{
//Add in your class variables here
//...
public function MathsQuiz()
{
}
public function startGame()
{
//Get the game loop to execute
addEventListener(Event.ENTER_FRAME,update);
}
public function update(evt:Event)
{
//This is the game loop
//Handle user input
//Handle game logic
//Handle display
}
}//end class
}//end package
My Question is, what does "extends MovieClip" actually do?
Thank you for your time!
The MovieClip class inherits from the following classes: Sprite, DisplayObjectContainer, InteractiveObject, DisplayObject (can be added to the display list, moved around via its x and y properties as Marcela said), and EventDispatcher, but unlike the Sprite object, a MovieClip object is Dynamic (A dynamic class defines an object that can be altered at run time by adding or changing properties and methods. A class that is not dynamic, such as the String class, is a sealed class. You cannot add properties or methods to a sealed class at run time.) and has a timeline.
If your class doesn't use timeline (looks like that is the case), you can extends Sprite and will have the same results and better performance. If you want a dynamic class you can just use the dynamic attribute when you declare a class.
The extends keyword allows a class to inherit any publicly-accessible or protected member variables and functions of a base class (in this case, MovieClip).
In this example, this means that MathsQuiz, on top of any functionality you may add, will also function as a MovieClip. On a basic level, this means that it is a display object that can be added to the display list and moved around via its x and y properties.
For a more in-depth understanding, do some research on OOP Inheritance.
Related
I have a main class in which I create instances of a class and add them with addChild(). I also have buttons and their respective classes. I want to remove the instance with removeChild() from my button class and not from the main class. Is that even possible?
One of the objects in mainClass:
public static var start_icon_:start_icon = new start_icon();
addChild(start_icon_);
I want to be able to:
removeChild(start_icon_); in a class that isnt mainClass.
First, a class does not have a parent or child; an instance has a parent or child. It's a good idea to try to get used to thinking that way. When you make something static you are making the code associated with the class, which is not specific to any particular instance. Meanwhile, methods like addChild and removeChild are instance functions, because they necessarily relate to specific instances of the class. So when you try to do things like expose a function globally by making it static, but want to do instance specific things like removeChild, you can get rather tangled.
To solve your problem, there are a few solutions.
You can simply "reach upward" to remove the child. For example, parent.removeChild(this) will remove a child from its parent. If you know the parent is a MainClass instance, you can cast and reference a property on it: parent.removeChild(MainClass(parent).start_icon). (start_icon should not be static.) You can even reach parent.parent. and so on.
That's not a great solution, though, because you are making the code assume a certain parent/child hierarchy. If you move things around it will break at runtime. A better solution (already mentioned in the comments) is to use events. For example:
class MainClass extends Sprite {
public var startIcon:StartIcon = new StartIcon();
public function MainClass() {
addChild(startIcon);
addEventListener("removeStartIcon", removeStartIcon);
}
private function removeStartIcon(e:Event):void {
removeChild(startIcon);
}
}
// From start icon, or any child (or children's child, etc) of main class instance:
dispatchEvent(new Event("removeStartIcon", true)); // bubbles=true, to trickle up the display hierarchy
Lastly, you can use the singleton pattern. Like others, I don't recommend this, but it is a quick and easy way to make a single instance of a class behave globally. The gist is that you expose a static reference to a single instance of your class, with the assumption you only ever need a single instance of that class. Then you can reference instance functions and properties from anywhere through the static reference of the class to its single instance. For example:
class MainClass extends Sprite {
public static var main:MainClass;
public var startIcon:StartIcon = new StartIcon();
public function MainClass() {
main = this;
addChild(startIcon);
}
public function removeStartIcon():void {
removeChild(startIcon);
}
}
Now from anywhere you can do this: MainClass.main.removeStartIcon() or even MainClass.main.removeChild(MainClass.main.startIcon).
I'm dabbling with game design and trying to create some characters for the game. Right now I've just created a single MovieClip that contains a rectangle. The MovieClip symbol extends a class that I've created in Flash Builder that implements the logic of a monster. I can then drag an instance of this monster symbol from the library to the stage and the code works when I run the simulation. So far, so good.
Now I want to create several monsters, all slightly different:
public class Monster extends MovieClip
{
public var isFriendly:Boolean = true;
public var strength:int = 10;
public var catchPhrase:String = "Booyah!";
public function Monster()
{
}
}
One way to do this is to write a new class for each monster that extends Monster and sets the properties I want in the constructor (I'd also have to create a unique symbol in the library for each of these variations too). However, this seems to be overkill if my monsters only differ by their property values.
Looking at the Flash Professional use interface, I see that at the very bottom of the Properties panel is a section that looks like a small table headed by 'Properties/Value'. Can I use this to somehow set the properties of my classes from within the Flash Professional UI? I can't find any info on how this is used.
Okay, I figured it out. The key is converting my symbol into a flash Component.
First I edited my ActionScript class to export the properties I wanted to set (including the Inspectable tag):
public class Monster
{
private var _catchPhrase:String;
public function Monster()
{
}
public function get catchPhrase():String
{
return _catchPhrase;
}
[Inspectable(name = "catchPhrase", type = String, defaultValue = "Booyah!")]
public function set catchPhrase(value:String):void
{
_catchPhrase = value;
}
}
Then I right clicked on the Monster symbol in my library and selected 'Component Definition...'. This brought up the Component Definition dialog. I then entered the name of my ActionScript class in the Class field and clicked the checkmark to validate it. Flash then automatically generated the properties I needed.
I also found this tutorial helpful:
http://redbjarne.wordpress.com/actionscript-3-0-custom-components-from-hell/
I have been struggling with the following for a couple of hours now, how do you call a custom class from another class if you do not extend that class for example.
I have on my main Base class a timer event, Base.myTimer.addEventListener(TimerEvent.TIMER, processTime) - Base class
Then I remove the method later in the code Base.mytimer.removeEventListener(TimerEvent.TIMER, processTime. - Base class
I have a button (Btn class) that when its done processing I want to call that method again, but I can't get it to work because the method does not exist in the button class but on the Base class so flash obviously gives me the error processTime is not defined.
For example now I want to re-instantiate the event listener from within the button, so I have
Base.myTimer.addEventListener(TimerEvent.TIMER, processTime);
or this.parent.parent["myTimer"].addEventListener()
myTimer is a static Timer in Base class.
I can make a normal dispatchEvent if its not a custom method for example Base.myTimer.dispatchEvent(new TimerEvent(TimerEvent.TIMER)).
The examples I have seen so far have not resolved my issue. Any help would be appreciated.
Looks like the button class is part of the child tree of the Base class. In this case, you can just do a dispatchEvent from the button class when it is clicked
dispatchEvent(new Event("AddListenerAgain", true));
In the Base class, you must be having access to the button class already, hence you can say:
button.addEventListener("AddListenerAgain", addListener);
Then in the Base class
private function addListener(e:Event) : void {
myTimer.addEventListener(TimerEvent.TIMER, processTime);
}
In this example, I have dispatched and listened for raw strings. This is not a recommended practice. You must read on how to dispatch custom events to do it correctly.
You could pass a reference to an instance of Base class into your Button instance.
// Button class
package {
import Base;
// Other imports...
public class Button {
public function Button(base:Base):void {
// processTime and myTimer must be public.
// I put this line in the constructor for brevity, but if you stored base
// in an instance variable, you could put this anywhere in the button
// class.
Base.myTimer.addEventListener(TimerEvent.TIMER, base.processTime)
}
}
}
// Create button like this.
var button:Button = new Button(base);
// Or if button is created inside of Base
var button:Button = new Button(this);
Even better would be to create two methods in the Base class, for adding and removing the listeners, and make myTimer and processTime private:
public class Base {
public function addTimerListeners():void {
myTimer.addEventListener(TimerEvent.TIMER, processTime)
}
public function removeTimerListeners():void {
myTimer.removeEventListener(TimerEvent.TIMER, processTime)
}
}
Then you can call these two methods from outside of the class. This keeps the inner workings of your class more hidden. If you decided you wanted to change myTimer to a instance variable instead of static, you wouldn't have to make any changes to code outside of your Base class. This is called encapsulation and is a good practice.
For example:
Library symbol "Card" is linked to class "Card" which extends "MovieClip". Library symbol "Card" contains a card background image.
Library symbol "Ace" is linked to class "Ace", which extends class "Card". Library symbol "Ace" contains a TextField with a big letter "A".
So we have Ace extends Card which extends MovieClip. Ace therefore extends MovieClip, but does not DIRECTLY extend MovieClip.
When I drop an instance of Ace on the stage and compile the clip, all that shows up is the big letter A. However, I expected the background image from Card to be included, since Ace extends Card, and the Card symbol contains the background.
It seems like Flash ignores symbol content unless it belongs to the top-level class being instantiated. I think it's LAME that one symbol can't extend another. The IDE could easily draw Card as a non-editable background while I'm editing Ace which extends it, and it should instantiate Card's content and then Ace's content when an Ace is instantiated. Thoughts?
Yeah, I've tried to do that. In theory you'd expect the display list of each extended class to stack, but they don't - it works as you describe, where you only see the graphics associated with the most recent class.
It's not a deal-breaker for you, though - various architectural options are at your disposal. You could, for instance, create a CardBackground class which is exported out of your library and has the card shape etc. Then you create a Card class which has a background:CardBackground property. Then your Ace class can extend Card and it should have the desired background.
Technically you're supposed to favor composition over inheritance, but Flash really encourages the inheritance mindset. Once you get used to breaking out of that you'll realize it's possible to create much more powerful, robust classes using composition in the manner described.
Cheers, and I hope that helps!
The base class to your card_mc(Card movieclip) may be your Card class but it doesn't make your Card class synonymous with card_mc.
Try doing this instead:
1) Create a movieclip containing the card background image and call it cardSprite_mc. Give it the class name CardSprite and set its base class to flash.display.Sprite.
2) Create a movieclip containing the textfield containing the letter "A" and call it ace_mc. Give it the class name Ace and a base class of com.cards.Ace.
3) Create a class called Card with the following code:
package com.cards
{
import flash.display.Sprite;
public class Card extends Sprite
{
public function Card():void
{
addChildAt(new CardSprite(), numChildren - 1);
}// end function
}// end class
}// end package
4) Create a class called Ace with the following code:
package com.cards
{
import com.cards.Card;
public class Ace extends Card
{
public function Ace():void
{
}// end function
}// end class
}// end package
Now if you add an instance of Ace to the stage you should see the card background image too.
I hope this helped :)
You can't do this in a programmatic way.
Instead you have to use the Flash Authoring environment. Extend symbols by creating one which includes the base symbol inside it.
And, yes I agree, it's quite LAME.
Taurayi's solution is inspiring, because it establishes that missing explicit link from Class to Symbol, ensuring the Symbol's content is instantiated whether it's the top-level class or just a base class in an inheritance chain. A side effect of that approach, however, is that it adds an extra containment level in Card's content, namely the CardSprite container.
I have managed to implement a practical generic solution that actually preserves the expected stacking behavior of all inherited symbols. For example, if you check "numChildren" on an instance of Symbol2 below, it will be exactly the sum of Symbol1.numChildren and Symbol2.numChildren, so it's a true merge stacking of symbol content.
When your symbol is in an inheritance chain, simply add this "ensureLinkage" call anytime after a call to the super() method.
package
{
public class Symbol1 extends Sprite
{
public function Symbol1()
{
super();
BugFixes.ensureLinkage( this, "Symbol1" );
}
}
}
package
{
public class Symbol2 extends Symbol1
{
public function Symbol2()
{
super();
BugFixes.ensureLinkage( this, "Symbol2" );
}
}
}
Note: Don't forget to make sure your top-level symbol also explicitly defines a class with the above pattern.
When Symbol2 and Symbol1 are linked to corresponding symbols in the library, their content will now stack. Just drop an instance of Symbol2 on the stage, and test the movie. You'll see that Symbol1's content appears under Symbol2's content. (Note: does not appear in the designer, since this is a runtime fix).
The implementation of ensureLinkage is as follows:
package
{
import flash.utils.getQualifiedClassName;
import flash.utils.getDefinitionByName;
import flash.events.Event;
public class BugFixes
{
public static var linkageMonitor:Object = new Object();
private static var linkageMonitorAuthority:Array = new Array();
public function BugFixes()
{
}
public static function ensureLinkage( instance:*, className:String )
{
if (getQualifiedClassName( instance ) != className) //detect non-top-level construction
{
//prevent inevitable factorial-recursive construction
var stack:Array = linkageMonitor[instance] as Array;
if (stack == null)
{
stack = new Array();
stack["numChildren"] = instance.numChildren;
linkageMonitor[instance] = stack;
}
var barredByAuthority:Boolean = false;
if (linkageMonitorAuthority.length > 0)
barredByAuthority = (linkageMonitorAuthority[linkageMonitorAuthority.length - 1] as Array).indexOf( className ) > -1;
if (stack.indexOf( className ) == -1 && !barredByAuthority)
{
stack.push( className ); //remember construction
trace( "ensuring Linkage of inherited class " + className );
//perform top-level construction to trigger symbol linkage and child object instantiation
linkageMonitorAuthority.push( stack );
var temp:* = new (getDefinitionByName( className ) as Class)();
linkageMonitorAuthority.pop();
//Merge children
while (temp.numChildren > 0)
instance.addChild( temp.getChildAt( 0 ) );
//Merge properties
for (var prop:String in temp)
instance[prop] = temp[prop];
}
else
{
trace( "skipping redundant construction of: " + className );
}
}
else
{
var stack:Array = linkageMonitor[instance] as Array;
if (stack != null)
{
var nc:int = int(stack["numChildren"]);
trace("construction completing for " + getQualifiedClassName( instance ) );
for (var i:int = 0; i < nc; i++)
instance.setChildIndex( instance.getChildAt( 0 ), instance.numChildren - 1 );
}
delete linkageMonitor[instance]; //top-level constructor is completing, all relevant sub-objects have been constructed
}
}
}
}
Basically, it detects whether symbols are going to need manually instantiated, by seeing whether the qualified class name of the instance matches the expected class name passed to the call from the class itself. Since it's called after "super", the calls start at the deepest class and ensure its library symbol's children are instantiated by making a temporary top-level instance and claiming its children as its own. The very first call for the instance also grabs the original number of children present, since the top-level clip in the stack will have already instantiated its children before any constructor code is run at all. By storing that number, a final step can then pull those initial children to the top where they belong. The class ensures no unnecessary recursion takes place, by using an "authority" stack to ensure the main stack is always visible to child constructors.
One issue is that static strokes are not persisted, but that is only because AS3 provides no API for accessing strokes (i.e. once you draw a line in the designer, or with graphics.lineTo, there is no way to programatically access that stroke for enumeration or modification purposes, except to clear all strokes at once). So that's not a limitation of this approach, but rather Flash's API.
Perhaps Adobe was simply unable to come up with this implementation :P
Please note that if your symbols do any work that ties the symbol instance to other code, there could be an issue, since this class claims ownership of children from a temporary instance. It also claims the values of variable references from the temporary instance using a for loop, but that's the best it can do in a generic implementation such as this.
I've got a AS3 program with a Main.as custom class.
In this class I load an instance of a 'menu' movieclip which has simpleButton instances inside... How do I access the Main class public functions by the menu movieclip buttons?
I.e. Menu button -> gotoPage(5); (which is a Main public function)
If I try to access the Main function with the above statement, it gives
"1180: Call to a possibly undefined method gotoPage.
Create a static method called GetMain() on the Main class that would return the instance of Main (Main should be a singleton).
package whatever
{
public class Main
{
private static var _instance:Main = null;
public static function getMain():Main
{
return _instance;
}
// Main constructor
function Main(..):void
{
_instance = this;
}
}
}
To refer to the instance of Main() from your Menu class, you could use:
Main.getMain().gotoPage(5);
You want to do this with events. If your menu movieclip is a child of Main.as as you say, name the instance buttons inside of the menu movieclip, and set up the listeners in Main.as:
1) Put the below code in the constructor: public function Main(){...
menu.button_a.addEventListener(MouseEvent.CLICK, onButtonClick);
menu.button_b.addEventListener(MouseEvent.CLICK, onButtonClick);
2) and then write the onButtonClick function in Main.as
private function onButtonClick(e:MouseEvent):void{
switch(e.currentTarget.name){
case "button_a":
//call the Main.as function you want here
break;
case "button_b":
//call a different Main.as function
break;
}
ruedaminute's answer on dispatching events from the buttons and having main process those events is by far the best way to handle this, but there are many ways to do this in as3 - but try to use the aforementioned technique. Some of the other techniques.
Make a function in Main such as public function GotoPage(iPageNum:int):void{}
from a button - try this._parent.GotoPage(1);
but this._parent might not be main, do a trace(this._parent), and keep trying
it might end up being
this._parent._parent._parent.GotoPage(1) depending on your display tree hierachry.
Again, this is REALLY bad OOP practices, but well, it will work.
Another tecnique - use a singleton for main- looks like u already are - add that same public method, then from the button click, you could do Main.getMain().GotoPage(1);
That is a bit better, in that you can change the display tree and not have to figure out where the heck Main is in the display tree, but singletons also are discouraged for a variety of reasons, but in this case I would say it makes since.
Good Luck!
~ JT