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

Forget it, I solved xD

While staring at the error I suddenly remembered reading something about a template function that need to be declared on the header file, I tried to move the declararion and it now runs :D

Well, guess now I will remember this one, sorry for the post above :S

I didn't see that you posted the error until you fixed it. That error is basically when something is being used without being defined first, which you probably already know. I'm glad you were able to fix it without having to wait several hours for a reply.

Advertisement

I might have some Time problems, I was wondering if someone good at timing could take a look  :\

Below is my entire Game Loop plus some debug console output:


void App::GameLoop()
{
	while (Game->IsRunning())
	{
		/*DEBUG*/static Uint64 Frame = 0;
		/*DEBUG*/Frame++;
		/*DEBUG*/std::cout << "FRAME:  " << Frame << std::endl;
		/*DEBUG*/LogConsole((Timer->PrintTimeSinceLasUpdate() + Timer->PrintTimeSinceLastDraw()).c_str());

		//UPDATE
		while (Timer->CurrentTime() > Timer->NextUpdateTime)
		{
			Game->Update(Timer->UpdateTick());
		}
		//DRAW
		Game->Draw(0.f/*Timer->DrawTick()*/);

		/*DEBUG*/std::cout << "INTERPOLATION VALUE:" << Timer->DrawTick() << std::endl << std::endl;
	}
}

UpdateTick() computes and return DeltaTime, while DrawTick() computes and return a float Interpolation ranging from 0 to 1 (I have commented it out from inside the Draw() function so that I can cout the value in the line below).

I'll also put the code of my entire Timer class at the end of page (inside spoiler since is long), in case needed to answer.

In the image below you can see what the code prints out, on the left side it the App running without SDL_RENDERER_PRESENTVSYNC, in the right side SDL_RENDERER_PRESENTVSYNC is enabled.

From my understanding "Interpolation" which is passed to the Draw() function to draw a prediction of the next game-state should range from 0 to 1, but as you can see by comparing FRAME 9 I think the Vsync is kind of holding things up so it outputs value slightly beyond 1...Is this acceptable? How should I handle this? Should I ignore it or should I cap the Interpolation value to 1 ? :/

IMAGE

aacWLe9.png

Spoiler


#pragma once
#include <chrono>
#include <string>
using namespace std::chrono;

//This type sets Ticks per second of the update call
template <size_t N>
using UpdateTickDuration = duration<uint32_t, std::ratio<1, N>>;

using FloatSeconds = duration<float>;

template<size_t N>
class GameTimer
{
private:/*variables*/
	UpdateTickDuration<N> GameUpdateTPS;
	milliseconds MsSinceLastDraw;
	milliseconds MsSinceLastUpdate;
	time_point<steady_clock> TimeNow;

public:/*variables*/
	time_point<steady_clock> TimeBegin;
	time_point<steady_clock> PrevUpdateTime;
	time_point<steady_clock> PrevDrawTime;
	time_point<steady_clock> NextUpdateTime;

public:/*constructors*/
	GameTimer();
	~GameTimer();

public:/*methods*/
	time_point<steady_clock> CurrentTime();
	float UpdateTick();
	float DrawTick();
	std::string PrintTimeSinceLasUpdate();
	std::string PrintTimeSinceLastDraw();

private:/*methods*/
	float Interpolation();
	float RecordTimeSinceLastUpdate();
	float RecordTimeSinceLastDraw();
};

///////////////////////////////////////////////////

template <size_t N>
GameTimer<N>::GameTimer()
	:GameUpdateTPS{ 1 }, MsSinceLastDraw{ 0 }, MsSinceLastUpdate{ 0 }
{
	TimeBegin = TimeNow = PrevDrawTime = PrevUpdateTime = NextUpdateTime = steady_clock::now();
}

template <size_t N>
GameTimer<N>::~GameTimer()
{
}

template <size_t N>
time_point<steady_clock> GameTimer<N>::CurrentTime()
{
	TimeNow = steady_clock::now();
	return TimeNow;
}

template <size_t N>
float GameTimer<N>::UpdateTick()
{
	NextUpdateTime += GameUpdateTPS;
	return RecordTimeSinceLastUpdate();//this is basically returning DeltaTime
}

template <size_t N>
float GameTimer<N>::RecordTimeSinceLastUpdate()
{
	MsSinceLastUpdate = duration_cast<milliseconds>(CurrentTime() - PrevUpdateTime);
	PrevUpdateTime = CurrentTime();
	return duration_cast<FloatSeconds>(MsSinceLastUpdate).count();
}

template <size_t N>
float GameTimer<N>::DrawTick()
{
	RecordTimeSinceLastDraw();//this is recorded to calculate FPS
	return Interpolation();
}

template <size_t N>
float GameTimer<N>::RecordTimeSinceLastDraw()
{
	MsSinceLastDraw = duration_cast<milliseconds>(CurrentTime() - PrevDrawTime);
	PrevDrawTime = CurrentTime();
	return duration_cast<FloatSeconds>(MsSinceLastDraw).count();
}

template <size_t N>
float GameTimer<N>::Interpolation()
{
	nanoseconds TimeOffset_ns = CurrentTime() + GameUpdateTPS - NextUpdateTime;
	nanoseconds GameUpdateTPS_ns = duration_cast<nanoseconds>(GameUpdateTPS);
	/*DEBUG*/std::cout << "NANOSECONDS TimeOffset_ns:" << TimeOffset_ns.count() << " / " << std::endl;
	/*DEBUG*/std::cout << "NANOSECONDS GameUpdateTPS_ns:" << GameUpdateTPS_ns.count() << " = " << std::endl;
	return (static_cast<float>(TimeOffset_ns.count()) / static_cast<float>(GameUpdateTPS_ns.count()));
}

template <size_t N>
std::string GameTimer<N>::PrintTimeSinceLasUpdate()
{
	return "| LastUpdate: " + std::to_string(duration_cast<milliseconds>(steady_clock::now() - PrevUpdateTime).count()) + "ms ago|";
}

template <size_t N>
std::string GameTimer<N>::PrintTimeSinceLastDraw()
{
	return "| LastFrame: " + std::to_string(duration_cast<milliseconds>(steady_clock::now() - PrevDrawTime).count()) + "ms ago|";
}

 

 

9 minutes ago, MarcusAseth said:

while (Timer->CurrentTime() > Timer->NextUpdateTime)

What is the idea behind the inner while loop?

🧙

7 minutes ago, matt77hias said:

What is the idea behind the inner while loop?

if the current time is greater than the time_point we scheduled the next update (which is at steps of 40ms), then we enter the update loop, and after updating, we skip it for the next 40ms, still drawing as fast as we can.

It should enter the update loop only 25 times per second.

4 minutes ago, MarcusAseth said:

It should enter the update loop 25 times per second.

And you don't draw every Update since your Draw is outside your "Update Loop"?

🧙

Advertisement
7 minutes ago, matt77hias said:

And you don't draw every Update since your Draw is outside your "Update Loop"?

Exactly. In that "40ms time frame" in which we don't update but we still draw as fast as we can, the Interpolate value is used to multiply the velocities of the thing we draw, basically kind of "predicting" their position and drawing at the appropriate location.

Edit: In the Draw() function I should probably pass the last calculated DeltaTime multipied by the interpolation, so I already have a mistake in there :P

3 minutes ago, MarcusAseth said:

Exactly. In that "40ms time frame" in which we don't update but we still draw as fast as we can, the Interpolate value is used to multiply the velocities of the thing we draw, basically kind of "predicting" their position and drawing at the appropriate location.

But why not just updating your scene with the current delta and then drawing that scene as-is (without prediction)?

🧙

1 minute ago, matt77hias said:

But why not just updating your scene with the current delta and then drawing that scene as-is (without prediction)?

https://gafferongames.com/post/fix_your_timestep/

Hello to all my stalkers.

2 minutes ago, matt77hias said:

But why not just updating your scene with the current delta and then drawing that scene as-is (without prediction)?

You guys passed me this -> http://www.koonsolo.com/news/dewitters-gameloop/  in another topic, I am just following what he says, during the last example of a game loop xD

This topic is closed to new replies.

Advertisement