Gossmatica

Building Aukera Part 4: Actors and their Features

I said in Part 3 that there’s nothing special about Actors. They’re any object that’s registered with the game as such, and if an actor happens to have a method in place for a certain pseudo-event then it will be called at the appropriate times. So really, to make an actor one just adds a method to an existing object, and then passes it to game.addActor. One could just write an actor ad-hoc and add it to the game. Could it be any simpler?

Actually, it could.

The Actor Constructor

It’s not considered part of the core engine, but I think it’d be silly not to use it. The Actor component adds a constructor at auk.Actor. The actors created by this constructor are a great place to start for any actor the game may need: For starters, there’s properties for the position and image, and an update loop that draws the actor in the right place. Now, if this were a classical language I’d tell you to create a new class extending Actor and go from there, but javascript is capable of some much more interesting solutions.

Here’s a quick sample of how it looks though, which I’ll add to as we go along. The game’s addActor method returns the actor it’s given, so assuming we’ve got one of those already, right away things look pretty clean:

var player =  game.addActor(new auk.Actor(0,0,0, 'images/actor.png'));

The Update Steps

I mentioned that these actors have update loops already, what I didn’t mentioned is that the update loop is designed to be expanded on. Each of these actors has an array at actor.updateSteps that contains all the functions that need to be run when the actor is update. The functions are called using the .call() method, so they actually run as methods of the actors. All that has to be done to add functionality is a call to actor.updateSteps.push(). I don’t recommend using this feature as a permanant fixture in you code, since the add() method I’m about to show you is much nicer, but it can be very useful for testing new functionality without writing new components and the like. Here’s how you could make the actor from the previous example move across the screen:

var player = game.addActor(new auk.Actor(0,0,0, 'images/actor.png'));
player.updateSteps.push(function () {

	// Remember, these functions are called as methods of the
	// Actor, so `this` points to the actor itself
	this.x += 0.01;

});

And that’s it! The actor will now walk across the room at 0.01 grid units per frame. But what if we want something more powerful than just more functions called on update?

Actor features

Actor features are lumps of functionality components can provide for actors in the game. Features don’t assume the actors they’re being added to a built from the actor constructor, but they may assume certain other features (like the updateSteps array) are present. All features have an addTo() method that accepts an actor (and sometimes settings), and then messes with it. Some features, like the one available from keybinding objects, just add some properties that other features can use. More powerful features (like auk.Physics.motor from the Physics component) add multiple properties and add to the updateSteps array.

“Okay, so what? you’re saying, you just said this doesn’t depend on the actor constructor, so what is it doing here? Well, the actor constructor has a convenience method that really plays nice with features. actor.add() takes a feature and an options object, and calls the features addTo() method with itself and the options object as arguments. When feature.addTo() returns, the add() method returns itself for easy chaining. What this means is that with the right components installed, creating an actor that walks around using the WASD keys and jumps with space is as simple as:

player = game.addActor(
	new auk.Actor(5,5,6, 'images/actor.png')
	.add(new auk.Keybinding({
		87 : 'up',
		68 : 'right',
		83 : 'down',
		65 : 'left',
		32 : 'jump'
	}))
	.add(auk.Physics.jump, {power: 35})
	.add(auk.Physics.motor, {speed: 6})
);

I’ll talk more about physics and keybindings in some other posts.