Tuesday, July 16, 2019

c++ - Input management techniques in large games


Is there a standard technique for managing input in large games. Currently, in my project, all input handling is done in the game loop, like so:


while(SDL_PollEvent(&event)){

switch(event.type){
case SDL_QUIT:
exit = 1;
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym){
case SDLK_c:
//do stuff
break;
}

break;
case SDL_MOUSEBUTTONDOWN:
switch(event.button.button){
case SDL_BUTTON_MIDDLE:
//do stuff
break;
}
}
break;
}


(I am using SDL, but I expect the main practice applies libraries and frameworks as well). For a large project this doesn't seem the best solution. I may have several objects all wanting to know what the user has pressed, so it would make more sense for those objects to handle input. However, they can't all be handling input, as after one gets an event, it will be pushed off the event buffer, so another object won't receive that input. What method is most commonly used to counteract this?



Answer



Since asked by the thread starter, I elaborate on event managers. I think this is a good way to handle input in a game.


An event manager is a global class which allows to both register callback functions to keys and to fire off those callbacks. The event manager stores registered functions in a private list grouped by their key. Each time a key gets fired, all registered callbacks are executed.


The callbacks could be std::function objects which can hold lambdas. The keys could be strings. Since the manager is global, components of your application can register to keys fired from other components.


// in character controller
// at initialization time
Events->Register("Jump", [=]{
// perform the movement

});

// in input controller
// inside the game loop
// note that I took the code structure from the question
case SDL_KEYDOWN:
switch(event.key.keysym.sym) {
case SDLK_c:
Events->Fire("Jump");
break;

}
break;

You could even extend this event manager to allow passing values as additional arguments. C++ templates are great for this. You could use such a system to, say, for a "WindowResize" event pass the new window size, so that listening components don't need to fetch it themselves. This can reduce code dependencies quite a bit.


Events->Register("LevelUp", [=](int NewLevel){ ... });

I've implemented such an event manger for my game. If you are interested, I'll post the link to the code here.


Using an event manager, you can easily broadcast input information within your application. Moreover, this allows for a nice way to let the user customize key bindings. Components listen to semantic events instead of keys directly ("PlayerJump" instead of "KeyPressedSpace"). Then you can have an input mapping component that listens for "KeyPressedSpace" and triggers whatever action the user bound to that key.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...