Sunday, June 16, 2013

A basic entity system using Haxe and NME

A while back I learned about a game development pattern called "component-entity system" (or "entity-component system" or just "entity system"). It's a brilliant architectural approach for reducing complexity in game development. When you use typical object-oriented inheritance your object graph can become more complex as you add functionality. But with an entity system you use composition, constructing entities from components and minimizing (if not completely flattening) your object graph.

An entity is like a namespace for components. In fact an entity doesn't need to be more than an identifier that associates components. Components themselves are pure data, they could be primitives or even structs, but it's convenient express them as classes. Systems are the third big aspect to this pattern. Systems look for entities with components they care about and take some action.

To make things happen in an entity system, you create a bunch of components, associate those components with entities, and then set up a bunch of systems to process the entities. It's typical to have systems for rendering, movement, input, AI, physics, and so on, and have components that are used by (and modified by) these systems such as a texture component, a location component, a player-character tag component, etc. Simply by wiring up the right set of components you can create new entities.

The best part is you can re-use functionality just about anywhere without having to worry about whether that functionality is available in one of your entity base classes. The functionality is in your systems. Just add the right component and you're good to go.

There's a universe of information out there already about entity systems. Instead of explaining them here I highly recommend you visit the Entity Systems Project. It's a great starting point for learning more about this approach.

One thing I think is really neat about entity systems is that the concept can be used outside of game development. In normal application development, web development, or enterprise development the maxim "favor composition over inheritance" is well known. The way entity systems turn inheritance on its head and make you re-think how you use objects can have a big impact. It's kind of like learning about OOP for the first time. I feel like I have a new and powerful tool under my belt, and I have found ways to re-use the knowledge in my day-to-day work.

My implementation

So, I wanted to write my own entity system. I built it using Haxe and NME. I haven't touched it in a while, and I feel like it could be a great starting point for a more complete engine, so I wanted to release it in case anyone might be able to learn from it or re-use it in their own project. There are other entity systems out there for NME, I believe, but there are some things about my implementation that I think are interesting and might be useful.

One of my big initial hang-ups with entity systems was the question of how systems know about the entities they wish to process. There are lots of options here: You could explicitly associate entities and systems, or you could have systems look for entities with a particular component attached, etc. The approach I chose was to use a filter-based system. Each time a component is added to or removed from an entity, systems are notified and they can process the entity through a series of filters to determine if they care about that entity. For example, I have a RequiredEntityFilter that indicates some set of components must exist in an entity for the system to process it, and an ExcludedEntityFilter that does the opposite. You can chain these filters, allowing you to say things like "I care about entities that have both a location component and a velocity component but do not have a player-character component", and so on.

Another issue I struggled with was how to deal with input. I created a Buffer class that provides a means of examining the set of input events that occurred during the last frame. This avoids the issue of systems having to be updated via some notification mechanism when an input event occurs. My goal was to make the systems as "pure" as possible and not use callbacks, events, or anything like that to achieve functionality. In retrospect, I think this was a little naive. It's probably better to think of the entity system as the "model" of your application, and find a way to wire the input events, which are part of the "view", to that model using some sensible mechanism. I think what I have here is a decent first pass at this but it could be improved.

There are some other little gems in there. Take a look at the code and see if it might be of use to you. I spent a lot of time working on it about a year ago and I hope it can help someone else.

No comments:

Post a Comment