Sunday, June 12, 2005

Frame Independant Movement

I've just about caught up on sleep, Tokyo was crazy, so I'm ready to do a little programming again :D

I'm still fine tuning my quake like console. I want to have frame-independant movement for my drop down console. This makes sure that on all machines the movement is relatively the same. On machines in the future extra speed won't mean an unplayable game. This is taken care of in a round about way in the game animation code in the Game Programming For Monkeys tutorial. Here though I'm trying to create a modular library. Code re-use can be done but code sharing is a bit of a no-no. My timing stuff is a bit heavy for a light GUI library. I want a simpler solution.

As with a lot of common problems Gamedev has a tutorial. This tutorial is by Ben Dilts thanks to him we can all whip something up much faster.

Of course as with most tutorials it's in C or C++, here I present some slightly modified code for C#.

internal sealed class FrameRate
{

[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(
out ulong lpPerformanceCount);

[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(
out ulong lpFrequency);

private float targetfps;
private float fps;
private ulong tickspersecond;
private ulong currentticks;
private ulong framedelay;

private float speedfactor;

public float SpeedFactor
{
get{ return speedfactor; }
}

public FrameRate(float targetFPS)
{
targetfps = targetFPS;
QueryPerformanceCounter(
out framedelay);
QueryPerformanceFrequency(
out tickspersecond);
}

public void SetSpeedFactor(object sender)
{
QueryPerformanceCounter(
out currentticks);
//This frame's length out of desired length
speedfactor = (float)(currentticks-framedelay)/((float)tickspersecond/targetfps);

fps = targetfps/speedfactor;
if (speedfactor <= 0)
speedfactor = 1;

framedelay = currentticks;
}
}


You can ignore the internal sealed stuff. Also I didn't want to import the LARGE_INTEGER definition so I just used unsigned longs. I hope this doesn't have any awful repuccusions. I feel there should be some use of mod in there to make it all perfectly safe forever and ever. If any one wants to make this addition I'd be interested. (This is to do with the interger getting to big and resetting at some very large number)

Oh so you called SetSpeedFactor everygame loop. Then when you want something to move you do the following.

Robot.Move(5 * framerate.SpeedFactor);

Simple. Now your code is frame independant.

No comments: