Skip to main content

Entity / Component Systems

I've been writing a new game recently -- and this time, I decided to use an entity/component system. Boy, does that approach make things easier! In other games I've written, I've struggled to fit new gameplay features into the existing code base. With a entity-component based systems, it's easy to add new features:
  • Need a way to track targetable objects in your game? Add a Targetable component that advertises the unit's position, name for display in the HUD, etc.
  • Need to add some new AI behavior to a unit? Add a component! Update all the AI components once per frame and you're on your way.
  • Does your game need networking? What should you do...? Add a component containing all the info for network serialization!
  • Need to control a unit from user input? Add a joystick component that updates the unit's position component in response to user input.

Basically, any new feature can be folded into a component. The best thing about components is that they are dynamic; you can add and remove components at runtime to change the behavior of a unit. If you think of the entity as a vector, then each component is like a separate "dimension" to your entity. Additionally, each component is a lot like a table in a relational database. The actual "entity" is just the sum of its components; that is, the sum of all its entries in each relational database table. I find this design incredibly elegant.

So, how have I implemented my entity/component system? I have a Table template class, which is basically a wrapper around std::unordered_map, indexed by the entity ID. To look up a component, you simply do a "query" (to borrow from relational database terminology) using the entity's ID and look up the component. For example:

Id id = ... 
// get the entity's ID
Ptr<Table<Position>> table = db->table(); 
// get position table
Position position = table->component(id);
// do something with the position
Say you want iterate over all the targetable enemies and select the closest one. This is really easy with entity/component systems:
Id nearestTargetableEnemy(Vector myPosition) {
    auto nearestId = Id();
    auto nearestDist = std::numeric_limits::max();
    for (auto i: *db->table()) {
        auto target = i.value;
        auto id = i.key;
        auto position = db->table(id);
        auto dist = position.origin.distance(myPosition);
        if (dist < nearestDist) {
            nearestDist = dist;
            nearestId = id;
        }
    }
    return id;
}
Simple! And, this code automatically works for any entity that has a Target and Position component! Pretty cool. The possibilities are pretty much endless. Here are some more things that are easy to implement with entity/component systems:
  • Recharge/powerup stations
  • Pathfinding
  • Serialization/save game
  • Camera tracking
  • Collision detection
  • Damage/hitpoints
  • Rendering effects
Next time you write a game, give the entity/component system approach a try. It's just too much fun not to use.

Comments

  1. Many of the steps can be completed by the machines or robotics controlled by a single operator, reducing labor prices and overhead. The precision machining process can also be|may also be|can be} performed extra shortly and effectively, rising manufacturing output. The high quality indexes revealed on this work all provide a great indication of the injection molding high quality beneath the thought-about processing circumstances.

    ReplyDelete

Post a Comment

Popular posts from this blog

Lua-Style Coroutines in C++

Lua's implementation of coroutines is one of my all-time favorite features of the language. This (short) paper explains the whole reasoning behind the Lua's coroutine implementation and also a little about the history of coroutines. Sadly, coroutines are not supported out-of-the box by many modern languages, C++ included. Which brings me to the subject of this post: Lua-style coroutines in C++! For those who don't know (or were too lazy to read the paper!), Lua's coroutines support three basic operations: Create: Create a new coroutine object Resume: Run a coroutine until it yields or returns Yield: Suspend execution and return to the caller To implement these three operations, I'll use a great header file: ucontext.h. #include <vector> #include <ucontext.h> class Coroutine { public: typedef void (*Function)(void); Coroutine(Function function); void resume(); static void yield(); private: ucontext_t context_; std

Warp

So, it turns out that I didn't use Criterium for the video game competition at Stanford.  I actually met a partner and went with another concept instead -- Warp.  It's kind of like Starfox and it's inspired by Rez, one of the first PS2 games.  Explosions and missiles fire in time with the music; we used ChucK , an audio processing language, to achieve this. We also made some destructible objects using rigid bodies, and I added some particle explosion effects.  We used Lua to for enemy AI, and wrote a small TCL-like script parser that reads in data for the level layout.  The buildings in the background are procedurally generated.  We used OGRE for the graphics (this was a loose requirement of the project) and Bullet for the physics.  I had a lot of fun with this project, and I've posted a video capture below.

Password Generator for Chrome

This week, I finally got fed up with typing in/managing passwords on a billion different sites. Since things like OpenID haven't really taken off, I decided to take matters into my own hands...and write a password generator extension for Google Chrome. There are actually a ton of such apps on the Chrome web store, but I'm paranoid about security, so I wrote my own and open-sourced it. By virtue of being open source, perhaps people will trust my version a bit more. Anyway, the extension is available here , and the source code is hosted at github . May all your online transactions be secure! UPDATE: Fixed github link.