ECS: One for All

These last two months of effort for #1GAM have ultimately ended up being a lot of basecode building, but boy I’d like to think it is going to help in the long run. I’m already looking to put out another pretty low-key game this month, but beneath the surface things are getting in shape.

One of the things I was trying to figure out this month is how to unify game pieces in a way that facilitates seamless communication and interaction. More types of components means a greater amount of systems and/or more specialized code. Though some of this is probably a given, one of the beauties of the ECS is being able to streamline common code through systems. Having to write new systems for every edge case sort of defeats the purpose in my mind.

When the solution finally came to me it seemed kind of silly I hadn’t thought of it before. What I decided to do was define a set of low-level, baseline components that would function as “output” components for commonly passed data types (numbers, booleans, etc.)

Let’s take input for instance. You have mouses, controllers, keyboards, etc. Each of these carry their own set of nuances. Now the initial idea might be to manage these from separate input classes and have getter functions for each’s respective input. But now try to hook these up to an entity. If you want an entity to be compatible with all three types of input, you might need to write three different systems, and so help someone should they try to combine different forms of input into the same control scheme. Its not impossible, but it can complicate things.

So my solution was two steps. First, all these “inputs” were not to be specialized classes: they should be entities themselves. By making them entities, we put them on the same level as our other game objects, able to use the same kind of methods to store and manipulate data. That brings us to the second step: they are then each assigned something like a common “BooleanComp” meant for output. Entities who wish to read these inputs look at these components to determine their course of action. Internally these input forms must still be handled based on what they are, but the idea was that system code could focus more on manipulating output as opposed to how it was derived in the first place.

But wait! You might be thinking that a keyboard has multiple buttons but only can have one “BooleanComp” in its component map. How does that work out? Simple: the keyboard itself is made up of multiple button entities. But how does this not muddy our output process? Well, entities still have to know what they are looking for, but in this example once they find said input, theoretically they all plug in nicely to the same code because they all share the same form of output.

Let me try to make it more concrete. Instead of this:

class KeyboardNode {key:KeyComp}
class MouseNode {click:ClickComp}
class ControllerNode {button:ButtonComp}

You get this:

class InputNode {bool:BooleanComp}

They all may take different paths to get to the same place, but it funnels input cleanly and quickly (i.e. it helps eliminate unnecessary intermediate steps) and can help keep fringe code down.

So there’s a small look into how things are going on the technical side. Hope you enjoyed it.

Posted in ECS, Game Dev

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: