Friday, August 24, 2012

Easier object setup in ActionScript

I recently thought of something that will make it easier when I'm creating instances with different values in ActionScript and thought I'd share it. It's sort of a mix of default parameter values and optional parameters and it makes it much more convenient to setup instances of things that are slightly different.

Let's suppose I have a Weapon class with some basic stats:

class Weapon
{
 public var name:String;
 public var attack:int    = 10;
 public var defense:int   = 10;
 public var speed:Number  = 1.0;
 public var heavy:Boolean = false;
 public var tags:Array    = ["weapon"];
 
 /* skipping constructor and a "describe" function that prints the values */
}

And assume I have some other code that creates a bunch of instances. They're mostly the same but ideally I could just specify what's different than the default. Something like this:

var weapons:Array = [
 new Weapon("stick"),
 new Weapon("sword", { attack: +2, defense: +2 } ),
 new Weapon("club",  { speed: -0.25, heavy: true } ),
 new Weapon("knife", { attack: -2, tags: ["sharp"] } )
];

for each (var weapon:Weapon in weapons)
 trace(weapon.describe());

It would be really cool if I could get something like this as the output:

stick = { attack=10, defense=10, speed=1, heavy=false, tags=weapon}
sword = { attack=12, defense=12, speed=1, heavy=false, tags=weapon}
club = { attack=10, defense=10, speed=0.75, heavy=true, tags=weapon}
knife = { attack=8, defense=10, speed=1, heavy=false, tags=weapon,sharp}

Well, wish no more because it's possible. Here's the function that makes it happen. It takes two things and expands the first by the second. It could be improved to handle other types, but this is enough to get started with.

public function expand(receiver:Object, expansions:Object):Object
{
 if (receiver == null || expansions == null)
  return receiver;
  
 for (var property:String in expansions)
 {
  if (receiver[property] == null)
   continue;
  
  var value:Object = expansions[property];
  
  if (value is Number || value is int)
  {
   receiver[property] += value;
  }
  else if (value is Array)
  {
   for each (var element:Object in value)
    receiver[property].push(element);
  }
  else
  {
   receiver[property] = value;
  }
 }
 
 return receiver;
}

Just use it in the constructor or some section external to the object like a Factory.

public function Weapon(name:String, values:Object = null)
{
 this.name = name;
 Util.expand(this, values);
}

I'm sure I'm not the first to do something like this but I think it's a more convenient way to create things. If I ever find myself working on a 7 day long project and need a quick way to add content, this could be useful....

No comments:

Post a Comment