2. Respond to input immediately. Generally what that means is you should have a linear sequence of events that is something like this :
Poll input Do actions triggered by input (eg. fire bullets) Do time evolution of player-action objects (eg. move bullets) Do environment responses (eg. did bullets hit monsters?) Render frame(* see later)
3. On a PC you have to deal with the issue of losing focus, or pausing and resuming. This is pretty easy to get correct if you obeyed #1 - read all your input in one spot, it just zeros the input state while you are out of focus. The best way to resume is when you regain focus you immediately query all your input channels to wipe any "new key down" flags, but just discard all the results. I find a lot of badly written apps that either lose the first real key press, or incorrectly respond to previous app's keys when they didn't have focus.
( For example I have keys like ctrl-alt-q that toggle focus around for me, and badly written apps will respond to that "q" as if it were for them, because they just ask for the global "new key down" state and they see a Q that wasn't there the last time they checked. )
4. Use a remapping/abstraction layer. Don't put actual physical button/keys all around your app. Even if you are sure that you don't want to provide remapping, do it anyway, because it's useful for you as a developer. That is, in your player shooting code don't write
if ( NewButtonDown(X) ) ...instead write
if ( NewButtonDown(BUTTON_SHOOT) ) ...and have a layer that remaps BUTTON_SHOOT to a physical key. The remap can also do things like taps vs holds, combos, sequences, etc. so all that is hidden from the higher level and you are free to easily change it at a later date.
This is obvious for real games, but it's true even for test apps, because you can use the remapping layer to log your key operations and provide help and such.
(*) extra note on frame order processing.
I believe there are two okay frame sequences and I'm not sure there's a strong argument in one way or the other :
Method 1 : Time evolve all non-player game objects Prepare draw buffers for non-player game objects Get input Player responds to input Player-actions interact with world Prepare draw buffers for player & stuff just made Kick render buffers Method 2 : Get input Player responds to input Player-actions interact with world Time evolve all non-player game objects Prepare draw buffers for player & stuff just made Prepare draw buffers for non-player game objects Kick render buffersThe advantage of Method 1 is that the time between "get input" and "kick render" is absolutely minimized (it's reduced by the amount of time that it takes you to process the non-player world), so if you press a button that makes an explosion, you see it as soon as possible. The disadvantage is that the monsters you are shooting have moved before you do input. But, there's actually a bunch of latency between "kick render" and getting to your eye anyway, so the monsters are *always* ahead of where you think they are, so I think Method 1 is preferrable. Another disadvantage of Method 1 is that the monsters essentially "get the jump on you" eg. if they are swinging a club at you, they get to do that before your "block" button reaction is processed. This could be fixed by doing something like :
Method 3 : Time evolve all non-player game objects (except interactions with player) Prepare draw buffers for non-player game objects Get input Player responds to input Player-actions interact with world Non-player objects interact with player Prepare draw buffers for player & stuff just made Kick render buffersthis is very intentionally not "fair" between the player and the rest of the world, we want the player to basically win the initiative roll all the time.
Some game devs have this silly idea that all the physics needs to be time-evolved in one atomic step which is absurd. You can of course time evolve all the non-player stuff first to get that done with, and then evolve the player next.