Game Timing, I/O and how to sort it out for a realtime game.

Started by
13 comments, last by RKillian 18 years, 3 months ago
Hello all, Firstly let me apologise if this information is covered somewhere else, I have searched on various forums etc. and come up with various stuff but would like to open a general discussion, if there are any developers out there who could give me some tips on how the pros do it I would be very grateful! My background is EE and I am used to programming in embedded environments, along with a bit of Win32, OpenGL, and various other things. Having sat down and decided to write a simple realtime 3D game (with possibly the option to make it multiplayer over TCP/IP) (WinXP/VC++6 is my dev platform with SDL and OpenGL) I am a little stuck at the first hurdle - the overall 'game loop', timing considerations (for constant game timing independent of framerate) and input gathering (mouse and keyboard). So a simple game loop might be: while(1){ DrawFrame() GetMouseAndKeyboardState() GetAccurateTime() UpdateGameWorldBasedOnTime() } Now my initial problem was getting a decent high resolution timer on Windows, (SDL only has the GetTicks() function which is in milliseconds and i believe only accurate to 10ms anyway! - no good!) After a little research it seems the QueryPerformanceCounter() functions in Win32 are the way to go. (Looks like I will have to encapsulate timing stuff and find an alternative for each platform Linux/Win/etc - bummer). Ok, so I thought great, I can base my game world on real time and all is good. Until I realised that just sampling the keyboard once every game-loop iteration is really not such a good way to do thigs. - For example on a machine that can render 25fps, the keyboard/mouse is sampled 25 times per sec, on a faster machine the sampling resolution could be e.g. 100fps/100s/sec. Obviously the guy with the faster machine has an advantage not just in framerate! So my quesion is, how do we deal with this? - What is the best way? On an embedded system I would probably have an interrupt funciton tied to key presses and buffer up the key press information with the accurate time of the press, and the game update function then has all the data it needs. What do we do on big bad multitasking OS's? Some thoughts are: 1. Set up some kind of callback thread to sample at say 100Hz, and package up the key/mouse data with time data so that the UpdateGameWorld() function can deal with key presses 'correctly'. (Remembering that callback functions are not very accurately timed either, but hopefully ~100Hz is adequate...) 2. Just ignore the problem? 3. Rely on the SDL message loop somehow, keypresses are buffered, but no accurate timing information? Am I missing something obvious here though? (I am not a games programmer -yet!) Any thoughts and insight greatly apreciated!! Perhaps I could even wite an article about it once solved..... James.
Advertisement
Yeah, locking input to your visual frame rate is bad.

Why does your game run at only 25fps? Do you limit it to that? Or are your draw methods just really slow ;-)

Have you tried using threads? A seperate graphics thread (or seperate input thread) might smooth things up.
Quote:Original post by jra1980
For example on a machine that can render 25fps, the keyboard/mouse is sampled 25 times per sec, on a faster machine the sampling resolution could be e.g. 100fps/100s/sec. Obviously the guy with the faster machine has an advantage not just in framerate!

Well, what good would it be if you sample for input more often than you redraw the screen?
Usually, the input from the player comes as a response to what you see on the screen. You see an enemy, you fire your gun. If you don't see the enemy, because the framerate is low, well, you're not going to fire your gun, and so, does it matter whether you sample input every frame, or 4 times per frame?

If you can't see what's up ahead in a racing game, then does it matter whether the game registers that you try to turn in between frames?

Just a thought. (I'm aware that locking the game logic to your framerate is often a bad idea, but I can't see the big issue with input in particular)

Quote:
Well, what good would it be if you sample for input more often than you redraw the screen?
Usually, the input from the player comes as a response to what you see on the screen. You see an enemy, you fire your gun. If you don't see the enemy, because the framerate is low, well, you're not going to fire your gun, and so, does it matter whether you sample input every frame, or 4 times per frame?


My argument against this is: Imagine that 2 players on 2 different machines (one fast one slow) are playing against each other in some FPS (First Person 3D shooter). They both are facing each other and both *at the same instant in time* fire at each other (press the fire button). Now the guy with the slower machine, with lower keyboard sampling rate, is at a disadvantage as it is more likely that the player with the faster machine will have his keyboard sampled first, and hence fire first.
Also, the human brain is amazingly good at predicting where & what is going on, even if your framerate goes a bit choppy in a game (or is low). Therefore I argue that the game world should update correctly (well, keyboard/mouse sampling should be fast enough on any machine - and the game world update take account of *when* keypresses occurred to a reaasonable accuracy.)

Quote:
Why does your game run at only 25fps? Do you limit it to that? Or are your draw methods just really slow ;-)


As mentioned I work with embedded systems mostly, 25fps on a phone is a reasonable framerate! ;-) It was really just for illustration....

As far as using seperate threads goes, well it is possible I guess, but seems possibly more complicated than necessary? I could be completely wrong here of course. It would be good to know how e.g. Quake3/Doom3 or new FPS type games sort this problem. I guess I could download the Q3 code and have a look but it would probably take a long time to figure it out....! :)

James.
Quote:
GetMouseAndKeyboardState()...


Actually it is not that for every interaction in the loop you have to check the keyboard & mouse device states; what you have to do is to set up two events handlers (for the keyborad for example) One event is triggered when any key is pressed and it will return what key was pressed. the other event is triggered when any key is released and it will return what key was released.

You have to use a boolean variable for every key you are interested to use in your game, In the key_pressed event you make true the variable and in the key_released event you make false the variable.

So in your loop game what you are checking is if the keys variables are currently TRue or False to know the current state of those keys. Note that the key_pressed event is only called when the user press the key the first time, if he keeps holding the key the event IS NOT CALLED AGAIN; until he releas the key (then the key_released event is generated) and he press the key again.

So in others words, you just check when the key started to be pressed and when ended to be pressed, no need to keeps cheking the device in between; if you want to known how much time the key was pressed then just store the time in both event hapen and then compare.


good luck,


If you're developing under "WinXP/VC++6" anyway, you may want to use DirectInput. It is able to buffer events as they come, so you could process them later (once per game loop, in this case). Every event has a time stamp associated with it.

Quote:From DX SDK
The dwTimeStamp member contains the system time, in milliseconds, at which the event took place. This is equivalent to the value that would have been returned by the Microsoft Win32 GetTickCount function, but at a higher resolution.


I guess "higher resolution" means to a single milisecond.
Quote:Original post by jra1980
My argument against this is: Imagine that 2 players on 2 different machines (one fast one slow) are playing against each other in some FPS (First Person 3D shooter). They both are facing each other and both *at the same instant in time* fire at each other (press the fire button).

How can they do that? The guy with the fast framerate will see his opponent first. The guy with the slower framerate won't even be able to see the enemy, when he gets shot. So what difference does it make?
You're talking about a purely hypothetical situation, which is only really relevant if there's a psychic link between the players (or, of course, if they can see each others monitors)

But in the normal case, a player won't be able to do anything useful, until the screen updates anyway. You could sample for input 200 times for each frame, but what good would it do? The player wouldn't have anything new to act on until the screen updates, so he wouldn't actually provide any new useful input.

As long as the screen isn't updating, how can the player react? And if the player can't react, how does it matter whether you read input from the player?

Now, just to be clear, it's usually a very good idea to use some kind of fixed timesteps, so the game logic is decoupled from framerate, I'm not arguing against that. This solves a hell of a lot of synchronizatino issues, it allows you to run at any framerate without in any way affecting the gameplay, and so on. Great stuff...
And if you do this, the obvious way to handle input is to sample every timestep, so this does pretty much solve the "problem".

I'm just arguing that how frequently you sample input isn't the important issue. The player can't meaningfully provide input until the game gives him some output to act on. That is, until the game updates the screen.
Loop is bad term. It's often sort of finite state machine, and asynchronous on top of that.

Obviously stable amount of Updates per second is important. 100 UPS should be enough. If you are doing flight simulation 1 K UPS should be close to real airplane. (IIRC you can't have it on current windoze (without errors) without blasting out system, or starve other devices.)

I think the most confortable is the most asynchronous type of input processing. (With possibly double/tripple buffered state array.)

Amount of graphic card updates per second is from 14 - 24 (30) for strategy game, to 30 - 60 FPS for something with more movements on the screen. It should be somewhat tailored to the update frequency of the monitor. (or you could use tripple buffering)

Sleeping is important to save notebook battery, and to prevent unnecessary CPU heat.

Note that you should know how your timmer works. If QueryPerformanceCounter would give you ONLY elapsed cycles from last call, CPU could be slowed down, and your application would be shreded to pieces. (Not to mention that multicore/CPU computers could have independent values on each core/CPU and provide wildly varying results.)


Re Spoonbender
Obviously if someone would press left left up, it should be different than up. And processing all key events is bit silly, you are not in office application development.

Quote:Original post by Tac-Tics
Why does your game run at only 25fps? Do you limit it to that? Or are your draw methods just really slow ;-)


He didn't say his program runs at 25fps... He said,
Quote:"For example on a machine that can render 25fps".


I would honestly lock it at 30-60 updates a second. I forget what Doom3 does but this levels the playing field for the most part. How many people need more then 30 keys hit in a second anyways? I consider myself a fast typer (70wpm+ when just plain text) but no way I can do that in a game :)

This way you also set everything up nicely for networking, no speed hacking etc from my understanding.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Quote:Original post by Mike2343
Quote:Original post by Tac-Tics
Why does your game run at only 25fps? Do you limit it to that? Or are your draw methods just really slow ;-)


He didn't say his program runs at 25fps... He said,
Quote:"For example on a machine that can render 25fps".


I would honestly lock it at 30-60 updates a second. I forget what Doom3 does but this levels the playing field for the most part. How many people need more then 30 keys hit in a second anyways? I consider myself a fast typer (70wpm+ when just plain text) but no way I can do that in a game :)

This way you also set everything up nicely for networking, no speed hacking etc from my understanding.

You must not be an FPS player. Speed and accuracy is everything, and I'll be damned if my mouse and keyboard aren't updating as fast as they could possibly be. Past a certain level, I'd like to be sure it's my skill keeping me from defeating my enemies, not my lack of a super-computer to play my games on. Sometimes, extropolation isn't good enough [smile] Sure, there's a level past which you can't (reasonably) go with regards to checking input, but at the very least grant a stable checking rate, without being locked to anything else.
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!

This topic is closed to new replies.

Advertisement