Issues with Accessing Superclass Properties (AS3) - actionscript-3

I am running into an issue where it seems to be ignoring functions I try to overload.
I have a class called Projectile that extends the Entity class. Projectile is passed an array of MovieClips to compare collision against. If it collides with one of those array elements, collidingWith is set to that object. The onCollision()function is then called to resolve what should happen to the colliding object.
Here is the relevant code:
public class Main extends MovieClip{
...
for(var i in projectileArray){
projectileArray[i].update();
}
...
}
public class Entity extends MovieClip{
protected var canCollideWith:Array; //Array of objects to test collision against
protected var collidingWith:Object; //Object this projectile collided with
...
protected function update(){
this.checkCollision()
}
protected function checkCollision(){
for(var in canCollideWith){
if (image.hitTestObject(canCollideWith[i])){
collidingWith = canCollideWith[i];
this.onCollision();
}
}
}
protected function onCollision(){
//To be overriden by child classes
trace("Entity onCollision");
}
}
public class Projectile extends Entity{
public function Projectile(...){
super.(...);
}
override protected function onCollision(){
trace("Projectile onCollision");
}
}
Based on trace statements I tried, I am able to overload Entity.update() and Entity.checkCollision, it will not let me override Entity.onCollision(). It will only ever go to the onCollision function of Projectile's superclass (Entity).
Further, when I attempt to access collidedWith from within any Projectile function, it remains at its default value, and is not sharing the value it should be set to from within Entity.checkCollision().
Am I missing something? Is there some OOP aspect I am overlooking?
Thanks in advance,
Glen

Nevermind, I figured out the problem. Projectiles can collide with Mortals, which are both subclasses of Entity. The trace statements for collision were being called from within the Mortal class, not Projectile, hence why the override did not appear to work.

Related

How to apply a method only to a certain sub class of Actor in Stage

My game has a class named Enemy which extends Actor. Additionally, I have an EnemyAffector class which has methods that affect Enemies, roughly like this:
class EnemyAffector {
public void affect(Enemy enemy) { ... }
}
In my Stage, in the act method, I want to iterate over all Enemies and apply an EnemyAffector to them. The obvious way is by casting:
#Override
public void act() {
super.act();
for (Actor actor: getActors()) {
if (actor instanceof Enemy) {
enemyAffector.affect((Enemy)actor);
}
}
...
}
However, legend has it that using instanceof should be avoided. So, I considered keeping an additional Array to which I will add Enemies as they are added to the Stage, i.e., by overloading my Stage with another addActor method:
public void addActor(EnemyProjectile pEnemyProjectile) { // add to Enemy Array }
So now my act method looks like this:
#Override
public void act() {
super.act();
for (Enemy enemy: enemyArray) {
enemyAffector.affect(enemy);
}
...
}
Yay! No instanceof!
However, the problem with this solution is that I will always need to synchronize between the Enemy Array, and the standard Actor Array because Enemies in the Enemy Array may have been removed from the Stage.
My question is, is there a different, cleaner, approach which can I take here?
You could either use the UserObject that you can add to an actor:
public enum ActorType
{
PLAYER, ENEMY, ETC;
}
//...
Enemy enemy = new Enemy();
// Or set this in the constructor
enemy.setUserObject(ActorType.ENEMY);
for (Actor actor : actors)
{
if (actor.getUserObject() == ActorType.ENEMY)
{
// Do stuff...
}
}
Or put your two arrays in an extra class and add methods for adding/removing:
public class ActorManager
{
private Array<Actor> actors = new Array<>();
private Array<Enemy> enemies = new Array<>();
public void add(Actor actor)
{
actors.add(actor);
}
public void add(Enemy enemy)
{
actors.add(enemy);
enemies.add(enemy);
}
public void remove(Actor actor)
{
actors.removeValue(actor, true);
}
public void remove(Enemy enemy)
{
actors.removeValue(enemy, true);
enemies.removeValue(enemy, true);
}
// To make sure our backing arrays are not modified:
public Array<Actor> getAll()
{
return new Array<>(actors);
}
public Array<Actor> getEnemies()
{
return new Array<>(enemies);
}
}
I quickly encountered a similar situation with LibGDX with both the Actor and Stage class. I created my own sub-class extending Actor, which I was going to use as the "base Actor" Object for all my Actors.
That way, you can set up methods which will be called by all your Actors on certain situations.
class MyStage extends Stage
{
public void addActor(MyActor pEnemyProjectile) { // call onAdd }
//override other methods as necessary,
//possibly getActors() to return Actors as MyActors, etc
}
class MyActor extends Actor
{
public void update(double delta)
{
//I find it easiest to have "removal" code happen in the Actor's update method, then I can call onRemove()
//This could happen by finding death conditions or just checking a "isDead" boolean.
}
public void onAdd()
{
//can set up a default behavior, or just override on other subclasses
}
public void onRemove()
{
//call for every Actor that gets removed - can extend and remove Enemies from an Enemy list if desired
}
//maybe it would be better to check if the Object can be Affected here?
//rather than keeping and maintaining a separate list
public boolean isAffected()
{
return false; //return true by Enemies
}
}
class Enemy extends MyActor
{
//implement onRemove, onAdd, etc..
}
If it works better, MyActor could also be created as an interface instead - and then you could just as easily create sub-classes for Label or other LibGdx classes which inherit from Actor.
I personally chose to make it a sub-class, just because I could create helper-methods which were easier to type and call - such as my "movement" and "rotation" code, which don't use the Action classes which LibGdx comes with.
The easiest and in my opinion generating least lines of code is to use UserObject Actor field like:
Actor actor = new Actor(); //or its children ofc
actor.setUserObject("enemy");
//...
if( actor.getUserObject().equals("enemy") )
{
//yup this is enemy
}
Of course it is not the best solution due to OOP and can be not very flexible in some cases but to be honest in a case like this handling additional arrays etc etc only complicates things.
Notice that UserObject is object type so if you want to push there something that Java cannot cast itself you will have to cast it on your own.
However if you would want to be super ok here's another more elegant solution:
You are overriding the Actor class with your own MyActor class with some customAction() method which do nothing. You will be inheriting from this class not from Actor now
In every child class the method do nothing but in your Enemy class you are implementing the funcionality
In a loop you are casting to (MyActor) and calling customAction method
for (Actor actor: getActors()) {
((MyActor)actor).customAction();
}
The customAction method has a logic from EnemyEffector
This would generate some problems if you are inheriting classes that inherits from Actor (like Label class) and also will be a problem if the EnemyEffector logic is using data that Actor instance should not know because they are global for example and shouldn't be redundant (of course you can also pass the information as a parameter of customAction method)

AS3 Method in superclass, public static vars in subclass

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

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

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");
}
}
}

AS3 pass MovieClip to super

I have a Spaceship movieclip, with a movieclip Turret inside.
Spaceship extends the Unit class, where I want to rotate the Turret.
In my Spaceship constructor, I use super(this.turret); but this always returns null.
Passing other variables works, and before calling super(), I can successfully trace this.turret
So why can't I pass it to super? And how can I fix this?
[edit]
Perhaps it has something to do with the turret not being available/added to stage yet when super() is called? If so, how could I deal with that and get it "Unit" anyways?
When you pass turret into the constructor you are only passing a reference to the MovieClip with that instance name. What does the Unit constructor do with the parameter? I guess that your Unit class are not supposed to have a turret variable.
UPDATE 1:
public class SpaceShip extends Unit
{
public var turret : MovieClip;
public function SpaceShip()
{
super();
}
}
// Access from other class where ship has been referenced
public class Test extends Sprite
{
public var ship : SpaceShip;
public function ship()
{
// access the public variable (reference) turrent
ship.turrent.rotation += 25;
}
}