Phil Hassey - game dev blog
Phil Hassey as Rambo
".. I've been there,
I know what it's like,
and I'll do it again if I have to."

Dynamite Jack: Component Object model

I’m gonna dig into some of the tech behind Dynamite Jack, so hold onto your seats.

So, a lot of devs are into Component Object game design. That article is by a friend of mine who goes into a good overview of a lot about the model. Anyway, you could probably spend all day reading the resources he links to. The short version (as I see it): Ideal Component Object game design is like a Normalized Database. It basically means, it’s kind of a chore to get it working but it’s super flexible and powerful.

I thought that was interesting. So I went to a talk at 360iDev by Gareth Jenkins. He demonstrated how to do component architecture with real concrete examples, which really helped me get my head around the idea. But the most profound bit of the talk was the end, where I remember him saying something like:

“It doesn’t matter HOW you do this, as long as you DO IT.”

That was super freeing for me. The idea that it didn’t matter how hacky I did it, but it would still give me all the benefits was very helpful. So here’s how I do the component object model in Dynamite Jack:

struct Entity {
  bool active;
  bool has_player;
  bool has_guard;
  bool has_light;
  bool has_position;

  int player_state;
  int player_cartridges;

  int guard_state;

  float light_angle;
  float light_radius;
  float light_degrees;

  float position_x;
  float position_y;
};

#define MAX_ENTITIES 64
Entity entities[MAX_ENTITIES];

Now, you’ll see the cool bit is that I have access to all data without creating anything, so no free / delete needed. The simple bit is activating a feature is just a matter of setting “has_light” to on or off. That’s how I actually turn on and off the player’s flashlight in the game.

In the game code, I just loop through all the items and dispatch to various functions for each component type.

void sys_loop() {
  LOOP_ENTITIES() {
    if (e.has_player) { player_loop(e); }
    if (e.has_guard) { guard_loop(e); }
    if (e.has_light) { light_loop(e); }
    if (e.has_position) { position_loop(e); }
  }
}

And I have a similar function for handling events, and painting the screen. It made it really great for prototyping the game and changing features. The “cave trolls” in the game (see at the start of the trailer) had their AI replaced quite a few times, and being able to just hack new things on and change things around without breaking my other entities was really nice!

One of the other nice things about having it explicitly in code, as opposed to “registering” things magically, is that I can see exactly in my code what order the components are being run in, so if something depends on something else, I can be sure they are in the right order.

Dynamite Jack has 20 different “components” but they all lie in the same big structure. Another cool one is having an “action” component, which doesn’t even exist in the game, it’s just a timer to trigger some future event. With everything being an Entity, it just gets it’s own loop called, and is able to do whatever.

So, yeah, my method gives me only a single Class, as many components as I like, and the flexibility to mix and match stuff. The power to toggle components on and off. And a fixed amount of memory used. So easy “save to file” style serialization of the game state.

Anyway, that’s the tech for the day. I definitely recommend component systems, it makes it SO EASY to try new things with your game, and be able to tweak them until they work “just right”.

-Phil

P.S. If you’re looking for the code on how to do this, it’s all in this post. It really can be THAT SIMPLE 🙂

5 Responses to “Dynamite Jack: Component Object model”

  1. Hume Says:

    This is like an Entity System, but with a single component.

    Obviously it’s extremely fast, because there’s no framework looking up components every frame — it’s all there in the single struct, like you said.

    I thought ES was simple, but this takes the cake. This is awesome.

  2. philhassey Says:

    Yeah .. I really like it for quick and easy. I’m sure it wouldn’t so well for a huge game with 100’s of Components .. but for a game with just a few dozen, it worked fine 🙂

  3. Martoon Says:

    I like this, but how do you deal with a component that has more complex data (e.g., lists, etc.)? I feel like I’d inevitably end up with at least a couple pointers/references in Entity that need to be managed.

  4. philhassey Says:

    Yeah, obviously this won’t work for ALL setups. It did for my game. The main point of Gareth’s talk (as I understood it) is that the concepts of Component Object stuff are really important — but how you implement them is a matter of “as simple as possible for your situation” .. In my situation it was VERY SIMPLE 🙂 And it gave me a ton of advantages because I was able to use the power of C-O without the complexity of a relational database.

  5. Marcus Says:

    COP is especially helpful for 100s or 1000s of components (or object instances) to process, since you can keep data and processing logic separated, not overloading your real in-game or in-application instances with unnecessary functionality and data fragments, they do not need.

    After ditching things like COP (CORBA anyone?) for years, it is fun to see that the industry seems to find its way back to such nifty patterns.

    Another big advantage for COP is to plug in or out processors and data structures without actually having to care too much about side effects on other parts (in contrast to simple OO, where mixing data and functionality happens often enough, leading to bloated objects that only need x% of their functionality).