AS3 Method in superclass, public static vars in subclass - actionscript-3

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

Related

Animation in class files?

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 :)

AS3 Inheritance

When 'SubClass' extends 'SuperClass', when it inherit its methods and properties, it creates methods and properties that distinguishes from the 'SuperClass'?
Or if I create an instance of 'SubClass' and I try to modify a property, that was inherited from 'SuperClass', am I modificating the super class property also?
Thanks.
EDIT
package {
public class SubClass extends SuperClass {
public function SubClass() {
trace('superclass value n='+superClass.n+'\n');
trace('subclass changes inherited n'+'\n');
n = 3;
trace('subclass value n='+n+'\n');
trace('superclass value n='+superClass.n+'\n');
}
}
}
Returns me:
superclass value n=-1;
subclass changes inherited n;
subclass value n=3;
superclass value n=3;
I will explain it in short.
We have two classes - Subclass and SuperClass.
SuperClass have four methods:
private function methodPrivate():void;
protected function methodProtected():void;
public function methodPublic():void;
internal function methodInternal():void;
From the Subclass you:
Cannot access methodPrivate():void;
Can access methodProtected():void; but just like your private method, it means, you cannot access it from outside of Subclass.
Can access methodPublic():void; and everything can access if from outside of Subclass also.
methodInternal():void; is available for classes from the package of SuperClass.
You can however override these methods. Overriding doesn't change a methods of SuperClass but change them only in SubClass.
override public function methodPublic() : void {
// your additional code
super.methodPublic(); // eventually calling the same method of SuperClass, you can pass arguments to it also
}
As you know, your SuperClass can also have variables, that also can be public, protected, private or internal. You cannot override them, but you can do this with getters or setters however.
You can access variables that are created as public or protected by using a word "super" like this: super.someVariable .
So everything is up to you, if you want to create a different variables of the same name in SuperClass and SubClass, just declare one as private in SuperClass. If you want to have one variable that SuperClass and SubClass both can access - just declare it as protected or public.
Hope that was clear.
When you create a blank SubClass the extends SuperClass, you are creating a new class that provides the same interface (with the same implementation) to the parent class.
That is to say, if your parent class contains a method doSomething, your SubClass, without ever actually writing it, will have the doSomething method available as well. The one caveat to this is if the method is marked private, in which case the inheriting class, SubClass, will not have access.
package {
public class SuperClass {
public function SuperClass():void {
self.doSomething();
}
public function doSomething():void {
trace("doing something");
}
}
package {
import SuperClass;
public class SubClass extends SuperClass {
public function SubClass():void {}
}
}
Once you have this relationship established, you can decide whether calling doSomething on an instance of SubClass will behave differently than the default implementation, defined in SuperClass. If you want the same behavior, you leave it as is. If you want different behavior, then you override the parent class' method, using the keyword override.
package {
import SuperClass;
public class SubClass extends SuperClass {
public function SubClass():void {}
override public function doSomething():void {
trace("doing another thing instead");
}
}
}
Now something that calls doSomething on an instance of SubClass will get modified behavior. But the default implementation has not been touched. Instanced of SuperClass are not modified by this overriding of a method. Only instances of SubClass will be affected.
This is the same case for properties.
There is one exception to this, and that is static properties. A static property is a property of the class, not of an instance of the class. Static properties are not inherited. A static property looks like this:
package {
public class SuperClass {
public static var i:int = 0;
public function SuperClass():void {
}
public function doSomething():void {
trace("doing something");
}
}
The SubClass class will not have a reference to a static property i. However, a SubClass instance can change the static value of the SuperClass. As an example:
package {
import SuperClass;
public class SubClass extends SuperClass {
public function SubClass():void {}
override public function doSomething():void {
trace("changing something in SuperClass");
SuperClass.i = 1;
}
}
}
Now, the SuperClass's static variable i has a value of 1, instead of 0. In this way a SubClass has the potential (although it is the same potential any code has with the right access privileges) to change the properties of SuperClass.
I hope this helps.

ActionScript3: Inheriting constructor arguments from parents

I'm making a game in action script 3. In it, I have an actor class from which player and enemy classes will be derived. I'm doing this so that unless I need to provide specific AI or fancy behavior (such as for bosses), I can just make a new clip in the library for each enemy without making an actionscript file.
However, I've run into a problem.
Whenever I try to pass arguments to the construction of an enemy (make it spawn with more health), I get error 1136 (Incorrect number of arguments.)
This is because the constructor created automatically at runtime doesn't have the same arguments as it's parent class. Is there any way to get around this without making a class file where I copy and paste the parent constructor function for each of my hundreds of enemies?
Edit
actually rereading your question I think you may be looking for super();
Example
public class Actor{
private var myHelth:uint;
public function Actor(helth:uint = 100){
myHelth = helth; //this will be set to 100 if nothing it passed in or the value passed
}
}
Class that extends Actor:
public class Boss extends Actor{
public function Boss(){
super(200); //passes 200 to Actor;
}
}
If you're trying to pass data into a classes constructor you need to make sure it's accepting arguments.
public class Actor{
private var myHelth:uint;
public function Actor(helth:uint = 100){
myHelth = helth; //this will be set to 100 if nothing it passed in or the value passed
}
}
Then to use
var a:Actor = new Actor(200); //setting health to 200
var b:Actor = new Actor(); //using the default of 100
Make sure your symbols in Flash Pro have appropriate AS linkage, then use pass constructor arguments in super statements:
Actor - base class
package
{
public class Actor
{
public function Actor(name:String, role:String)
{
}
}
}
Player - inherits from Actor defining its own constructor parameters:
package
{
public final class Player extends Actor
{
public function Player(... params:Array)
{
// pass desired inherited constructor parameters
super("name", "role");
}
}
}
Enemy - inherits from Actor defining its own constructor parameters:
package
{
public final class Enemy extends Actor
{
public function Enemy(... params:Array)
{
// pass desired inherited constructor parameters
super("name", "role");
}
}
}

How to Access Properties And Methods of a Class Without Extending or Instantiating?

Let's say I have a defined ClassA.
ClassB extends ClassA and there's a Movie Clip instance on the stage linked to ClassB.
How would ClassC access the properties and methods of ClassB without extending ClassB or creating a new instance of ClassB?
The way I'm currently doing it is by referencing the stage instance linked to ClassB and then using the dot syntax to access ClassB instance variables, and this works only if the the accessed variables are public or internal, depending on what package ClassC is part of. I would like to know if there's a better, cleaner way to accomplish this.
Edit: Code example.
package com.core.stage.classes {
import flash.display.MovieClip;
public class ClassA extends MovieClip {
public var classAvar:uint = 0;
public function ClassA() {
}
protected function classAfunction(funPar:uint):void {
classAvar = 2 * funPar;
}
}
}
package com.core.stage.classes {
import com.core.stage.classes.ClassA;
public class ClassB extends ClassA {
public function ClassB() {
classAfunction(10);
}
}
}
package com.core.stage.classes {
import flash.display.MovieClip;
public class ClassC extends MovieClip {
private var classBreference:*;
public function ClassC() {
classBreference = Object(parent);
trace(classBreference.classAvar); // Outputs 20.
}
}
}
So what I basically want to know is if there's a better way to get the value of classAvar (which was declared in ClassA, got a value after calling the method in ClassB) while working in ClassC.
Solved:
Ok, after some research and an idea I got from daniel.sedlacek, it seems that I have found the solution that best suits my needs.
in ClassB:
private static var _instance:ClassB;
public function ClassB() { // constructor
_instance = this;
}
public static function get FUN_GetInstance():ClassB {
return _instance;
}
in ClassC:
private var MC_VariablesContainer:ClassB
MC_VariablesContainer:MC_ClassB = ClassB.FUN_GetInstance
and this works only if the the accessed variables are public or internal, depending on what package ClassC is part of. I would like to know if there's a better, cleaner way to accomplish this.
This is one of the base principles of OOP. You can not get private and protected properties or methods. If you want to get them, you should make them public or internal.
A)
Don't do it, think of better architecture that will respect encapsulation loose coupling.
B)
If you have to do it, you can use static global register and make all stage instances (like your ClassB) assign to it, for instance:
in ClassB:
StaticRegister.assign(this);
in StaticRegister:
publis static var register : Array = [];
public static function assign(instance : Object) : void {
array.push(instance);
}
And then get it out of there in similar fashion. But it's really dirty to do it like this.
C)
If there is only one instance of ClassB you can give it static - singleton like - accessors:
In ClassB:
private static var instance : ClassB;
publis static function getInstance() : ClassB {
return instance;
}
In Constructor:
public class ClassB() {
instance = this;
}
More about complete singletons: www.actionscript.org or Google or Wikipedia.

Actionscript 3: Can someone explain to me the concept of static variables and methods?

I'm learning AS3, and am a bit confused as to what a static variable or method does, or how it differs from a method or variable without this keyword. This should be simple enough to answer, I think.
static specifies that a variable, constant or method belongs to the class instead of the instances of the class. static variable, function or constant can be accessed without creating an instance of the class i.e SomeClass.staticVar. They are not inherited by any subclass and only classes (no interfaces) can have static members. A static function can not access any non-static members (variables, constants or functions) of the class and you can not use this or super inside a static function. Here is a simple example.
public class SomeClass
{
private var s:String;
public static constant i:Number;
public static var j:Number = 10;
public static function getJ():Number
{
return SomeClass.j;
}
public static function getSomeString():String
{
return "someString";
}
}
In the TestStatic, static variables and functions can be accessed without creating an instance of SomeClass.
public class TestStaic
{
public function TestStaic():void
{
trace(SomeClass.j); // prints 10
trace(SomeClass.getSomeString()); //prints "someString"
SomeClass.j++;
trace(SomeClass.j); //prints 11
}
}
A static variable or method is shared by all instances of a class. That's a pretty decent definition, but may not actually make it as clear as an example...
So in a class Foo maybe you'd want to have a static variable fooCounter to keep track of how many Foo's have been instantiated. (We'll just ignore thread safety for now).
public class Foo {
private static var fooCounter:int = 0;
public function Foo() {
super();
fooCounter++;
}
public static function howManyFoos():int {
return fooCounter;
}
}
So each time that you make a new Foo() in the above example, the counter gets incremented. So at any time if we want to know how many Foo's there are, we don't ask an instance for the value of the counter, we ask the Foo class since that information is "static" and applies to the entireFoo class.
var one:Foo = new Foo();
var two:Foo = new Foo();
trace("we have this many Foos: " + Foo.howManyFoos()); // should return 2
Another thing is static functions could only access static variables, and couldn't be override, see "hidden".