• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Tomsen1410

Game Engine :: Entity Component Design - Handling Input

12 posts in this topic

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 wasKeyPressed(int key);
        bool wasKeyReleased(int key);
    
        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(){
    id = cEngine->AddEntity();
}

void Update(){
    //add some components, bla bla...

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

    if(cInput->WasKeyPressed(KEY_A)){
        //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
0

Share this post


Link to post
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
0

Share this post


Link to post
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?

To reduce overhead.
 

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
2

Share this post


Link to post
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.
2

Share this post


Link to post
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.

0

Share this post


Link to post
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
0

Share this post


Link to post
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).

I am still concerned about this though, because this doesn't seem like a neat solution.

 

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
0

Share this post


Link to post
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.

0

Share this post


Link to post
Share on other sites

I prefer to leverage game states as a means to orchestrate chunks of behavior that must coordinate with a broad range of engine subsystems.  

 

For example, you may have a cutscene/movie subsystem that knows how to play avi files and a game state is responsible for checking whether the player has watched the intro movie and if not, instructs the movie subsystem to play it; otherwise transition to the login screen.  The login state is responsible for preparing the login UI with the UI subsystem, perhaps loading the game's theme music and waiting for the user to enter their credentials.  Our entire game menu/settings system which can be invoked from the login screen, character select screen, and while in game is all driven inside the game state system by pushing that state onto the active state list.

 

Another simple example of the game state system at work is when a user transitions from one map to another.  You simply signal that you need to transition to a loading state, when you enter the loading state you know which map you need to load and so you can display an appropriate loading screen.  During the update loop of this state, perhaps various things are being performed, specific tasks completion statuses being checked and when loading has finished, you pop the state which removes the loading screen and returns the player back to the game play state.  Such a transition disables input to the controllers and perhaps other aspects.

 

As for event detection/dispatch, the observer pattern is simple and yet powerful.  Most of my subsystems expose some type of listener interface that I just implement where needed.  It's a very simple solution to implement, has minimal overhead and allows you to focus your energy in other places rather than loosing momentum designing something that is likely overkill for where you are at right now.  Then when an event is fired, the class holding the listeners simply iterates the listeners, calls some virtual method and the listener implementation fires it's logic.  :)

 

Good luck!

0

Share this post


Link to post
Share on other sites


As for event detection/dispatch, the observer pattern is simple and yet powerful.  Most of my subsystems expose some type of listener interface that I just implement where needed.  It's a very simple solution to implement, has minimal overhead and allows you to focus your energy in other places rather than loosing momentum designing something that is likely overkill for where you are at right now.  Then when an event is fired, the class holding the listeners simply iterates the listeners, calls some virtual method and the listener implementation fires it's logic.

I second this, but with an emphasize on "where needed".

 

Simultaneously I'm used to mention that a game usually runs continuously in a well ordered game loop, opposed to desktop applications. As a result, asynchronous input processing (asynchronous is meant here w.r.t. to the update() of a listening sub-system) means to memorize any relevant input changes locally, because a meaningful reaction can be made only when the own update() is called the next time. However, what "meaningful reaction" that is can also be determined inside update() only, because it is required to consider not only input but the entire state of the world, and that is valid only when the game loop calls the said update() method.

 

So question is, whether input listening is actually needed in a given use case, or whether it is even perhaps counter-productive. Patterns are fine in general, but as every tool, they have their use cases. Just "where needed"...

0

Share this post


Link to post
Share on other sites

I prefer to leverage game states as a means to orchestrate chunks of behavior that must coordinate with a broad range of engine subsystems.  
 
For example, you may have a cutscene/movie subsystem that knows how to play avi files and a game state is responsible for checking whether the player has watched the intro movie and if not, instructs the movie subsystem to play it; otherwise transition to the login screen.  The login state is responsible for preparing the login UI with the UI subsystem, perhaps loading the game's theme music and waiting for the user to enter their credentials.  Our entire game menu/settings system which can be invoked from the login screen, character select screen, and while in game is all driven inside the game state system by pushing that state onto the active state list.
 
Another simple example of the game state system at work is when a user transitions from one map to another.  You simply signal that you need to transition to a loading state, when you enter the loading state you know which map you need to load and so you can display an appropriate loading screen.  During the update loop of this state, perhaps various things are being performed, specific tasks completion statuses being checked and when loading has finished, you pop the state which removes the loading screen and returns the player back to the game play state.  Such a transition disables input to the controllers and perhaps other aspects.

Basically this, although the reason I support stacks of states is to allow the lower states in the stack to maintain their current “state” while the top state interjects something on top, such as when your controller battery is about to die on a Nintendo Wii U.
Rather than going from a CGamePlayState to CLoading on top, then back to the original CGamePlayState, it’s better to go to an entirely new instance of a CGamePlayState so that you can easily release memory between stages etc. The loading screen would still be pushed on top of the CGamePlayState, but it would be at the start of a new instance rather than a singular massive multi-stage–encompassing instance.



As for event detection/dispatch, the observer pattern is simple and yet powerful.  Most of my subsystems expose some type of listener interface that I just implement where needed.  It's a very simple solution to implement, has minimal overhead and allows you to focus your energy in other places rather than loosing momentum designing something that is likely overkill for where you are at right now.  Then when an event is fired, the class holding the listeners simply iterates the listeners, calls some virtual method and the listener implementation fires it's logic.

As mentioned by haegarr, there is a place for the observer pattern, but input has to be handled at a specific time within the game loop, not just immediately as the inputs are received. Inputs are not events.
I’ve discussed this exhaustively and posted links above.


L. Spiro
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0