Need help with game loop (screenshot included)

Hi! I've been working on overall design of a game loop and I've gotten most of information from here: http://gameprogrammingpatterns.com/game-loop.html

I'm using SFML, so I have a question and also code I need help with. First with the question:

The last (and from his words usually the best) type of game loop is "Fixed update time step, variable rendering." I get the fixed update time step, but I have no idea how to do the variable rendering. If someone could give me a super rough example of this in SFML or something similar it would be a godsend. Because I have no idea how to render something at half speed.

Onto my problem! I've been trying to create the "Variable time step", and I think I have done so, but there's a problem: my program is very unstable when it comes to draw time and fps. With about 1.2k sprites on the screen it will jump to 13 ms per draw frame then suddenly jump to 40-100ms. Is there any way to make it not do that? You can see my "info" I'm getting these numbers with: http://i.imgur.com/UEJnXgc.png

My graphics card (GTX 760) is around 42% load @ 1600 squares on the screen so it'd definitely not because I'm close to the max my system can handle. It has to be because of something else.

Here is the loop code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

void App::MainLoop()
{
	sf::Clock fpsClock;
	sf::Clock printClock;
	sf::Clock updateClock;
	sf::Clock timeTakenClock;

	sf::Time previous, lag, current, elapsed, update = sf::seconds(1.f / 80);
	sf::Time frameTime;


	while (window->isOpen())
	{
		//get current fps
		frameTime = fpsClock.restart();
		fps = sf::seconds(1.f) / frameTime;

		//fixed time step
		current = updateClock.getElapsedTime();
		elapsed = current - previous;
		previous = current;
		lag += elapsed;

		//get input time

		timeTakenClock.restart();

		Input();

		inputTime = timeTakenClock.getElapsedTime();

		timeTakenClock.restart();

		while (lag >= update)
		{
			Update();

			lag -= update;
		}

		updateTime = timeTakenClock.getElapsedTime();

		timeTakenClock.restart();

		Draw();

		drawTime = timeTakenClock.getElapsedTime();

		if (printClock.getElapsedTime() > sf::seconds(1))
		{

			int totalShapes = 0;

			for (auto it = trees.begin(); it != trees.end(); it++)
			{
				totalShapes += (*it)->getSize();
			}

			system("cls");
			std::cout << "fps: " << fps << " | " << sys.timeToString(frameTime) << " frame time" << std::endl
				<< "input time: " << sys.timeToString(inputTime) << std::endl
				<< "update time: " << sys.timeToString(updateTime) << std::endl
				<< "draw time: " << sys.timeToString(drawTime) << std::endl
				<< "object count: " << totalShapes << std::endl;


			printClock.restart();
		}
	}
}


Thanks a bunch for the read and answering just one of my questions would be really helpful. I doubt you need to see the rest of the program: it's literally just an incomplete (more or les bad) QuadTree with a vector of rectangles. In fact, here's the update part. Nothing special:

1
2
3
4
5
6
7
8
void QuadTree::Update()
{
	for (auto it = shapes.begin(); it != shapes.end(); it++)
	{
		(*it)->rotate(1);
		//(*it)->move(sf::Vector2f(.1, 0));
	}
}


edit: so as i increase the update speed to higher numbers, the game seems to run a lot better but crashes harder. i can get to around 800 objects without shuddering with an update speed of 1/400th of a second but after it starts to shudder it can never stop. is there a sweet spot i should put it at? obviously not everybody's computer is the same..
Last edited on
That seems awfully slow. Back when I was using a 9500 GT, I used to be able to draw around 900k textured quads per second (assuming single texture), and that's including computation of complex trajectories using trigonometric functions. A 760 shouldn't even break a sweat at 1600 untextured polygons.
Last edited on
900k?! That seems insane from the performance I have now. At 9000 squares I have between 2-11 fps. And that's without rotation. With I have a max of 1. I mean I'm pretty sure SFML is basically a wrapper around OpenGL. wouldn't that give theoretically the best performance in tests like this?
Last edited on
You should run your code through a profiler. There must be something on the CPU side that's eating up your performance.
http://i.imgur.com/tAcfBIe.jpg

First time doing this. I did it for a minute with 9000 boxes on the screen. Can someone help me figure out what this means?
It looks like 83% of the time is wasted in an operator=() implementation. Make sure you're not passing or returning any sf::ComplexShapes by value. If you have any containers of the form T<sf::ComplexShape>, consider changing them to T<std::shared_ptr<sf::ComplexShape> >.
The only container I'm using is a vector of pointers. Do you mean sf::ConvexShape instead of ComplexShape? If so, I'm pretty sure I'm not passing any by value.

this is the update part:

1
2
3
4
5
6
7
void App::Update()
{
	for (auto it = shapes.begin(); it != shapes.end(); it++)
	{
		(*it)->rotate(1);
	}
}


draw part:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

void App::Draw()
{
	window->clear();

	for (auto it = shapes.begin(); it != shapes.end(); it++)
	{
		auto shape = **it;

		window->draw(shape);
	}

	window->display();
}


I found some interesting results however. When I build release mode and I run the .exe OUTSIDE of my IDE i can push 20k shapes and have all of them rotate with a solid 60. No shuddering at all. So.. Is that normal? It seems like running release mode from my ide still has the same performance as debug mode.
(Stupid fingers! Ctrl+Shift+T, not Ctrl+Shift+R!)

Debugging a program always has the same performance penalty, but debugging an optimized executable should be faster (and generally less useful) than debugging an unoptimized executable.

The program is still too slow. You're only drawing 33% more shapes than I was, in a GPU that's vastly superior. The bottleneck must still be in the CPU.
How expensive is Update()? That's not a typical variable timestep implementation.
1
2
3
4
5
6
7
8
9
10
11
12
auto first = now();
auto last = first;
while (true){
    auto t = now();
    //...
    Update(t - last);
    // Alternatively: Update(t - first);
    //...
    Draw();
    //...
    last = t;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
void App::Draw()
{
	window->clear();

	for (auto it = shapes.begin(); it != shapes.end(); it++)
	{
		auto shape = **it;

		window->draw(shape);
	}

	window->display();
}


Line 8 makes a copy. It is not inconceivable that some operator= is called during the initialization of that copy.

Why not:
1
2
3
4
5
6
7
8
9
void App::Draw()
{
	window->clear();

	for (auto it = shapes.begin(); it != shapes.end(); it++)
		window->draw(**it);

	window->display();
}


or
1
2
3
4
5
6
7
8
9
10
11
12
13
void App::Draw()
{
	window->clear();

	for (auto it = shapes.begin(); it != shapes.end(); it++)
	{
		auto& shape = **it;

		window->draw(shape);
	}

	window->display();
}
Wow, thank you, Cire. Doing your last example didn't make any difference on the debug version, but it runs flawlessly in release when launched from my ide (previously it only ran flawlessly in release running the compiled .exe outside of the .ide).

so
 
auto shape = **it;


was copying each shape and drawling them? and putting the '&' made it pas through reference? .


@helios
this is my update:

1
2
3
4
5
6
7
void App::Update()
{
	for (auto it = shapes.begin(); it != shapes.end(); it++)
	{
		(*it)->rotate(10);
	}
}


I did Cire's suggesting and it got rid of the = operator bottleneck in the profiler. This is what it looks like now: http://i.imgur.com/tyFX3GF.png

I still don't understand how release can have a solid 60 fps with 20k sprites on the screen while debug is taking 1-3 seconds per frame to render 9k. And thanks for the help!

Also, why isn't it typical? I tried to copy it from the website I linked in my first post. Should I not follow that?

Last edited on
Topic archived. No new replies allowed.