Advertisement

Making Breakout - Code Structure help requested

Started by September 11, 2017 01:08 PM
77 comments, last by Kylotan 7 years, 5 months ago

I still don't understand what do you mean...and I'm getting a slightly headache since your question are not clear at all to me =_=

First of all, what is this "time_budget"? I have no "time budget", I have a running clock which just keep running. When an UpdateTick() call is issued, the UpdateTick() function takes care of advancing the Timer class internal variable "NextUpdateTime" of 40ms. (NextUpdateTime is a time_point initially set up at the steady_clock starting point).

So the clock just keep being compared to that time_point every time trough the loop. When the clock surpassed the NextUpdateTime time_point, then it enter the Update loop and set the NextUpdateTime again 40ms forward.

5 minutes ago, MarcusAseth said:

First of all, what is this "time_budget"? I have no "time budget", I have a running clock which just keep running.

The "accumulator" in the Gaffer On's game loop which I use in DeWitters' game loop (since I do not want to interpolate the state) (see the urls posted above). That name feels odd (at least for me) since an accumulator is typically something used in pure functional programming languages to pass temporary data around.

🧙

Advertisement
1 minute ago, matt77hias said:

The accumulator in the Gaffer On's game loop.

I didn't yet had the chance to read that because that tutorial starts with

Quote

In the previous article we discussed how to integrate the equations of motion using a numerical integrator.

So now I am still reading that previous tutorial :\

8 minutes ago, MarcusAseth said:

I didn't yet had the chance to read that because that tutorial starts with

So now I am still reading that previous tutorial :\

No, you don't. The whole article has nothing to do with concrete physics. Think of "integrate" in their code snippets as a black box for the physics. But I do not use Gaffer On's game loop, I merely read it and just mention his terminology. I use DeWitters' game loop (which I haven't read about, but just deduced it myself based on this thread), which seems the most commonly used one based on my gut feeling.

🧙

18 hours ago, matt77hias said:

As a small note, I think it would make more sense to subtract the (predicted) render time from the frame time, since we now assume render time is neglectable.

If you don't do this, you enter the so-called Spiral-of-Death.

Lets say you use a fixed time step of 0.5ms and require 4ms for rendering. You will basically increase your time budget with the render time every frame, waste that budget on updates after which your rendering has no time any more, resulting in the continuous increase of your elapsed frame time (and thus even more updates per frame).

You could of course clamp your time budget, but then you obtain something like abs(sin(t)) = #updates.

I moved this to a separate forum post since it starts looking like a forum post hijack ;)

🧙

I need a goddamn book on game loops :D Those two articles won't cut it for me, I guess I am a slow learner (or rather, I need to see a lot of tables with the times and when and how a particular solution start falling apart) I can't even time properly my timer, since it enters the update loop 38ms since the last update even though I said it should enter 40ms after... :\  

Let's see what amazon has to offer on the subject

Advertisement

@MarcusAseth Forget everything I said about spinning and Spirals-of-Death. I (not you) was completely missing a point. My apologies for the confusion.

🧙

Wow, I leave a thread for a few hours and it goes well off the rails. ;)

I think Unity is the only game engine I've seen that has separate FixedUpdate and Update functions. Unreal likes to just have a single Tick. And not every engine uses explicit Updates - sometimes they expect you to register a callback on a timer, which gives you more control over your updates. Since low level stuff such as physics and animation is usually being handled separately (probably with fixed timesteps), this makes a lot of sense.

Marcus, you're still insisting that Vsync is messing up the interpolation value, and I think I told you right back on page 1, twice, that it's not. You're just measuring it incorrectly, at the wrong time. The only time that interpolation value needs to be calculated is immediately after the fixed update loop ends, and that tells you how the next render call needs to be adjusted. It doesn't make sense to calculate it again after the rendering because obviously more time will have passed. That will be taken into account on the next loop iteration.

I am not even considering the interpolation thing right now and just trying to get the basics of it timed properly, because I think there is something wrong even before.

4 hours ago, Kylotan said:

Marcus, you're still insisting that Vsync is messing up the interpolation value, and I think I told you right back on page 1, twice, that it's not.

I just made a test for Vsync, image below, let's see who can explain it.

So this image is the resoult I get with SDL_RENDERER_PRESENTVSYNC active(image below).

The data is stored into vectors and is collected inside the Update loop, therefore since I have a Fixed Update once every 40ms, this means we collect 25 samples in a second, and that shown is 1 second worth of data. So, the bar on top are the "scheduled next update" which predictably increase at step of 40ms, nothing to see there, but the matching data on the bottom is the current time when we enter the update loop. As you can see, we are always entering late when Vsync is On.

nksjizt.png

Now compare with the image below, where the SDL_RENDERER_PRESENTVSYNC flag is off. As you can see in the image below, we enter the update loop as soon as possible, which makes us right on time (except the 25th update where we are 1ms late).

FwiVwXg.png

Anyway, why is Vsync messing up when I enter the update function?! =_=

I also leave the testing code below in spoiler, so you can see where I was storing the values.

Spoiler


void App::GameLoop()
{
	/*DEBUG*///////////////
	std::vector<std::string> UpdateCall;
	std::vector<std::string> NextUpdateVals;

	Timer->Restart();
	while (Game->IsRunning())
	{
		time_point<steady_clock>& CurrentTime = Timer->Tick();

		/*DEBUG*///////////////
		SDL_SetRenderDrawColor(Renderer, 55, 55, 55, SDL_ALPHA_OPAQUE);
		SDL_RenderClear(Renderer);

		//UPDATE
		while (CurrentTime >= Timer->NextUpdateTime)
		{
			/*DEBUG*///////////////
			int CurrentMs = duration_cast<milliseconds>(CurrentTime - Timer->TimeBegin).count();
			int NextUpdateMs = duration_cast<milliseconds>(Timer->NextUpdateTime - Timer->TimeBegin).count();
			UpdateCall.push_back(std::to_string(CurrentMs));
			NextUpdateVals.push_back(std::to_string(NextUpdateMs));
			
			Game->Update();
			Timer->NextUpdateTime += Timer->GameUpdateTPS;
		}

		//DRAW
		Game->Draw(0.f/*Timer->DrawTick()*/);

		//Testing the loop from here.
		/*DEBUG*///////////////
		Timer->DrawTick();


		//1 seconds worth of Updates. Step marks at 40ms spacing
		int spacing = 100, border = 50;
		float fixedUpdate = 40;
		for (int i = 0; i < NextUpdateVals.size(); i++)
		{
			auto& val = NextUpdateVals[i];
			DrawDebugText(Renderer, val, Point{ border + spacing*i,180 }, Color{ 150,110,40,255 });
			DrawDebugLine(Renderer, Point{ border + spacing*i,200 }, Point{ border + spacing*i,230 }, Color{ 150,110,40,255 });
		}
		//Draw and compare the recorded value of when we entered UpdateLoop
		for (int i = 0; i < UpdateCall.size(); i++)
		{
			auto& val = UpdateCall[i];
			int scaledToGraph = (std::stof(val) / fixedUpdate) * spacing;
			DrawDebugText(Renderer, val, Point{ border + scaledToGraph,400 }, Color{ 215,130,40,255 });
			DrawDebugLine(Renderer, Point{ border + scaledToGraph,390 }, Point{ border + scaledToGraph,234 }, Color{ 215,130,40,255 });
		}

		SDL_RenderPresent(Renderer);
		/*DEBUG*/////////////////////////////////////////
	}
}

 

 

Vsync affects how long it takes to render. There is no way it can affect the timing of the main update code. I have no idea what those pictures are supposed to represent, but whatever you're measuring, it's wrong.

The fact you're talking about a fixed update as if it's meant to happen every 40ms, or like it's a thing to be scheduled, implies you don't understand what the system is doing. Fixed updates do not occur every X milliseconds. They happen whenever they happen, but they represent X milliseconds. You need to perform as many of them as needed to 'catch up' to the current time, and the remainder is what makes up the interpolation or extrapolation value for extra rendering smoothness.

Having vsync on does, by definition, imply that your rendering will take slightly longer, as it has to wait to synchronise the rendered frames with the update rate of the display hardware. This is not a bug, but a feature. Frame times will be larger on average, but usually much more regular. This may mean that you end up performing more fixed-step updates per rendering frame, as you have more time to make up between each one. Again, this is a feature, not a bug.

This topic is closed to new replies.

Advertisement