Hacker News new | past | comments | ask | show | jobs | submit login
Entity/Component Game Design: A Primer (2011) (piemaster.net)
37 points by 3131s on Apr 1, 2017 | hide | past | web | favorite | 17 comments

If you want to successfully build a game, I recommend staying away from entity/component or any other overcomplex system ... until such time as you are an expert game programmer and know that's what you really want (such a time is likely never to come, for one reason or the other).

I have worked on games and engines using several different systems, and the only ones I ever enjoyed treat entities as plain regular structs that you operate on with procedures.

The games I have shipped all treat entities this way. And I never thought "I wish I had made the entity system more complex". The top N problems on our list, where N > 10, are always about graphics drivers or APIs.

Entities are hard enough when they are just structs. Don't insist on making them harder, or you are likely to shoot yourself in the foot when it comes to performance issues, later.

Have you written about this in more detail Jon? I'd love to read about it.

I'm not sure if there's an explicit definition somewhere, but i think an ECS could be as simple as an entity struct that contains an (optional) physics struct, that is then operated on by some physics module.

What about entities that need specialized members?

e.g an "isOpen" member might make sense for a "door" entity, but it hardly makes sense for a "bullet" entity.

My understanding is that Quake2 "solves" this issue by making a big structure from the union of all specialized members (see: https://github.com/id-Software/Quake-2/blob/master/game/g_lo... ).

Although Quake2 certainly is industry-proven, it doesn't feel right for every specialized entity behaviour function to depend on members needed by other specialized entity behaviour functions.

The way I do it, each entity has one struct. So a Bullet is one strict and a Door is one struct. They both share common base members that all entities share.

But this is all that is really necessary. Once you start getting into components, you add a lot of complexity (even if the pitch is that it's "simple").


I'm not fully convinced by components either, I don't like the idea of the bullet behaviour code having to check if "this entity has 'propeller' and 'rigid_body' components", as if the bullet behaviour code had to re-discover what a bullet was made of (BTW, this feels like a re-implementation of coarse-grained dynamic duck-typing for static languages).

This problem is less visible when the game logic is written in Lua, where dynamic duck-typing is the rule. I do write my game logic in C++/D, though, and the problem is perfectly visible.

The way you describe how you would do it raises a few questions ; because now it seems you can't process entities in a systematic/opaque way.

This implies that, say, the renderer has to loop over bullets, then to loop over doors, and so on. Each time a new entity type is added, this part of the code has to be modified, even though most entities might share the drawing code (e.g mesh).

This sequence of loops appears in many places, like collision checking, game logic update, save/load, etc. and all of them have to be updated when a new entity type is added.

Something in my understanding must be wrong, because the way you do it obviously works ; maybe the issues I just described isn't so problematic in practise?

No, because they share a base Entity class.


I do think it is a useful exercise though to go through your entities and see if these various "components" or attributes of one entity make sense with another entity. Like, if you have a RTS with some resources and units, which of the units' attributes could apply to a resource? What if a resource could attack? Or if it could move (e.g. deer in AoE)? Or maybe it can be destroyed and explodes doing damage with a large blast radius. I think as a practice this approach generates a lot of creative ideas and leaves an opening for making these changes late into the process of programming a game.

It's a problem, but I'm not sure it's a big enough problem to seek out an alternative architecture altogether.

Bullets probably would be simple structs in a shooty game, not full blown entities.

The next step beyond that simple approach is to store the components outside the entity. E.g. using SoA that Jon's new language has support for.

In my game (http://moonman.io) i use an approach similar to that in the bitsquid engine, with static polymorphism and crtp and other nonsense. It works but i admit is probably overkill.

> Bullets probably would be simple structs in a shooty game, not full blown entities.

Why not?

You still need to render bullets, to load/save them to disk, to synchronize them over a network ; some of them move by themselves, they physically interact with the rest of the world, play sounds, and have animations. And actually, many other entities also inflict damage on collision (spikes, forcefields ...).

So from the point of view of your game low-level internals, there's nothing very specific about bullets.

BTW, the same applies with powerups, doors, monsters, spikes, moving platforms, ... But some bullets might have a locked target, some powerups might disappear after a while, some doors might need a key to be open ... these behaviours are typically not shared between game object types ; I might be wrong, but having a new component/array for each of them also seems overkill.

> The next step beyond that simple approach is to store the components outside the entity. E.g. using SoA that Jon's new language has support for.

For one second I thought you were talking about "service-oriented architecture" :-)

You could definitely make them full entities, it would depend on your use case. If you're making a bullet hell shooter then maybe bullets need to be handled as a special case. Either way best not to get caught up in ideology or finding a perfect architecture, just do what works for you and your game.

I've written an entity/component "system", but it's mostly just a macro that generates structs and some useful functions on them :)

Basically, I started out just writing structs, then realized I was writing a lot of boilerplate, and now I can specify components like this, and use a custom derive to generate the actual structs and helper functions:

    pub enum Component {
        Position { x: f64, y: f64, z: f64 },
        Direction { x: f64, y: f64, z: f64 },
        Velocity { x: f64, y: f64, z: f64 },

There is this myth about the correct way in which one should code a game, entity/component is just the current fad of the decade, previously it was OOP.

I think it's more than a mere fad, but like OOP, it does have the potential for a cult to build around it.

The entity/component pattern is little more than preferring to decouple data from logic, and avoiding dependency trees. That's not particularly esoteric or irrational.

A post on the same topic that hn liked: https://unlikekinds.com/t/game-components

(I wrote it)

This article is mostly a list of ways not to do entity/component- the sequel (linked at the bottom of the post: http://piemaster.net/2011/07/entity-component-artemis/) actually talks about how to do it.

Simple bags of data and the functions that act on them. That's a message I can get behind.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact