# Game Engine :: Entity Component Design - Handling Input

This topic is 1416 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi,

first of all: great site!

I am currently creating a game engine for educational purposes.

ECS Design Pattern

The first design pattern I've included is the Entity/Component/System pattern. Therefore I've got a base SINGLETON class called cEngine, which contains all systems(PhysicsSystem, GraphicsSystem, etc.) so it can update them on each frame.

void cEngine::Run()
{
while( m_Run )
{
m_Timer.Update();
for(int i = 0; i < m_Systems.size(); ++i)
m_Systems.at(i)->Update();
//NOTE: I will add a SystemManager to update them in the proper order
}
}

Also, I can create new entities(actually just IDs) and add different components(position, velocity, renderable, ...), which then get saved in the right system. So for example, the position and the velocity components will be saved in the physics system, as this one is responsible for modifying those values. Other systems, however, may have a pointer to those components, because they may need those values(the graphic system for example needs the positional information, but won't modify it).

State Design Pattern

The second design pattern I use is a state system:

class iState
{
virtual void Init() {}
virtual void Quit() {}
virtual void Update() {}
virtual void UpdatePause() {}
virtual void Obscuring() {} //call when another state gets pushed
virtual void Revealed() {} //call when upper state gets poped
private:
bool m_isActive; //true, when it is at the top of the state stack
};

The user will be able to create customable states(overwrite the virtual functions), which then get pushed onto the StateStack. Those functions will be called properly for every state by the StateManager class.

class cStateManager
{
void Init();
void Update();
void Quit();

void PushState( iState* state );
void PopState();
void ChangeState( iState* state );
private:
std::vector<iState*> m_stateStack;
};

Questions

1. First of all: Is this the right choice? In my opinion this design is pretty good, as it is easy for the user AND it SHOULD have good performance. However, I appreciate suggestions!

2. My second question is related to Input Handling. My design would've been a SINGLETON Input class.

class cInput
{
void Update();

bool isKeyDown(int key);
bool isKeyUp()int key);

private:
//...
}

Once again, the engine class would Update() this class every frame, so it would always have the right key information. The huge benefit by not handling this class as a system, but as a segregated singleton class is, that the user simply can create a new state, create some entities in it, and easily handle input in the virtual Update() function of that state. E.g. something like this:

//overwriting virtual state functions
void Init(){
}

void Update(){

//simple input handling
if(cInput->IsKeyDown(KEY_W)){
//do something...
}

//do something
}
}

As I've already said, in my opinion this "hybrid" design, which does not see the Input as another ECS system, but as a "independent" class is better and much more comfortable for the user than a "input component". However, I haven't seen this pattern on the internet, which makes me a little bit insecure. Did I miss one huge benefit of an input component? Or a huge disadvantage with this approach?

I would really appreciate any answers, as this bothers me for a few days now. Thanks!

Edited by Tomsen1410

##### Share on other sites
Thank you for this great reply L. Spiro and phil_t!

I still have some questions, but first I want to make something clear:

I don’t get what you mean.
Using a singleton implies “only one” (and, again, singletons also imply incorrect design).
States should inherit from cState and yes inside their Update() method they can handle/distribute input as they please (though usually a common distribution class would be utilized to avoid rewriting code in each state), but that has nothing to do with singletons/globals.
When the user provides his or her own new states for a game, he or she must also inherit from cStateFactory and override cStateFactory::CreateState( u32 _u32Id ), utilizing the factory pattern to create regular instances (not global/singleton instances) of custom states that will be handed over to the state manager (which is a regular instance owned by cGame (or whatever, but there are no globals/singletons)).
I think you misunderstood me. I've never wanted states to be singletons. As you already said that would be just stupid^^
I meant that the singleton design for the INPUT class would be great, because then the user can get (and process) input information really easily inside of a state INSTANCE simply with Input->IsKeyUp(key) and thats it. Nevertheless, after reading your post, I now realize how much better your approach is.

Questions:

1.) So, you stated that the cTimer should have a virtual time value and an actual time value. I don't exactly know what a virtual timer is, but I guess it is similar to the actual timer, but in addition you can "manipulate" it(e.g. stop updating it).
Now to my question: Wouldn't it be better just to ignore the states, which aren't on top of the stack rather than processing them with the deltaTime value zero? Then you would save processing time or did I get the whole virtual-timer-thing wrong?

2.) What exactly do you mean with using a state of stack internally?

3.) Why is UpdatePaused() a bad approach? Maybe the user would like to process some other stuff(not the stuff in the original Update() function) when the state is not on the top of the stack?

4.) Why exactly are the logical updates only processed 30-40 times per second? Is this still true when the game runs at 60 fps? Then those "extra" frames wouldn't make much sense or do I miss something again?
Edited by Tomsen1410

##### Share on other sites

Now to my question: Wouldn't it be better just to ignore the states, which aren't on top of the stack rather than processing them with the deltaTime value zero? Then you would save processing time or did I get the whole virtual-timer-thing wrong?

No. Just because they are paused it doesn’t mean there is no reason to run updates and render. What if you need the results of the bottom state to display the pause menu like in Conker’s Bad Fur Day?
As I said, if the state doesn’t update when it is not on top, iState::Interruptable() returns true.

What exactly do you mean with using a state of stack internally?

A stack of states. The same thing you have.

Why is UpdatePaused() a bad approach? Maybe the user would like to process some other stuff(not the stuff in the original Update() function) when the state is not on the top of the stack?

There will always be copy/pasted or otherwise rewritten code.
A state can be update in exactly 1 location. Never more. If they want to do something else for pausing they can simply branch inside the Update() call.

Why exactly are the logical updates only processed 30-40 times per second?

Is this still true when the game runs at 60 fps?

Yes.

Then those "extra" frames wouldn't make much sense or do I miss something again?

Fixed-Time-Step Implementation

L. Spiro

##### Share on other sites

I have some notes related back to the OP:

Also, I can create new entities(actually just IDs) and add different components(position, velocity, renderable, ...), which then get saved in the right system. So for example, the position and the velocity components will be saved in the physics system, as this one is responsible for modifying those values. Other systems, however, may have a pointer to those components, because they may need those values(the graphic system for example needs the positional information, but won't modify it).

I don't know exactly the matter of your game, but I advice to manage object placement separate:

a) Not all objects are dynamic;

b) not all dynamic objects are physics controlled (in fact, usually the animation system drives objects more often than physics does; although constraints like parenting may do);

c) there is a need for spatially relation checks in many sub-systems: collision detection, proximity detection, perhaps sensing, ... all of them not interested in physics but just the placement.

In summary, I think these are reasons to have a sub-system that deals especially with placement and spatial relations, and that also physics is just a client of it.

1. First of all: Is this the right choice? In my opinion this design is pretty good, as it is easy for the user AND it SHOULD have good performance. However, I appreciate suggestions!

Both, ECS with sub-systems and game states as objects, are high level architectural decisions. They alone tell nothing about performance. Especially game states as such are called once or so per frame. Hardly a bottleneck. The real meaning comes with the solutions of the low level problems: How and how often are relations between components resolved? Are data of components stored in one or possibly more batches (SoA), and is consecutive processing possible? Things like those.

Nevertheless: IMHO using an ECS is a Good ThingTM, and providing objectized game states (if made correctly), too.

2. My second question is related to Input Handling. My design would've been a SINGLETON Input class.

As L. Spiro already has answered: In the general case your sub-systems need to be able to look not at the current state but the history as well.

... The huge benefit by not handling this class as a system, but as a segregated singleton class is, that the user simply can create a new state, create some entities in it, and easily handle input in the virtual Update() function of that state.

...

As I've already said, in my opinion this "hybrid" design, which does not see the Input as another ECS system, but as a "independent" class is better and much more comfortable for the user than a "input component".

Look at ECS as a tool so solve a specific kind of problem. Don't try to enforce it on every part of the game, just because it is there anyway. ECS is for game objects. Terrain, for example, doesn't fit very well. And input is much more away from game objects than terrain is.

However, ECS is the usage of a general concept especially for game objects. The general concept is "compositing" (besides "inheritance"). There is no reason to use compositing not also in other environments than game objects.

Coming back to input as components: After input is collected, timestamped, unified, and provided to the game loop, some sub-systems need to deal with it. When speaking of components as input processes, one usually mean something like "CharacterController". Such components are meaningful w.r.t. detecting input situations and mapping detected ones to abstract input, e.g. in the form of commands which are to be processed further by animation / physics or whatever. For example, the input situation "key W hold down" may yield in the command "forward move". This may seem to be overkill at the moment, but it has several advantages:
a) Different input situations can yield in the same command (keyword "alternative input");
b) it allows for customized input configurations;
c) it allows game objects to be controlled by other sources; e.g. the PC by a controller and an NPC by AI, and both sources send the same commands.

##### Share on other sites

Thank you for your replies! Sorry I couldn't answer earlier but I didn't have much time.

Anyway, I've got a question relating @haegarr 's post:

The InputSystem gets the raw input data. The Controller components then map this data to "events" such as MoveForward, Attack, etc...

Now, how should those events get handled? Maybe the user would like to tell the PhysicsSystem to add a value to the entitiys position when the MoveForward event gets created. But maybe he would also like to create a new entity in the current state.

I'm a little bit confused, as I don't know if the events should get processed by the systems only or if the user should also be able to process them in the states Update() function...or maybe this is a completely wrong approach.

##### Share on other sites
The InputSystem gets the raw input data. The Controller components then map this data to "events" such as MoveForward, Attack, etc...
Now, how should those events get handled? Maybe the user would like to tell the PhysicsSystem to add a value to the entitiys position when the MoveForward event gets created. But maybe he would also like to create a new entity in the current state.
I'm a little bit confused, as I don't know if the events should get processed by the systems only or if the user should also be able to process them in the states Update() function...or maybe this is a completely wrong approach.

The player announces her/his desire by generating the appropriate input situation with the given input devices. The controller investigates the current input situation accordingly to the input configuration, and detects the said desire. The controller then generates the belonging command. The command expresses still a desire, although translated from an input situation into a behavior.

How to process the behavior depends on many details. Let's use the example of "walk forward" and assume a skeleton based avatar, and look at one possible solution:

The Motion sub-system keeps two float variables for the player's avatar, namely "forward" and "sideways". The former variable defines a speed for forward (if greater than 0) or backward (if lesser than 0) movement, and standing if zero. The latter variable defines how much the movement path is bend to the right (if greater than 0) or to the left (if lesser than 0), or whether it is straight (if 0). The motion system gets / fetches the "walk forward" command and hence increases the "forward" variable from its current 0 up to 3 (using meters per second) within the next 1 second. For this we assume that the "walk forward" command is maintained longer than those second, simply because the input situation is hold.

The animation sub-system controls the skeleton of the player's avatar. It is able to blend animations. It uses the "forward" variable to blend between the animations "standing", "walking forward", "running forward", and "walking backwards". During the second in which the "forward" variable increases from 0 to 3, the initially valid animation "standing" is blended with "walking forward", so that later on when "forward" reached 3 the animation "standing" is weighted with 0 and "walking forward" with 100%.

The animation has tracks not only to define the pose of the skeleton, but also to alter the placement of the skeleton in the world. With each step in time elapsed when those animation track is advanced, the player's avatar is hence moved forward.

Edited by haegarr

##### Share on other sites

Thanks.

However, this didn't answer my question entirely.

I am still confused because of the game states. As I wrote in my first post I've implemented states, which have the following interface:

class iState{
...
void Init() = 0;
void Update() = 0;
void Quit() = 0;
...
};


Now I've got two questions:

1.) What exactly should be in the Update() function of a state?

As I already have systems that manage the "technical" side of the game, I thought of states as a "container" for the game logic. Therefore the user checks if the player did lose, win, gets to the next level etc. in a states Update() function and handles those situations properly (maybe creating new Entities and so on).

2.) The second question is related to the first one and may be irrelevant, if the above approach with the states is wrong. How should I handle events created by the controller components?

I know that you've already answered this question, but what if the user doesn't want an event to be processed by a system, but rather by a state. Lets say the controller generates an event "AddEnemies" when pressing down a specific key. Well, this event has to be processed in the current states Update() function, because new entities have to be created. This has to happen in a state, as this is part of the game logic.

Edited by Tomsen1410

##### Share on other sites

It seems me that your understanding of some of the terms used differs from my understanding...

1.) Usually what is called the player controller, or controller for short as used in posts above, controls the player's avatar. This purpose does not allow for adding entities to the world, simply because that action doesn't count to "controlling the avatar".

It is important to restrict the responsibility of classes to a single purpose, not only in this case but in general!

However, it is no problem to have more than one object that investigates the input. For example, the runtime system may investigate it to detect the "goto menu" input situation, and the player controller investigates it to detect avatar controlling input situations.

2.) Detecting occurrences that cause a new entity to spawn is usually integrated into the level. E.g. the player's avatar enters a zone, pushes a button, or does anything else that causes a script to be executed (be it directly of by a fired in-game event). The elements needed to interact accordingly are all part of the level, and hence also the spawning should be.

3.) Usually what is called the game state system controls the overall state of the game as an application. It transitions between states like "startup screen", "highscore", "menu", "settings", "gameplay", and what not. It is possible to have an own state for each game level, i.e. "gameplay level 1", "gameplay level 2", and so on, but that would make the state machine significantly more complex. If you think of the state "gameplay" then the game loop can be understood as the body of the state's update() function, or at least it is triggered from therein, because the game advances if and only if the current state is "gameplay" and it pauses if it is "game menu".

So, you're right if you feel that game states should not be directly responsible for e.g. game object creation.

4.) If you want to have a state "level loading", entered from "gameplay" and returning to "gameplay", then the transition to "level loading" should be caused by the level scripting. This script can (and perhaps should) be called at the beginning of the game loop to allow for a continuous checking. Although it can be understood as an extension to he "gameplay" game state, the script itself (i.e. the actual condition) should be part of the level.

5.) If you want a game state to investigate the input, e.g. the state "gameplay" to detect the invocation of the game menu, then do so. It's okay IMHO.

1. 1
2. 2
Rutin
22
3. 3
4. 4
JoeJ
16
5. 5

• 14
• 30
• 13
• 11
• 11
• ### Forum Statistics

• Total Topics
631776
• Total Posts
3002299
×