Tuesday, November 23, 2010

Game Engine Design: Game Contexts

I have been working on game engine design for the past... um... hmm I can't remember when I started... well lets just say it's been years. Typically I have entity objects, and a Game State Machine implementation. The entity objects became the base class for all other game objects. Entity objects would have been able to be updated and rendered. This allowed me to do everything I needed specific to each entity.

For rendering I would pass only the graphics object to each entities render method. Something that looks like public void render(Graphics2D g). For updating I would pass the time passed since the last call which looked something like public void update(double dt). Each entity would have their render/update methods called at least one per frame.

How it used to be!
As I was working on a few games using my work-in-progress engine code, I came across situations where it would be easier for the entities to already have all the information they need and have spawn and kill functions. A game entity needs to know information about the world, other objects, screen sizes, etc. Also I needed the ability for an entity to change states of the game system. But that is only because the entities were checking input and doing game logic.

The system worked fine the way it was, it was just very painful modifying constructors and adding parameters to methods, I had even modified the render methods sometimes to be passed the time and dimensions of the screen. I constructed a Spawner interface which essentially was implemented by my world container class and allowed objects to have a spawner and to spawn other objects. The spawner was really really nice because it allowed any entity to create new ones on the fly the creating entity could hold on to them and then kill them if need be. The problem with this approach is that each object contains a reference to a spawner, which had to be set and could potentially not have been set causing errors or lots of additional null checks.

Enter Game Contexts
I am a big fan of Design Patterns and after experimenting with different design patterns in games such as the Composite, Observer, Visitor and Mediator. I found that what my entity objects needed was a mediator between them and the rest of the game system. So I figured I could put all the methods and information needed by the game objects into an interface to be implemented by the main game class. It turned out to look something like this
public interface GameContext {

    // the width of the screen
    public int getWidth();

    // the height of the screen
    public int getHeight();

    // the input manager
    public InputManager getInput();

    // the time passed in seconds between frames
    public double getTimePassed();

    // spawn a new entity
    public void spawn(Entity e);

    // kill the entity
    public void kill(Entity e);

    // switch game states
    public void changeState(State next);

    // return the graphics object used for rendering
    public Graphics2D getGraphics();

    // set fullscreen mode
    public void setFullscreen(boolean fullscreen);

    // return whether the game is fullscreen or not
    public boolean isFullscreen();

This interface gave each game object the methods it needed to do a lot more than they could before. The render/update methods now changed to
public void render(GameContext gc);

public void update(GameContext gc);
It really does make a lot of difference when creating new entities and you can add lots more to the GameContext. For instance you could have a method for collision detection or initiating certain effects etc... It is also just as efficient as the previous method since only one parameter is being passed to the game objects.

I hope to show a full runnable snippet using this idea sometime in the future. This should be enough to get you started if you already have something in place. If you have an alternative method to share it would be much appreciated, or if you've already used something like this it would be nice to know as well.

That's all for now, getting ready for Turkey day.

No comments:

Post a Comment