I'm making a Java shoot em up game for Android phones. I've got 20 odd enemies in the game that each have a few unique behaviors but certain behaviors are reused by most of them. I need to model bullets, explosions, asteroids etc. and other things that all act a bit like enemies too. My current design favors composition over inheritance and represents game objects a bit like this:
// Generic game object
class Entity
{
// Current position
Vector2d position;
// Regular frame updates behaviour
Behaviour updateBehaviour;
// Collision behaviour
Behaviour collideBehaviour;
// What the entity looks like
Image image;
// How to display the entity
Renderer renderer;
// If the entity is dead and should be deleted
int dead;
}
abstract class Renderer { abstract void draw(Canvas c); }
abstract class Behaviour { abstract void update(Entity e); }
To just draw whatever is stored as the entity image, you can attach a simple renderer e.g.
class SimpleRenderer extends Renderer
{
void draw(Canvas c)
{
// just draw the image
}
}
To make the entity fly about randomly each frame, just attach a behavior like this:
class RandomlyMoveBehaviour extends Behaviour
{
void update(Entity e)
{
// Add random direction vector to e.position
}
}
Or add more complex behaviour like waiting until the player is close before homing in:
class SleepAndHomeBehaviour extends Behaviour
{
Entity target;
boolean homing;
void init(Entity t) { target = t; }
void update(Entity e)
{
if (/* distance between t and e < 50 pixels */)
{
homing = true;
// move towards t...
}
else
{
homing = false;
}
}
}
I'm really happy with this design so far. It's nice and flexible in that you can e.g. modularize the latter class so you could supply the "sleep" behavior and the "awake" behavior so you could say something like new WaitUntilCloseBehaviour(player, 50/pixels/, new MoveRandomlyBehaviour(), new HomingBehaviour()). This makes it really easy to make new enemies.
The only part that's bothering me is how the behaviors and the renderers communicate. At the moment, Entity contains an Image object that a Behaviour could modify if it chose to do so. For example, one behavior could change the object between a sleep and awake image and the renderer would just draw the image. I'm not sure how this is going to scale though e.g.:
What about a turret-like enemy that faces a certain direction? I guess I could add a rotation field to Entity that Behavior and Renderer can both modify/read.
What about a tank where the body of the tank and the gun of the tank have separate directions? Now the renderer needs access to two rotations from somewhere and the two images to use. You don't really want to bloat the Entity class with this if there is only one tank.
What about an enemy that glows as his gun recharges? You'd really want to store the recharge time in the Behaviour object, but then the Renderer class cannot see it.
I'm having trouble thinking of ways to model the above so the renderers and the behaviors can be kept somewhat separate. The best approach I can think of is to have the behavior objects contain the extra state and the renderer object then the behavior objects call the renderers draw method and pass on the extra state (e.g. rotation) if they want to.
You could then e.g. have a tank-like Behaviour object that wants a tank-like Renderer where the latter asks for the two images and two rotations to draw with. If you wanted your tank to just be a plain image, you would just write a subclass Renderer that ignored the rotations.
Can anyone think of any alternatives? I really want simplicity. As it's a game, efficiency may be a concern as well if e.g. drawing a single 5x5 enemy image, when I have 50 enemies flying around at 60fps, involves many layers of function calls.