I've found myself needing to refer to certain animations in some unknown frame in my classes. What would be the best way to do this? Should I be creating a custum name and specify that all instances of the class should label a certain animation the same thing. For instance:
public class CanBeHurt{
public CanBeHurt() extends MovieClip{
// constructor code here
}
public function hurt():void{
gotoAndPlay("hurt");
}
}
Any instance of this class would then be forced to label the start of the hurt animation "hurt". Alternatively I could take in strings in the constructor that specify the frame, like so:
public class CanBeHurt{
private var hurtAnimationLabel: String;
public CanBeHurt(hurtAnimationLabel: String) extends MovieClip{
this.hurtAnimationLabel = hurtAnimationLabel;
}
public function hurt():void{
gotoAndPlay(hurtAnimationLabel);
}
}
But unfortunately with more complex objects, I already have a bunch of other input arguments for the constructor and with so many animations, I really don't want to add anymore to it. And lastly, the last option I came up with is:
public class CanBeHurt{
private var hurtAnimationLabel: String;
public CanBeHurt() extends MovieClip{
this.hurtAnimationLabel = this.currentLabels[0];
}
public function hurt():void{
gotoAndPlay(hurtAnimationLabel);
}
}
Unfortunately, with multiple animations, now I'm forced to have my animation labels in a certain order to be able to refer to them properly. Of the 3 methods, I've found the first one to be the most satisfying, but is there a better way?
You don't need to store label names, only if you want the efficient way.
Example:
public class CanBeHurt{
private var label: String;
public CanBeHurt() extends MovieClip{
label= "hurtLabel";
}
public function hurt():void{
currentFrameLabel != "hurtLabel" ? gotoAndPlay("hurtLabel") : null;
}
}
You should check the current frame's label and then play the animation to avoid frame stucking. (The animation is always at the first frame)
For games, most of the developers use a function to control the animations, it's the handleAnimation function.
Example:
public class Example{
private var label:String = "someLabel1";
public Example() extends MovieClip{
//constructor code here
}
private function handleAnimation(){
if(condition){
label = "someLabel1";
}
if(condition2){
label = "someLabel2";
}
gotoAndPlay(label);
}
}
I usually don't extend movieclip for my code. I create some kind of class that accepts a MovieClip in constructor and stores a reference to this and then acts upon it on function calls.
When it comes to label names I usually place them as a static variable in the appropriate class.
This has worked well for me throughout the years :)
Related
I am fairly new to AS3 and I want to know how to set a boolean to true or false in one package class and have it do something in another package class.
This is where I first set my boolean "mute":
package
{
public class AvoiderGame extends MovieClip
{
public var mute:Boolean;
public function Game()
{
mute = false;
And I want to change it on this package and have it effect the first package where I originally put it:
package
{
public class DocumentClass extends MovieClip
{
public function onRequestMute( navigationEvent:NavigationEvent ):void
{
mute = true;
}
I know it should be fairly easy but I'm not that great in certain parts of as3.
You can make it a static variable. you need to refer to it as "AvoiderGame.mute" everywhere not inside of the owning class.
//declaration in AvoiderGame
public static var mute:Boolean;
//use in some other file
AvoiderGame.mute = (true | false);
This is considered a bad practice overall though. I suggest looking up how to make a simple sound manager class to take care of this type of global variable.
Try searching for: "sound manager as3", "singleton pattern as3"
I'm developing a game in AS3. There is a Weapon superclass, which contains methods such as shoot and reload, which will behave the same across all weapons.
The specific weapons, such as Pistol, Shotgun inherit from this class so they can use these methods. They have public static variables, such as what type of bullet to shoot, rate of fire, bullet spread, that make them unique, and are used in these methods. They need to be public static variables so I can look them up from somewhere else in the core when all I've got there is the type of weapon that was fired.
Is this how I should be trying to do it? How does the Weapon superclass access these variables?
public static const RATE:uint = 2;
That is accessed by the Weapon class either as Weapon.RATE or as RATE. Scope works a little weird when it comes to static objects. I personally don't think you should be able to access the static objects with just RATE, but it works.
Subclasses do not inherit static properties and methods. They belong solely to the class they are created in (which makes sense if you know what a static object really is). So for all classes, even classes that extend Weapon, you must access a public static object via Weapon.RATE.
There is an oddity I have noticed however. If you use the protected access modifier instead of public, classes can access static objects in their super classes via RATE, as if it were created within the class itself. I don't know the logic behind that, but it works.
So:
public class Weapon {
protected var RATE:uint = 2;
public var RATE2:uint = 5;
}
public class Gun extends Weapon {
trace( RATE ); // output 2
trace( Weapon.RATE ); // output 2
trace( RATE2 ); // output Error, access of undefined property
trace( Weapon.RATE2 ); // output 5
}
EDIT: In response to the first comment:
The way superclasses work, an object that extends a class has access to all public and protected objects in the super class.
So let's say the weapon class is this:
public class Weapon {
public function shoot():void{}
protected function reload():void{}
private function aim():void{}
}
You would access those methods within the subclass like you would in the super class itself:
public class Pistol extends Weapon{
public function Pistol() {
this.shoot(); // works
this.reload(); // works
this.aim(); // doesn't work because it is private
}
}
Now if you are looking to abstract things further, you can set up properties within your super class with a protected or public modifier with a default value for all weapons. In your superclass methods, you simply call these values. In the subclass, you change them to be whatever you need them to be
public class Weapon {
public var rate:uint = 2;
public function shoot():void{
// use this.rate here
}
protected function reload():void{}
private function aim():void{}
}
public class Pistol extends Weapon{
public function Pistol() {
this.rate = 5; // value of rate is now 5 and will be used in shoot()
this.shoot(); // works
this.reload(); // works
this.aim(); // doesn't work because it is private
}
}
If there is a main class which uses class Chan, given two codes, for example
public class Chan extends Sprite
{
public function Chan():void
{
this.graphics.beginFill(0x123456);
this.graphics.drawRect(100,100,30,30);
}
}
And
public class Chan extends Sprite
{
public static var rect:Sprite=new Sprite();
public function Chan():void
{
rect.graphics.beginFill(0x123456);
rect.graphics.drawRect(100,100,30,30);
}
}
Why does one seems to work, and the other doesn't ?
scope. In the first example, you are drawing on the sprite instance itself that is already on the stage. rect in your second example is static and belongs to the class. So although you are drawing in it, it is not visible... it's only in memory. If you add one more line to the second example, it will also be visible.
public class Chan extends Sprite
{
public static var rect:Sprite=new Sprite();
public function Chan():void
{
rect.graphics.beginFill(0x123456);
rect.graphics.drawRect(100,100,30,30);
this.addChild(rect);
}
}
EDIT:
I wanted to elaborate on this a bit. The fact that rect was a static var wasn't the main problem. I mentioned it was static in my answer but didn't want that to confuse you. The reason it doesn't work is the scope where you were drawing wasn't in view... it was simply a variable. so even if it said:
public var rect:Sprite = new Sprite();
It would not be visible until you called addChild(rect) to actually add it into view.
I'm using actionscript 3.0 and Flash Professional CS5.5
I ran into a problem with instance objects which are not on the first frame.
My first frame is a menu and my second frame contains a TLF text field.
I have given the text field an instance name, let's say "username_txt".
Now if I turn off the "Automatically Declare Stage Instances" and do this in my main class
public class MainClass extends MovieClip {
public var username_txt:TLFTextField;
public function MainClass() {
username_txt.text = "anything";
}
}
I will receive a run time error stating that I try to access the property of a null object. (I have import all the necessary classes so that is not the problem)
This does not happen when I put the text right in the first frame though.
Any help?
Thanks in advance
As the text field has not yet been instantiated since the frame has not yet been reached, I'm unsure there is an elegant way to perform this task.
Perhaps a better model would be to decouple your data model from your views.
Create a singleton class to store data:
package
{
public class ApplicationModel
{
/** Singleton instance. */
private static var instance:ApplicationModel = new ApplicationModel();
/** Return singleton instance. */
public static function getInstance():ApplicationModel
{
return instance;
}
/** Data Model */
public var username:String;
/** Constructor as singleton enforcer */
public function ApplicationModel()
{
if (instance)
throw new Error("ApplicationModel is a singleton and can only be accessed through ApplicationModel.getInstance()");
}
}
}
Then from within anywhere such as keyframes or classes, you can get the instance of the object, implemented either as:
ApplicationModel.getInstance().username = "test";
Or a better practice would be:
var applicationModel:ApplicationModel = ApplicationModel.getInstance();
applicationModel.username = "test";
As per your example:
public class MainClass extends MovieClip {
public var username_txt:TLFTextField;
public function MainClass() {
ApplicationModel.getInstance().username = "anything";
}
}
Then, on the frame you need to update your TLFTextField (frame script of frame 2), you set the text based upon the model:
username_txt.text = ApplicationModel.getInstance().username
Your view will always update when needed.
Before firing away, I know there are many questions here on SO that are quite similar. Yet, none of the solutions given were of any help to me, probably because my case is a little different.
I have a main class which loads an external class (separate .as file). In this external class, there are several objects which have tweens and time events bound to them.
What I want to do, is starting the animations when a certain function is called in my Main class. However, I've tried numerous things to stop and/or reset the animations in the external class, so it will start from the beginning if the required function in Main is called.
Main.as:
package {
//required imports
public class Main extends MovieClip {
var myClass:MyClass = new MyClass; //this is the external class
var button:Button = new Button; //movieclip in the library
public function Main() {
addChild(myClass); //I want to do this here so the objects show from the start
//try 1: myClass.gotoAndStop(1);
//try 2: myClass.stop();
button.addEventListener(MouseEvent.MOUSE_CLICK, playAnimation);
}
function playAnimation (e:MouseEvent) {
//try 1: myClass.gotoAndPlay(1);
//try 2: myClass.start();
//try 3: controlling the startTweening() function in MyClass, I tried different ways
}
}
}
The problem starts in the Main class above. I don't want to animate yet!
MyClass.as:
package {
//required imports
public class MyClass extends MovieClip {
//vars
public function MyClass() {
startTweening();
}
function startTweening() {
//tween event
//calling next function (with use of a TimerEvent) after tween is done. This is repeated several times.
}
}
}
Everything in this class works fine, so that's not the problem.
If this makes any difference, I used TweenMax in MyClass for tweening. I didn't use the timeline in the .fla.
Any help would greatly appreciated!
If you don't want to animate at creation of MyClass remove startTweening(); call from the constructor of MyClass.
Make startTweening(); a public function and call it whenever your need with myClass.startTweening().
Here the MyClass
public class MyClass extends MovieClip {
//vars
public function MyClass() {
}
public function startTweening() {
//tween event
//calling next function (with use of a TimerEvent) after tween is done. This is repeated several times.
}
}
and here the Main class
public class Main extends MovieClip {
var myClass:MyClass;
var button:Button = new Button; //movieclip in the library
public function Main() {
myClass = addChild(new MyClass()) as MyClass;
button.addEventListener(MouseEvent.MOUSE_CLICK, playAnimation);
}
function playAnimation (e:MouseEvent) {
myClass.startTweening();
}
}