Game architecture
Although games vary wildly in appearance and mechanics, the structure of the underlying classes and objects is often similar. There is a “world” object, which contains everything else; there are multiple “entities” representing stuff in the world, there’s a “renderer” which tells each object to draw itself, etcetera. My game is no different, but still contains some interesting aspects that I would like to highlight.
There are many different types of objects in the game: floor tiles, obstacles, shopping carts, powerups, UI buttons, timers … Some of these need to be drawn to the screen. Some need a corresponding body in the physics engine. Some need to respond to touch events. Some need to receive a tick to perform some action each frame. Some need all of the above; some have other, special needs.
Suppose we would use a classical object-oriented approach: we create an inheritance tree, extending base classes to add functionality. But now suppose that we want some classes to be Renderable
(it has methods to draw itself), such as a shopping cart and a floor tile. Other classes have to be Physical
(their motion is driven by the physics engine), such as triggers and, again, shopping carts. A floor tile is only Renderable
, a trigger is only Physical
, and a shopping cart is both. Since Java does not support multiple inheritance, we have two choices: put all functionality that we might possibly need into one big stinking base class; or declare some interfaces and duplicate their implementation in several different derived classes. Neither sounds like a good idea.
A better approach is described by Chris Pruett in his excellent talk Writing Real-Time Games for Android. In the engine he developed for his open-source game Replica Island, each game object is relatively dumb. In my game, I dumbed it down even further, to the point that a GameObject
contains only the position of the object in the game world, a state, and a list of components.
The real magic, then, happens in these components. There is a ModelComponent
that renders a 3D model to the screen. There is a BodyComponent
that pulls position updates from the physics engine. There is a RotateComponent
that does nothing but make the object spin around at a constant rate. There is a ThrusterComponent
that represents one of the thrusters on a rocket-enabled shopping cart. A GameObject
can contain a lot of these components, or none at all (although that wouldn’t be very useful).
Each component can be either active or inactive. The exact meaning depends on the particular component, but generally, inactive components don’t do much. For example, a component that does some rendering will register itself with the renderer when it is activated, and unregister itself when it is deactivated again. The components are very autonomous in this regard: the parent GameObject
doesn’t have to know a single thing about rendering or the renderer.
Whether a component is active is dependent on the state of the GameObject
. This is simply an integer, and its meaning depends on the particular object. Each component contains a bit mask, which indicates for which states of the GameObject
we want the component to be active. The GameObject
then takes care of activating and deactivating the proper components when its state changes.
Some components need to interact with one another. For example, the component that does the AI computations has to talk to the cart’s thrusters in order to control them. In the source code of Replica Island, above its GameObject
class, a comment says:
GameObjects are also “bags of data” that components can use to share state (direct component-to-component communication is discouraged).
I did not follow this approach, but instead let components know about each other’s existence when they have to. The advantage is that the GameObject
remains relatively simple and lightweight; the drawback is a potential tangle of references between components. So far, I haven’t had trouble with my approach yet. The result is that most types of GameObject
are little or nothing more than a constructor to set up the components; all the rest is handled automatically.
I promised on Twitter that this post would contain a video. I’m currently working on weapons and powerups in the game, and got one half working. Since I’d prefer to demonstrate the first weapon only when it’s done, and since I don’t like to break promises, here’s a video!
I still think rocket engines are cooler, but this is a neat idea too!