Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411507 Posts in 69374 Topics- by 58429 Members - Latest Member: Alternalo

April 26, 2024, 05:14:34 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)How does my game loop look? (SDL2)
Pages: [1]
Print
Author Topic: How does my game loop look? (SDL2)  (Read 4322 times)
Jagnat
Level 0
**



View Profile WWW
« on: October 26, 2014, 02:51:50 PM »

Greetings!

I'm currently struggling a bit with setting up a robust game loop. I've based my current code off of this: http://gafferongames.com/game-physics/fix-your-timestep/, but although my physics seems to be solid, my rendering tends to be a bit stuttery.

I added a second counter to make it so that rendering doesn't happen as fast as possible. My render function takes an interval between 0 and 1, which represents how far in between an update we currently are, which I multiply the velocities of my objects by and add to their position. This cuts out a lot of jerkiness, but there's still a little visual stutter every time the update function is called.

Any help would be appreciated. There is hopefully a simple solution; I'm kinda bad at this! Here is the code:

Code:
prevTime = SDL_GetTicks();
uint32_t updateElapsed = 0;
uint32_t renderElapsed = 0;
uint32_t currentTime;
uint32_t elapsed;

running = true;
while (running)
{
currentTime = SDL_GetTicks();
elapsed = currentTime - prevTime;
if (elapsed > 500)
{
std::cout << "Running Slowly! Elapsed time between last cycle is " << elapsed << "!" << std::endl;
elapsed = 500;
}
updateElapsed += elapsed;
renderElapsed += elapsed;

HandleEvents();

// targetUpdatePeriod: 33, or roughly 30 cycles per sec
while (updateElapsed >= targetUpdatePeriod)
{
Update();
updateElapsed -= targetUpdatePeriod;
}

// targetrenderPeriod: 17, or roughly 60 frames per sec
if (renderElapsed >= targetRenderPeriod)
{
// Where are we between updates
Render((float)updateElapsed / (float)targetUpdatePeriod);
renderElapsed = 0;
}

// CPU break
SDL_Delay(1);

prevTime = currentTime;
}
Logged
Layl
Level 3
***

professional jerkface


View Profile WWW
« Reply #1 on: October 26, 2014, 03:26:32 PM »

You're updating at half the speed you're rendering, there's no reason to render the frame again if you didn't update, nothing changed. Not sure if this is the kind of stutter you're talking about.
Logged
Boreal
Level 6
*


Reinventing the wheel


View Profile
« Reply #2 on: October 26, 2014, 03:46:43 PM »

Instead of making the renderer predict where things are going to be, make it lag one update interval behind and interpolate between the two most recent states.
Logged

"In software, the only numbers of significance are 0, 1, and N." - Josh Barczak

magma - Reconstructed Mantle API
Jagnat
Level 0
**



View Profile WWW
« Reply #3 on: October 26, 2014, 04:00:19 PM »

You're updating at half the speed you're rendering, there's no reason to render the frame again if you didn't update, nothing changed. Not sure if this is the kind of stutter you're talking about.
From how I understand it, the render extrapolation should fix this potential issue. The reason I have a slower update rate than render rate is so that on crappy hardware I'll (hopefully) still get a constant amount of updates per second. The render interval on the other hand is meant to be adjustable, and still look smooth by extrapolating using an object's velocity. Correct me if I'm wrong!

Instead of making the renderer predict where things are going to be, make it lag one update interval behind and interpolate between the two most recent states.
I'm not sure if I understand this correctly.. Are you saying that I should keep two physics states, and instead of extrapolating the potential position using the velocity, I should instead interpolate between the past state and the current state and then render that? Will that cause a noticeable delay in between input changing an object, and the change actually showing up on the screen?
Logged
Thomas Hiatt
Level 0
***



View Profile
« Reply #4 on: October 26, 2014, 04:11:40 PM »

You could use SDL_GetPerformanceFrequency() and SDL_GetPerformanceCounter() instead of SDL_GetTicks() to potentially have more precision.
Logged
tjcbs
Level 1
*


View Profile WWW
« Reply #5 on: October 26, 2014, 04:12:59 PM »

I would very much like to understand this idea as well. Are people really keeping two sets of state for everything, and interpolating between the two?? It seems horribly wasteful and difficult to work with.
Logged

Boreal
Level 6
*


Reinventing the wheel


View Profile
« Reply #6 on: October 26, 2014, 04:36:06 PM »

I would very much like to understand this idea as well. Are people really keeping two sets of state for everything, and interpolating between the two?? It seems horribly wasteful and difficult to work with.

If you want to have an unlocked render frequency and a fixed update frequency, then yeah that's what you should do.  And it's not two sets of state for everything, just things like position, rotation, color, etc.  In terms of latency I've implemented this type of game loop before and there's really no difference.
Logged

"In software, the only numbers of significance are 0, 1, and N." - Josh Barczak

magma - Reconstructed Mantle API
ThemsAllTook
Administrator
Level 10
******



View Profile WWW
« Reply #7 on: October 26, 2014, 06:07:35 PM »

I'm not sure if I understand this correctly.. Are you saying that I should keep two physics states, and instead of extrapolating the potential position using the velocity, I should instead interpolate between the past state and the current state and then render that? Will that cause a noticeable delay in between input changing an object, and the change actually showing up on the screen?

Yes and yes. Extrapolation can't ever be accurate if something changes in Update(), so interpolation is your only real option. For less latency, you could always update more frequently - is there a reason you've chosen 30hz? I usually update at either 60hz or 120hz.

I would very much like to understand this idea as well. Are people really keeping two sets of state for everything, and interpolating between the two?? It seems horribly wasteful and difficult to work with.

Last time I implemented a system like this, I kept just a small subset of the previous frame's state for interpolation. All I needed for most cases was for each visible game object to keep a lastPosition variable (and maybe lastOrientation too if it can rotate). Not a huge inefficiency.
Logged

Jagnat
Level 0
**



View Profile WWW
« Reply #8 on: October 26, 2014, 06:28:55 PM »

Yes and yes. Extrapolation can't ever be accurate if something changes in Update(), so interpolation is your only real option. For less latency, you could always update more frequently - is there a reason you've chosen 30hz? I usually update at either 60hz or 120hz.

Last time I implemented a system like this, I kept just a small subset of the previous frame's state for interpolation. All I needed for most cases was for each visible game object to keep a lastPosition variable (and maybe lastOrientation too if it can rotate). Not a huge inefficiency.

No, 30hz was completely arbitrary. My thought process behind keeping it that low was that it wouldn't cause any problems on very slow machines, but as is evident by this topic, I don't have much experience with this kind of system Tongue. I guess when I think about it more, updating is never going to be slower than rendering in most games.
Logged
Sik
Level 10
*****


View Profile WWW
« Reply #9 on: October 26, 2014, 07:12:57 PM »

Bah, reason is in the above post, but: I recall SDL1 tutorials insisting that you should strive for 30FPS because of the accuracy of SDL_GetTicks() (yes, it's really inaccurate, it doesn't update in steps of 1ms despite the values it returns). In practice you're better off with the high accuracy timers instead, although those are somewhat harder to setup since the update frequency varies among systems.
Logged
Layl
Level 3
***

professional jerkface


View Profile WWW
« Reply #10 on: October 27, 2014, 08:45:27 AM »

A tricky note to be aware of with high frequency timers: If your game thread is switched between CPU cores, the time goes wacky. For some reason different cores tend to give a slightly different time with that.
Logged
Sik
Level 10
*****


View Profile WWW
« Reply #11 on: October 27, 2014, 10:41:38 AM »

Modern computers have a dedicated timer independent of all cores actually, so that's not the issue. The problem is that buggy implementations can cause the returned value to be incorrect (in really bad cases going as far as making time go backwards). Generally the OS knows to work around this, although in some cases it may fail. The problem is that the alternatives have their own downsides as well (lower resolution, higher power usage if you try to increase accuracy to 1ms, etc.).

The real issue is that PC hardware has some really serious problems with timers in general.
Logged
Boreal
Level 6
*


Reinventing the wheel


View Profile
« Reply #12 on: October 27, 2014, 11:24:23 AM »

Is there ever any reason to be putting calls to the high performance timer outside of your main thread?  I wouldn't worry about it.
Logged

"In software, the only numbers of significance are 0, 1, and N." - Josh Barczak

magma - Reconstructed Mantle API
Sik
Level 10
*****


View Profile WWW
« Reply #13 on: October 27, 2014, 02:49:14 PM »

No, but the kernel can decide to run the thread in a different CPU core the next time it gets scheduled.
Logged
Boreal
Level 6
*


Reinventing the wheel


View Profile
« Reply #14 on: October 27, 2014, 03:25:37 PM »

No, but the kernel can decide to run the thread in a different CPU core the next time it gets scheduled.

I suppose that's true.  I guess I wasn't thinking about sleep(), since normally I either just use V-sync or don't limit the frame rate at all.
Logged

"In software, the only numbers of significance are 0, 1, and N." - Josh Barczak

magma - Reconstructed Mantle API
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic