0

This is for a playbook app.

I have two classes:

public dynamic class Bullet extends Sprite {
   public function update():void {
      x += 5;
      y += 5;
   }
}

public class BulletFactory {
   public function createFastBullet:Bullet {
      var result:Bullet = new Bullet();

      result.update = function() {
         x += 10;
         y += 10;
      }
   }
}

This is essentially what I'm trying to do. What's the best way to achieve this in actionscript?

Kenneth
  • 611
  • 2
  • 8
  • 17

2 Answers2

2

You don't do it that way. Dynamic is to allow you to add any ad-hoc property that isn't already declared, not to override already declared functions. Dynamic is not to be confused with abstract.

Try something like this instead

public class Bullet extends Sprite{
    public var speedX = 5;
    public var speedY = 5;

    public function update():void{
       x += speedX;
       y += speedY;
    }
}

public class BulletFactory{

    public static function getFastBullet():Bullet{
        var result:Bullet = new Bullet();
        result.speedX = result.speedY = 10;
        return result;
    }

}

Adjust the public/private visibility of speedX/speedY to your liking.

If on the other hand you want to "dynamically override a function" in as literal a sense as possible, there's always this (which is hacky but valid).

public class AbstractBullet extends Sprite{

    public var update:Function; // <- Notice that function is just a variable here.

}

Then in your bullet factory you can assign the update function on an ad-hoc basis. Note that this is less "secure" as you lose all notion of type safety as update no longer has a set signature. You also have to make sure it exists before you call it. You must make the null check explicit if you want to avoid a compiler warning.

var f:Function;

// this is fine.
// it's particularly safe if 
// f is a declared variable of type
// Function.
if(f != null) f();

// this is also fine,
// and is preffered if f is NOT
// a defined variable but instead
// a dynamically created (and therefore
// untyped) variable of a dynamic object.
// You would not want to "call" something
// that is not a function, after all.
if(f is Function) f();




// but this gives a warning
// even though the code works
// correctly at runtime.
if(f) f();
scriptocalypse
  • 4,942
  • 2
  • 29
  • 41
  • using != null to see if a Function is set is fine, you don't get compiler warnings. I use Function objects in place of event listeners all the time as it's about a 1000 times faster – divillysausages Mar 11 '11 at 10:23
  • @divillysuasages I found the issue I was talking about. It was less a null check and more of an existence check. var f:Function; if(f)f(); Will ammend the answer with this. – scriptocalypse Mar 11 '11 at 16:47
  • I actually have another type of bullet called WaveBullet which moves in a sine wave, so it wouldn't necessarily use a speedX and speedY. – Kenneth Mar 11 '11 at 18:28
  • @Kenneth In that case, you'd use more classic inheritance and create a separate "WaveBullet" class that extends Bullet in the AS3 context. As I mentioned, the only way to override an "abstract function" in AS3 is to define it as var f:Function = function(){trace("I'm a function");} but that's not as well supported in AS3 as just creating a new specific derived class. – scriptocalypse Mar 11 '11 at 21:20
1

You could solve your issue using a combination of Interfaces, extensions and overrides. The below won't compile, but should give you a starting point.

public interface IBullet {
    function update():void
}

public class DefaultBullet extends Sprite implements IBullet{
   public function update():void {
      x += 5;
      y += 5;
   }
}

public class FastBullet extends DefaultBullet implements IBullet{
   override public function update():void {
      x += 10;
      y += 10;
   }
}

public class BulletFactory {
   public function createBullet(bulletType:String):IBullet {
      var bullet:IBullet;
      if(bulletType=="fast"){
        bullet = new FastBullet();
      }else{
        bullet = new DefaultBullet();
      }
      return bullet;
   }
}
Trevor Boyle
  • 1,025
  • 7
  • 15