Search code examples
javaoopjava-2d

Game design in an OO manner


I'm designing a simple game, which uses Java 2D and Newtonian physics. Currently my main "game loop" looks something like:

do {
  for (GameEntity entity : entities) {
    entity.update(gameContext);
  }

  for (Drawable drawable : drawables) {
    drawable.draw(graphics2d);
  }
} while (gameRunning);

When an entity is instructed to update itself it will adjust its velocity and position based on the current forces applied to it. However, I need entities to exhibit other behaviour; e.g. if a "bad guy" is shot by a player the entity should be destroyed and removed from the game world.

My question: What is the best way to achieve this in an object oriented manner? All examples I've seen so far incorporate the game loop into a God class called something like Game, which performs the steps: detect collisions, check-if-bad-guy-killed, check-if-player-killed, repaint, etc and encapsulates all the game state (lives remaining, etc). In other words, it's very procedural and all the logic is in the Game class. Can anyone recommend a better approach?

Here are the options I've thought of so far:

  • Pass a GameContext to each entity from which the entity can remove itself if required or update the game state (e.g. to "not running" if the player is killed).
  • Register each GameEntity as a listener to the central Game class and take an event oriented approach; e.g. a collision would result in a CollisionEvent being fired to the two participants in the collision.

Solution

  • I have worked closely with two commercial game engines and they follow a similar pattern:

    • Objects represent components or aspects of a game entity (like physical, renderable, whatever), rather than the whole entity. For each type of component there is a giant list of components, one for each entity instance that has the component.

    • The 'game entity' type itself is just a unique ID. Each giant list of components has a map to look up the component (if any exists) that corresponds to an entity ID.

    • If a component requires an update it is called by a service or system object. Each service is updated directly from the game loop. Alternatively, you could call services from a scheduler object which determines update order from a dependency graph.

    Here are the advantages of this approach:

    • You can freely combine functionality without writing new classes for every combination or using complex inheritance trees.

    • There is almost no functionality that you can assume about all game entities that you could put in a game entity base class (what does a light have in common with a race car or a sky-box?)

    • The ID-to-component look-ups might seem expensive, but services are doing most of the intensive work by iterating through all the components of a particular type. In these cases, it works better to store all the data you need in a single tidy list.