Game State Machine with Component Based Entity Design

Started by
9 comments, last by Gasimzada 10 years, 4 months ago

I have implemented game state machine (Main Menu, Play game etc) into my engine. I have some questions regarding the relation of the states to the entity design that I have:

  1. There are 3 base interfaces: Entities that hold components, Components that holds and manipulate data, and systems that all the hard work
  2. Components can communicate between each other through messaging or straight referencing. I use referencing for inner operations, where dependencies are strict; while events are used for decorative purposes. One example would be sending event walk, which will play walk sound and walk animation; if you completely disable both animation and sound, the system will still work properly but uglier (hence the name "decorative").
  3. Systems have direct access for particular components (like PhysicsSystem holds PhysicsComponents but can also manipulate PositionComponent (if you have one)), components can sometimes talk to systems through messaging but it should be very rare. I haven't implemented it yet, but I am thinking of creating an event queue and then go though all the events in the update/render. Additionally, systems don't communicate with each other directly. And systems should be stored in a certain order, therefore all the systems have a unique ids that are in ascending order.

In my current draft implementation, each state holds a list of systems that need to be updated,rendered,or used for input. For example:

The "gameplay" state holds Physics System, Graphics System, and Input System, while the "main main" state holds GUISystem and InputSystem. The input systems do not hold the same address. They are created separately and hold the components they need for each other. This way when I call update, only the needed systems get updated. So far, everything seems to be making sense...

But I have one problem with connecting these states to components. I need that for one reason: Sometimes components can talk to the systems. For instance, the components get added to their corresponding systems during entity initialization (the initialize function gets called. And from there I can write whatever I want in that function).

When I had an engine with only one system manager, it was easy to handle systems. Currently, the active state is stored in the entities the moment an entity gets created. But what if the state gets changed when there was an entity getting created? The Entity will be added to a system in a wrong state or if the state doesn't have the system the game will crash. Also, wouldn't it be inefficient in terms of memory to store all the resources of the inactive states?

Design wise this system makes sense to me but efficiency-wise i don't know. What do you think? Is this approach even good? I know there is usually no universally accepted way of doing this but I don't want this system to be horribly bad. So, please criticize it as much as you can.

Advertisement

i believe in most designs, the CE system is usually only active during the "game is running" state, and other code and variables are used for other states.

generally speaking though, an update to a system should be allowed to complete before the code is allowed to lose focus.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

that makes. I was thinking of making everything an entity, even the gui but now I realized what's the point.

There's no reason your GUI can't also be entities, if it makes sense (if it lets you re-use rendering and input handling code for example).


But what if the state gets changed when there was an entity getting created? The Entity will be added to a system in a wrong state or if the state doesn't have the system the game will crash.

I actually don't understand the problem you're having. Why would your game crash? It sounds like there is some other flaw in your architecture that has nothing to do with your GUI (e.g. even if you move your GUI completely outside the entity/component system).


But I have one problem with connecting these states to components. I need that for one reason: Sometimes components can talk to the systems. For instance, the components get added to their corresponding systems during entity initialization (the initialize function gets called. And from there I can write whatever I want in that function).

Why do you mean "components can talk to the systems"? Components shouldn't know anything about the systems. Why would they need to?

And your above quote suggests that you're subclassing Entity and writing custom initialization code for each. Is that really true? Are entities responsible for adding themselves to various systems? (that would not be a good design).

Can you explain your design a bit better?


I actually don't understand the problem you're having. Why would your game crash? It sounds like there is some other flaw in your architecture that has nothing to do with your GUI (e.g. even if you move your GUI completely outside the entity/component system).

It wasn't really a problem but more of a theoretical question. But I sometimes confuse the fact that I am working in a sequential environment. Now I know even if I add multithreading support, I would keep the entity creation (not initialization; read below) and state changes in one loop while the subsystems in another loop. Or lock everything during state change. Its an idea for the future as I am not implementing any multithreading until I have something thats stable.


Why do you mean "components can talk to the systems"? Components shouldn't know anything about the systems. Why would they need to?

99% of the time I do that for initialization. The reason for that is that, the component creation does not rely on the system. I just don't like that idea. This way the components are created through the entity factory but they don't get initialized. In order to initialize them i need to call "entity->initialize()" which goes through all the stored components and calls the "initialize" function of each of them. A typical component initialize function looks like this:


void InputComponent::initialize() {
   getCurrentState()->getSystem<InputSystem>()->addComponent(this);
}

When an entity is initialized, the systems will start doing their jobs on them. I think of the above function as this shared space between component and system that is used only once. This helps me with a lot of things with one being cloning, so I don't use objects the moment I create them - for example I can move the entity to a position and create it there.


And your above quote suggests that you're subclassing Entity and writing custom initialization code for each. Is that really true?

I am not subclassing entity but each component has its own initialization and cloning code, whereas I also provide a generic solution with one function call.

When it comes to the question of this topic, there is doubt about the way the state machine should be working. I have implemented a very generic and broad state machine where each state machine can have their own systems etc. So far it works great and makes sense but I don't have any predictions for the long run.


A typical component initialize function looks like this:
void InputComponent::initialize() {
getCurrentState()->getSystem<InputSystem>()->addComponent(this);
}
When an entity is initialized, the systems will start doing their jobs on them. I think of the above function as this shared space between component and system that is used only once. This helps me with a lot of things with one being cloning, so I don't use objects the moment I create them - for example I can move the entity to a position and create it there.

So, the question you started this thread off with alludes to why you shouldn't be doing it this way. It adds an unnecessary dependency, but moreover: how does InputComponent know which InputSystem to add itself to? It looks like it depends on some global state, which is not a robust solution, and is probably what leads to the problems you're wondering about.

There's no reason for this code to exist in the component. You can pull it out and put it elsewhere (e.g. an "entity manager" class). It can inspect which components are in the entity and add it to the right systems. Even better: systems could declare which components they are interested in, so when adding/removing systems during development you won't need to update code in either the components or the "entity manager".

Adding/removing components from an entity should also go through this "entity manager" so it can remove/add the entity to the various systems. The "entity manager" would be tied to a state, so there is no ambiguity at all (in fact, maybe your "state" and "entity manager" classes are one and the same).

Putting the code in the entity manager also allows you to be smart about when you add/remove components to/from the systems (e.g. at the end of the update cycle).

If you want to leave it pretty much as you have now, the very least you could do is pass the current state as a parameter into the initialize() function. That will at least remove any ambiguity (and of course, any code anywhere that adds/removes components to/from systems needs to know the proper state too).


So, the question you started this thread off with alludes to why you shouldn't be doing it this way. It adds an unnecessary dependency, but moreover: how does InputComponent know which InputSystem to add itself to? It looks like it depends on some global state, which is not a robust solution, and is probably what leads to the problems you're wondering about.

It takes the state from the entity, the entity's state gets assigned during entitiyManager that stores which state is was created.


There's no reason for this code to exist in the component. You can pull it out and put it elsewhere (e.g. an "entity manager" class). It can inspect which components are in the entity and add it to the right systems. Even better: systems could declare which components they are interested in, so when adding/removing systems during development you won't need to update code in either the components or the "entity manager".

I understood how entityManager can add the components to their right systems but can you please give more details for the latter. I am going to start with initialization through the entity Manager then it would be easier for me to port it to the systems. And one more question, how would you deal with the cloning? Cloning copies everything from an existing entity to a newly created instance. If i remove initialize function, I would only be able to do modify the object after it is added to the scene and is used; or at least I don't see how i should be able to do that. Can you give me a hint on how to deal with this problem?

The state should not be the owner of the subsystem. That's the problem. The subsystems are services that your engine provides. The state is a client that can access these systems, that doesn't mean they cease to exist after you switch from one state to another.

The "gameplay" state holds Physics System, Graphics System, and Input System, while the "main main" state holds GUISystem and InputSystem

This is an arbitrary separation. What if you want to display a physically correct exploding character in your main menu or you want to display a GUI over your game scene?

The state should not be the owner of the subsystem. That's the problem. The subsystems are services that your engine provides. The state is a client that can access these systems, that doesn't mean they cease to exist after you switch from one state to another.

That makes sense. Finally everything is starting to fall into pieces. My design right now is so overcomplicated because of my not clear understanding of the situation. Simplifying it is going to take some time but the design would be understandable eventually. Thanks!


I understood how entityManager can add the components to their right systems but can you please give more details for the latter. I am going to start with initialization through the entity Manager then it would be easier for me to port it to the systems.

If you look at the Artemis framework (https://code.google.com/p/artemis-framework/source/browse/), you'll see they have the notion of Aspect to handle this.

In my case, the constructor for my EntitySystem base class has some bitflag parameters that describe the types of components it's interested in (This of course limits me to 64 types of components, but you could do something more open ended, like an array of component types). So system implementations need to supply this to the base class. Then this information is exposed as a public property on EntitySystem, so EntityManager can just check against that.

From a quick glance, it looks like Artemis keeps all this info in the system itself, and weeds out entities as the system enumerates through all of them. In my case, entities are added/removed from the system (only by the EntityManager), so the system only needs to enumerate through the entities that apply to it.


And one more question, how would you deal with the cloning? Cloning copies everything from an existing entity to a newly created instance. If i remove initialize function, I would only be able to do modify the object after it is added to the scene and is used; or at least I don't see how i should be able to do that. Can you give me a hint on how to deal with this problem?

I'm not clear on the problem here. What modifications are you making, like position or something? So, some calling code would ask the entity manager to clone a particular entity. Then that entity would be returned to the caller, so it could ask for the components it's interested in and make the corresponding modifications. Before returning, the entity manager could add the entity to the appropriate systems (if they're robust against entities being added at any time), or delay adding the entity until the end of the update cycle (e.g. keep a "todo list" of entities to add).

This topic is closed to new replies.

Advertisement