I've come to the conclusion that a crucial step for input is abstracting/having a layer between the input and actions I forgot where I saw this, but I remember seeing someone who said "[...] shouldn't care that SPACE was pressed it cares that JUMP was pressed" anyways with that in mind how do I actually organize input code? I'm working on a game that uses earth and I want to be able to rotate and zoom in/out there is also gonna be a player object that has actions for them so would each object handle its own input? Or would I make a separate object that is responsible for handling input for a specific object? (i.e Planet and PlanetInput) it seems overkill to make a whole other class for potentially 2 functions, but I suppose it follows the single responsibility principle.
How do you handle input for various objects?
Depends on the game style, and the tools you are using.
Often tools give you a mapping system and a way for players to reassign key and button events. They can have mouse and keyboard assignments, and controller button mapping for each controller or gamepad.
Eventually the events are processed and dispatched, often during a regular update step, possibly every frame or every simulation cycle. Rarely these days but also possibly for some it is dispatched at the time an event is received by the system even if it is different from the regular processing flow.
Also there is often a hierarchy or structure with a chain of responsibilities, first the system can process it and decide to pass it along, then maybe your ui system, then another system and another, maybe eventually you send the event to the thing controlling the character, maybe to the thing in the crosshairs, maybe to the thing a character is standing on, whatever you need for the game.
There is no universal answer.
Konjointed said:
I've come to the conclusion that a crucial step for input is abstracting/having a layer between the input and actions I forgot where I saw this, but I remember seeing someone who said
There are very few absolutes in software, this depends on how much flexibility you want.
If you only have “space” to “jump”, and you have no intention to ever change that, then “space” is the same as “jump” so there is no need to create a second form of “jump”.
On the other hand, if there are several ways to “jump”, or the key for “jump” can be changed by the user, then indeed “space” and “jump” are different things, and you need to convert from key input to action input.
That is, your game accepts actions that you do, like shoot, run, jump, buy, etc. You watch inputs from the keyboard or mouse etc, and when an input happens, you check if they are attached to an action, and if so, you call the action of the game.
Even if you do want to make a distinction between actions and key input at this time (ie you could also add that further down the development), as long as you don't have a working game yet, you can take a shortcut for now, and simply hard-code the mapping by directly calling eg jump action from detecting space key input. In that way, you do make a distinction between input and actions already, but you don't spend time on building a way to configure how keys are converted to actions at this time.
@Konjointed I believe you're thinking of the command pattern. Instead of using a switch statement of keydown options and their actions, you could send commands (messages) to the object. So when I press ‘Space’, the InputController object sends a ‘Jump’ command/message to the player. Then in Player::Update(), the player gets the message, and updates velocity accordingly (if not already jumping).
I've used this because it makes things simple. For example if I fire a shotgun in my game, I send all enemies a message that the player fired a shotgun. That's it. In Enemy::Update(), the enemy object gets the message (stored in a queue or vector) and decides what to do with that information. If they're far from the player, do nothing (like they didn't hear it). If they're an aggressive enemy, move towards the player. If not too aggressive, just stand guard, but face in the direction of the player. If a cowardly or injured enemy, move away from the player. All the actions are handled by having the enemy switch to a different finite state.
I agree with Alberth, if you're currently experimenting and trying different things, it's not important to implement it right away. But file it away for later.
Konjointed said:
with that in mind how do I actually organize input code?
A simple way is to have an object which stores the input state. The object is updated when processing related messages form OS, and at this point you can also consider configurable input remapping players do in options menu.
After that you pass the input object to the playable object the player currently controls (assuming you implement input processing in such playable objects). It may be the character, then a car, or a horse, etc.
The input object can then typically answer if the jump button is currently down, was pressed, or was released since the last update.
Basically the input object serves as abstraction of both OS and button remapping.
It's usually simple if you design it only for one specific game, but becomes more complex if you want to use it for any game.