Sign in to follow this  
Gage64

Accurate timing in the game loop

Recommended Posts

Suppose my game runs constantly at 60 fps. That means that each frame lasts about 16 ms. Now suppose that I want to perform an action every 10 ms. The obvious way to achieve this is to check each frame if 10 ms have passed, and if it has, perform the action. Unfortunately this doesn't work. Using this method, the action will be performed at most once per-frame, meaning that it will really be performed every 16 ms. How can I solve this? Thanks in advance.

Share this post


Link to post
Share on other sites
The short answer is that you can't (with your present game loop setup).

The long answer is that you will probably need multi-threading. If one iteration of your game loop takes 16 MS, it's either because you fixed it to that interval (see MJP's post), because you are CPU bound, or because you are GPU bound (including Present()'s waiting for vsync). Either way, your main game loop will be busy doing something. The only solution, then, is to use another thread to check continuously if the interval has elapsed.

Share this post


Link to post
Share on other sites
Quote:
Original post by davidsporn
the timeStep is 10ms in your case.


That can't be right. I can have many actions, some of which will be performed every 5 ms, some every 50 ms, etc, so the time step has to be based on something else.

Quote:
Original post by ValMan
If one iteration of your game loop takes 16 MS, it's either because you fixed it to that interval (see MJP's post), because you are CPU bound, or because you are GPU bound (including Present()'s waiting for vsync). Either way, your main game loop will be busy doing something.


The 16 ms was just for the sake of discussion. Besides, I think pretty much every game supports this in some way. Are you saying that they all use multi-threading (even the old ones)?

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
Quote:
Original post by davidsporn
the timeStep is 10ms in your case.


That can't be right. I can have many actions, some of which will be performed every 5 ms, some every 50 ms, etc, so the time step has to be based on something else.


You can implement this for every action if you want, with timeStep being a member variable for that particular class. This won't allow you to update things at the exact moment the time step elapses, but the end result will be the same over a long period of time.

Share this post


Link to post
Share on other sites
Quote:
Original post by MJP
You can implement this for every action if you want, with timeStep being a member variable for that particular class.


If you mean what I think you mean, this won't work properly. If you'll read a couple of posts starting from here, you'll see what I mean.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kylotan
I would argue that it would be best to give up on the idea of getting anything to happen every 5 milliseconds. That sort of resolution isn't really reliable without a lot of work.


Again, it was just an example. The question is, how do I do this for a frequency that's higher than the game loop's. For example, if it's running at 30 fps, each frame lasts about 33 ms, and suppose I want something to happen every 20 ms.

Share this post


Link to post
Share on other sites
You need another thread.

Basically, you should never need anything to be done more than once per game loop. Games are not real-time, the user won't be able to know if you are running at 60fps and emitting a particle every 5ms or if you simply emit 3 per loop.

If you want twice the particles if the game was running at 30fps, then I'd argue against the idea since you're only getting 30fps. But to simulate 5ms timing, divide your frame time by 5ms, and emit that many particles. Then at 60fps you will get 3, at 30fps you will get 6, etc.

But I'd strongly suggest re-thinking what you're trying to do. Odds are you can achieve the same thing for much less work and overhead that will give the end user the same experience.

Share this post


Link to post
Share on other sites
You need an accurate timer; and then make a separate calculation loop and a render loop. You call these in your main loop and you can call these at any time interval. No need for threading imho. Of course threads can; but will make things complicated.

Share this post


Link to post
Share on other sites
Quote:
Original post by gekko
But I'd strongly suggest re-thinking what you're trying to do. Odds are you can achieve the same thing for much less work and overhead that will give the end user the same experience.


This is mostly theoretical thinking. In the games I've created so far (pong, snake, tetris), the naive approach I described in my original post worked just fine (or seemed to work just fine. Some of the posts in the link I gave earlier show that this stuff can be tricky to get right, and you might not even notice if it's wrong).

I was just trying to think ahead for more complex games. For example, if you have a machine gun, it should fire at a very high rate of fire, so maybe firing just one bullet per-frame won't be fast enough.

This is also an attempt to better understand the discussion over here.

I guess I need to try and implement this, and when I'll actually encounter a problem I'll know what questions to ask.

Thanks everyone for their comments.

Share this post


Link to post
Share on other sites
The code MJP posted will solve that issue, as it will execute the code x times each frame to compensate for the fact that your game is running at 60 hz instead of say 200 which is the machine-guns rate of fire.. The user won't notice this and he can't, the world state is only rendered at 60 hz anyways.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64

I was just trying to think ahead for more complex games. For example, if you have a machine gun, it should fire at a very high rate of fire, so maybe firing just one bullet per-frame won't be fast enough.



That's not the way to go about doing this. Just fire more bullets per frame in that scenario.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
Quote:
Original post by gekko
But I'd strongly suggest re-thinking what you're trying to do. Odds are you can achieve the same thing for much less work and overhead that will give the end user the same experience.


This is mostly theoretical thinking. In the games I've created so far (pong, snake, tetris), the naive approach I described in my original post worked just fine (or seemed to work just fine. Some of the posts in the link I gave earlier show that this stuff can be tricky to get right, and you might not even notice if it's wrong).

I was just trying to think ahead for more complex games. For example, if you have a machine gun, it should fire at a very high rate of fire, so maybe firing just one bullet per-frame won't be fast enough.

This is also an attempt to better understand the discussion over here.

I guess I need to try and implement this, and when I'll actually encounter a problem I'll know what questions to ask.

Thanks everyone for their comments.


Interesting...I suppose are cases where simulating concurrency will break down quite quickly. Unfortunately I don't really know of any sure-fire solutions, so I can't really help you out. If you do come up with anything, be sure to share with us. [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
Then I'll repeat my earlier question: How do you determine what time-step to use?


Say you want the machine gun to fire 200 times per second, if float dt is in seconds your timestep for the bullet fire code should be float timestep = 1.0/200.0

Share this post


Link to post
Share on other sites
Quote:
Original post by lexs
Say you want the machine gun to fire 200 times per second, if float dt is in seconds your timestep for the bullet fire code should be float timestep = 1.0/200.0


Quote:
Original post by Gage64
That can't be right. I can have many actions, some of which will be performed every 5 ms, some every 50 ms, etc, so the time step has to be based on something else.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
I was just trying to think ahead for more complex games. For example, if you have a machine gun, it should fire at a very high rate of fire, so maybe firing just one bullet per-frame won't be fast enough.


Even the typical machine gun probably won't need to fire more than 20 times a second. But remember the aim of a game isn't necessarily to simulate every single bullet.

Your original suggestion is good enough, with a small modification. If you need to do something every 10ms, but 16ms has elapsed, then you do whatever needs to be done, and you cut 6ms off the schedule for the next one. It's a tiny bit more complicated when your timestep is big enough to encompass two sequential events rather than just one. The system perhaps needs to repeatedly ask the event generator (eg. the gun in this case) for the next event, and if it's due, handle it, and if it's not, leave it for the next frame.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kylotan
Your original suggestion is good enough, with a small modification. If you need to do something every 10ms, but 16ms has elapsed, then you do whatever needs to be done, and you cut 6ms off the schedule for the next one.


Unfortunately this doesn't work. This post explains why. Unless I misunderstood you?

It looks like using MJP's fixed time-step will solve this issue, but I still haven't gotten an answer as to how to choose the time-step.

Share this post


Link to post
Share on other sites
You misunderstood me. I'm not suggesting a sampling approach to see which events are due right now, I'm suggesting watching to see which events have become due since last time, and at that point, you can handle it and see if yet another event will become due as a result. Each time you check whether an event is due, and if it is, you handle it, which for repeated actions typically involves scheduling the next event. That new event may be due already, so you handle that as well, until you're out of events to handle. This way you could end up firing 10 bullets per update, or whatever. You also know exactly how overdue each one is, so you can factor that into your physics or graphics.

As for choosing the time step, it's arbitrary. Pick one that is fine-grained enough to work for you, but not so fine-grained that you waste too much CPU time on trivial updates. As typical examples, I've heard of some people using 10Hz, others using 25Hz or 30Hz.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kylotan
I'm suggesting watching to see which events have become due since last time, and at that point, you can handle it and see if yet another event will become due as a result. Each time you check whether an event is due, and if it is, you handle it, which for repeated actions typically involves scheduling the next event. That new event may be due already, so you handle that as well, until you're out of events to handle. This way you could end up firing 10 bullets per update, or whatever.


I think I'm starting to get it. I also think that that's what MJP suggested with his code for the fixed time-step loop, though it looks like I'll have to do that for each event (because different events can have different execution frequencies). I'm not sure how I should set all this up...

Quote:
This way you could end up firing 10 bullets per update, or whatever. You also know exactly how overdue each one is, so you can factor that into your physics or graphics.


I assume you are referring to interpolation. I haven't even thought about how that will work, but that's a topic for another thread...

Thank you for your help. I'll think about this some more and maybe try to implement a simple demo and see if it works out.

Thanks again to everyone.

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