Jump to content

  • Log In with Google      Sign In   
  • Create Account

Controlling game loop speed


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
10 replies to this topic

#1 CdrTomalak   Members   -  Reputation: 272

Like
0Likes
Like

Posted 04 May 2013 - 10:09 AM

My pacman clone is progressing, and I am now at the point where I need to slow down the game loop.

 

However, there are points where I switch textures which causes a subtle slow-down (I think - it's hard to tell), so my thoughts turn to regulating the game loop speed - i.e. I don't want to see any slowdown whatsoever.

 

Rather than putting a wait command in the loop, what other techniques are there? I'm sure there are loads out there, so please feel free to point in the way of your favourite article. I'm basically doing research at the moment before going ahead with anything.

 

Essentially I want to choose a game speed which means there will always be room for a little extra processing overhead, and the user will not notice a thing. It's running too fast at the moment! On average about 350 FPS.

 

Thanks in advance! cool.png


Edited by CdrTomalak, 04 May 2013 - 10:17 AM.


Sponsor:

#2 unbird   Crossbones+   -  Reputation: 6021

Like
2Likes
Like

Posted 04 May 2013 - 10:36 AM

Yep, neither a busy wait nor a Thread.Sleep would be I good idea. The former wastes cycles and the latter has too big a granularity so you might drop frames.
 
Do a VSync, in D3D9 this is done with PresentInterval.One (PresentParameters of the device or SwapChain), in D3D11 with SwapChain.Present(1,PresentFlags.None);

#3 Servant of the Lord   Crossbones+   -  Reputation: 21194

Like
7Likes
Like

Posted 04 May 2013 - 11:05 AM

The below code is from a C++ user's perspective, but the concept works across languages.

 

Every frame, get the amount of time passed since the last frame, like this:

//Get the amount of time passed since the program began.
currentTime = GetTimeInMillaseconds();
 
//Calculate amount of time past since the previous frame's time.
deltaTime = (currentTime - previousTime);
 
//Make this frame's time be the previous frame's time (for next loop's calculation).
previousTime = currentTime;

 

Then convert from milliseconds to floating point seconds (not actually required, but makes calculations alot easier).

//This makes 1 second equal to 1.0f, and half a second 0.5f, and so on.
deltaTimeAsFloat = (float(deltaTime) / 1000.0f);

 

Sometimes APIs provide a convenience function that directly gives you the delta time.

 

Now you can pass 'deltaTimeAsFloat' to all your subsystems where movements, animations, and everything else takes place.

 

So, you can do things like this:

updateCharacter(float deltaTime)
{
      const float MovementSpeedPerSecond = 200.0f; //200 pixels a second.
 
      //If half a second (deltaTime = 0.5f) goes by, then (200.0f * 0.5f == 100.0f).
      float distanceMovedThisFrame = (MovementSpeedPerSecond * deltaTime);
      
      playerPosition += distanceMovedThisFrame;
}

 

So you end up updating movement based on the amount of time passed, not the number of frames that ran.

 

There are other methods as well, like fixed time-steps.


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#4 CdrTomalak   Members   -  Reputation: 272

Like
0Likes
Like

Posted 04 May 2013 - 12:09 PM

unbird and Servant - thanks for the advice!

 

So I just tried this as a first foray into FPS regulation. Results are ... not great!

 

So before my game loop I call this code:

 

			int FPS_TARGET = 150;
			int SKIP_TICKS = 10000000 / FPS_TARGET;			
			int TICKS_BEFORE_GAME_LOOP = getTickCount();	
			int TICKS_PASSED = 0;
			int TICK_TARGET = 0;
			int TICKS_NOW = 0;
			int TICKS_TO_WAIT = 0;
			TimeSpan timeSpan;

Then after the game operations, at the end of the loop I call:

 

					//		Tick target = Ticks BEFORE game loop + how many ticks to equate to desired FPS
					TICK_TARGET = TICKS_BEFORE_GAME_LOOP + SKIP_TICKS;
					// Get the tick count right now
					TICKS_NOW = getTickCount();
					// Find out how many ticks have passed
					TICKS_PASSED = getTickCount() - TICKS_BEFORE_GAME_LOOP;
					// Find out how many ticks we should wait
					TICKS_TO_WAIT = TICK_TARGET - TICKS_NOW;
					// Create a time span object so we can esily derive the milliseconds to wait
					timeSpan = new TimeSpan(TICKS_TO_WAIT);

					// Now sleep for the desired number of milliseconds	
					if(timeSpan.Milliseconds > 0)
					{
						// We're going to fast so slow down.
						Thread.Sleep(timeSpan.Milliseconds);
					}
					else
					{
						// We're running slow
					}

Initially this looks like it is working, but then later on the game starts going to fast again. I've got some timers in my game already, and confess to not really understanding threads that much (all the work has been on the game engine and logic so far...), so I am going to look into why my method is failing terribly!

 

As I said, new to this FPS regulation stuff. Trying a few things out is teaching me about various pitfalls etc (I seem to like learning that way!) cool.png



#5 unbird   Crossbones+   -  Reputation: 6021

Like
1Likes
Like

Posted 04 May 2013 - 12:22 PM

Well I said you shouldn't use Thread.Sleep wink.png. Get accurate timing first. You can e.g. use the System.Diagnostics.Stopwatch: Start it at program start and use the Elapsed property.

 

Edit: As Servant pointed out. You use the delta to "feed your simulation", not the other way round.

 

Now: Even the Stopwatch normally has a granularity which might pose a problem (15 ms if memory serves). Check if Stopwatch.IsHighresolution is enabled, it usually is. You will have to do the conversion yourself with (double)Stopwatch.ElapsedTicks / Stopwatch.Frequency.


Edited by unbird, 04 May 2013 - 12:27 PM.


#6 CdrTomalak   Members   -  Reputation: 272

Like
0Likes
Like

Posted 20 May 2013 - 01:27 PM

Well I've tried to implement FPS control using a timer, but it's not working for some reason I cannot fathom.

 

I am succesfully calculating the "MS to wait after every frame until proceeding to the next iteration of the game loop". Now then - having already tried Thread.Sleep() with dodgy results, I thought using a time would help.

 

I've got a setting to enable me to switch between timing modes. The code for using a timer is as follows:

 

	
        nextFrame = false;

        if(FPS_METHOD == "TIMER")
	{		
		// -----------------------------------------------------------------
		// TIMER METHOD (awful at present
		// -----------------------------------------------------------------
		if(GLOBAL_MS_TO_WAIT > 0)
		{		
			// START TIMER
			StartFPSTimer();	// Sets MS passed to 0
			
			// Wait until the nextFrame flag has been set. This will be when we reach the desired number of MS.
			// This is detected in the event MSecondHasPassed().
			do
			{
				// nothing
			} while (!nextFrame); // nextFrame will always be true after exiting this loop.
		}
		else
		{
			// We're running SLOW.
		}
	} // TIMER METHOD

Now in the game initialisation code I call the following to set up the FPSTimer:

 

		public void CreateFPSTimer()
		{
			// This timer needs to be tied to an event which fires every time a MS passes, not a second.
			FPStimer = new System.Threading.Timer(new System.Threading.TimerCallback(MSecondHasPassed), null, 0, 100);
		}

I declare the event as follows:

 

		private void MSecondHasPassed(object obj)
		{			
			// Increase the seconds passed counter.
			MsecondsPassed++;
			
			// Set nextFrame flag if MS passed is at the threshold
			if(MsecondsPassed == GLOBAL_MS_TO_WAIT)
			{
				nextFrame = true;
			}
		}

So what I'm doing is just waiting for the flag to be set via the event per MS. It looked easy to implement.

 

I *think* my timer is not declared correctly because the game slows to an unbearable pace. I thought it was declared correctly but it can't be. Is there something painfully obvious that I've got wrong?



#7 ApochPiQ   Moderators   -  Reputation: 16415

Like
0Likes
Like

Posted 20 May 2013 - 01:39 PM

Why are you insisting on regulating your framerate? That's kind of a backwards approach to the issue, which is that you don't use real wall-clock time to control your simulation speed.



#8 CdrTomalak   Members   -  Reputation: 272

Like
0Likes
Like

Posted 20 May 2013 - 01:44 PM

Well basically I'm trying to slow the game down. The design is quite (read very) primitive really. I'm just starting out and whilst I have a fairly solid game engine, I need to control the speed of the game loop.

 

Whilst really I should go with an overhaul to bring the design up to speed with best practice (updating movement based on time passed) I thought a quick fix for now would be to regulate the FPS.



#9 ApochPiQ   Moderators   -  Reputation: 16415

Like
0Likes
Like

Posted 20 May 2013 - 05:11 PM

I strongly recommend biting the bullet and writing the code correctly. As far as I'm aware you're under no specific deadline, so there's no reason to do something you explicitly know is inferior :-)

#10 CdrTomalak   Members   -  Reputation: 272

Like
0Likes
Like

Posted 21 May 2013 - 04:24 AM

My first game iteration plan includes quick-win options, as the quality of the first game is not supposed to be A1 but server as a learning exercise. I would imagine that the 2nd pass, or phase 2 would include using deltas and doing things correctly. Although I am under no specific deadline, I do want to draw Phase 1 to a close.


The next task after controlling game speed is to introduce sound, which I'm placing a higher priority on than a full rework to control game speed correctly. I guess it depends what's on your plan is for the implementation - and they are always pretty individual. I'd favour a patch-up for now. Just a preference though, and I'm sure others will disagree. If I can patch it up for minimal effort and it runs OK from the users point of view then that's fine for now.cool.png



#11 SimonForsman   Crossbones+   -  Reputation: 6325

Like
0Likes
Like

Posted 21 May 2013 - 06:42 AM

If you don't want to change much:

Just use a simple(not optimal, but very simple) fixed timestep then: (If you want to do it properly, read this: http://gafferongames.com/game-physics/fix-your-timestep/ )

 

add:

double currentTime, lastTime;

const double timePerFrame = 16.66667; //60 updates per second, roughly

currentTime = lastTime = systemfunctiontogetcurrenttimeaccuratly();

before your main loop.

 

and 

currentTime = systemfunctiontogetcurrenttimeaccuratly();

if (currentTime - lastTime < timePerFrame) continue;

lastTime+=timePerFrame;

//update and render normally here

 

at the top of your mainloop (inside the loop, just after the while)

 

set timePerFrame to whatever makes your game run at the speed you want.


I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS