• 11
• 9
• 10
• 9
• 11

# Frame independent movement - problem calculating speedFactor

This topic is 1958 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi folks,

I'm working on a simple game (basically pong meets breakout) and am trying to implement framerate-independant movement.
I'm polling my Timer object for a speedfactor (= seconds per frame) and multiplying my movement with this number. This causes my objects to move VERY slowly - obviously I'm not doing this right. I used to multiply with "deltaTime" (= seconds since last frame) but the results are the same.
Is this a rounding error or something - what am I not getting here?

Timer object (polled function is getSpf())
[source lang="cpp"]
#include "Timer.h"
#include "defines.h"

/*
double m_secondsPerCount;
double m_deltaTime;

__int64 m_baseTime;
__int64 m_pausedTime;
__int64 m_stopTime;
__int64 m_prevTime;
__int64 m_currTime;

boom m_bStopped;
*/

Timer::Timer()
: m_secondsPerCount(0.0),
m_deltaTime(-1.0),
m_baseTime(0),
m_pausedTime(0),
m_prevTime(0),
m_currTime(0),
m_stopTime(0),
m_bStopped(false)
{
__int64 countsPerSecond;
QueryPerformanceFrequency((LARGE_INTEGER*) &countsPerSecond);
m_secondsPerCount = 1.0 / (double)countsPerSecond;
}

Timer::~Timer()
{
}

void Timer::tick()
{
if(m_bStopped)
{
m_deltaTime = 0.0;
return;
}

//get the time this frame
__int64 currentTime;
QueryPerformanceCounter((LARGE_INTEGER*) &currentTime);
m_currTime = currentTime;

//time difference between this frame and the previous frame in seconds
m_deltaTime = (m_currTime - m_prevTime) * m_secondsPerCount;

//prepare for the next frame
m_prevTime = m_currTime;

//threading or power save mode can cause non-negative values for delta time
//we correct this here
if(m_deltaTime < 0.0)
m_deltaTime = 0.0;
}

float Timer::getGameTime() const
{
//if we're stopped, get frequency difference between start and stop
//then translate the difference into seconds
if(m_bStopped)
return (float)((m_stopTime - m_baseTime) * m_secondsPerCount);
else //same idea but we need to remove the amount of paused time
return (float)(((m_currTime - m_pausedTime) - m_baseTime) * m_secondsPerCount);
}

double Timer::getDeltaTime() const
{
return m_deltaTime;
}

double Timer::getSpf() const
{
return 1.0 / getFps();
}
short Timer::getFps() const
{
return (short) 1.0/m_deltaTime;
}

void Timer::reset()
{
__int64 currentTime;
QueryPerformanceCounter((LARGE_INTEGER*) &currentTime);

m_baseTime = currentTime;
m_prevTime = currentTime;
m_stopTime = 0;
m_bStopped = false;
}

void Timer::stop()
{
//if we're already stopped we don't need to do anything
if(!m_bStopped)
{
__int64 currTime;
QueryPerformanceCounter((LARGE_INTEGER*) &currTime);

//save the time at the moment we stopped
m_stopTime = m_currTime;

m_bStopped = true;
}
}

//resume timer from a stopped state
void Timer::start()
{
__int64 startTime;
QueryPerformanceFrequency((LARGE_INTEGER*) &startTime);

//if we're resuming the timer from a stopped state we need to do a few calculations
if(m_bStopped)
{
//accumumlate paused time
m_pausedTime += (startTime - m_stopTime);

m_prevTime = startTime;

m_stopTime = 0;
m_bStopped = false;
}
}
[/source]

This number is fed into a tick() function for the objects which need to move - move() is then called to perform the actual adjustments
First I multiply the direction with the speed to get the amount of pixels we move (the direction is a normalized vector). Then I multiply this result
with the speedFactor (= secondsPerFrame) in order to adjust to the frame rate. That's the theory anyway :/
[source lang="cpp"]
void Ball::tick(const double& p_secondsPerFrame)
{
XMFLOAT2 movement;
movement.x = (m_direction.x * m_speed) * p_secondsPerFrame;
movement.y = (m_direction.y * m_speed) * p_secondsPerFrame;
move(movement);
}

void Ball::move(XMFLOAT2& p_movement)
{
if(m_bInitialized)
{
m_pHitRegion->move(p_movement);
m_pBitmap->move(p_movement);
}
}
[/source]
This is the movement itself, just an addition
[source lang="cpp"]void Sprite::move(XMFLOAT2& p_movement)
{
m_position.x += p_movement.x;
m_position.y += p_movement.y;
}[/source]

##### Share on other sites
One error may be that your position is an int, if movement is less then 1 pixel per loop, its not gonna move.

Also how much is your (m_speed), also (m_direction.x)
 movement.x = (m_direction.x * m_speed) * p_secondsPerFrame; 

I also have problems finding from where you call (void Ball::tick(const double&amp; p_secondsPerFrame)) don't know what value is passed.

Check this up http://gafferongames.com/game-physics/fix-your-timestep/ that should do. Edited by BaneTrapper

##### Share on other sites

One error may be that your position is an int, if movement is less then 1 pixel per loop, its not gonna move.

Also how much is your (m_speed), also (m_direction.x)
 movement.x = (m_direction.x * m_speed) * p_secondsPerFrame; 

I also have problems finding from where you call (void Ball::tick(const double&amp;amp; p_secondsPerFrame)) don't know what value is passed.

Check this up http://gafferongames...-your-timestep/ that should do.

Hello BaneTrapper, I didn't include that particular piece of code - here it is. (solipsistProject is basically a parentclass for all the subsystems like audio, input, etc)
[source lang="cpp"]
void SolipsistProject::tick()
{
if(m_bInitialized)
{
m_pGameTimer->tick();
m_pAudio->tick();

m_pGame->tick(m_pGameTimer->getSpf());
}
}
[/source]
this is the tick function for the game itself
[source lang="cpp"]
void PongPrototype::tick(double p_speedFactor)
{
//move balls
for(std::vector<Ball*>::iterator ballIt = m_balls.begin(); ballIt != m_balls.end(); ++ballIt)
{
if((*ballIt) != NULL)
(*ballIt)->tick(p_speedFactor);
}

//check for collisions
performCollisionChecks();

//tick bricks
for(std::vector<PowerupBrick*>::iterator brickIt = m_bricks.begin(); brickIt != m_bricks.end(); ++brickIt)
{
//brick has not yet been deleted yet and hitcounter is smaller or equal to zero
if(((*brickIt) != NULL) &amp;&amp; (*brickIt)->getHitCounter() <= 0)
{
delete (*brickIt);
(*brickIt) = 0;
}
}

}[/source]
The position is kept in an XMFLOAT2 structure so I don't think that's the problem.
During a debug attempt I came accross #INF for the movement, which I gather is because I'm mutliplying with values well below zero every frame. Edited by molehill mountaineer

##### Share on other sites
Try passing "p_speedFactor" as a float around, possible loss of information.

//time difference between this frame and the previous frame in seconds
m_deltaTime = (m_currTime - m_prevTime) * m_secondsPerCount;
[/quote]
Whats m_secondsPerCount ? and why is it there?

float dt = 0.0;
float currentTime = hires_time_in_seconds();
float lastTime;
while ( !quit )
{
dt = hires_time_in_seconds() - currentTime;
currentTime = hires_time_in_seconds();

//game related stuff
}

Read the article i posted, it will help allot fixing this problem.
You should google for , float precision, double precision, and converting then around

##### Share on other sites

Try passing "p_speedFactor" as a float around, possible loss of information.

//time difference between this frame and the previous frame in seconds
m_deltaTime = (m_currTime - m_prevTime) * m_secondsPerCount;

Whats m_secondsPerCount ? and why is it there?

float dt = 0.0;
float currentTime = hires_time_in_seconds();
float lastTime;
while ( !quit )
{
dt = hires_time_in_seconds() - currentTime;
currentTime = hires_time_in_seconds();

//game related stuff
}

Read the article i posted, it will help allot fixing this problem.
You should google for , float precision, double precision, and converting then around
[/quote]

Hello baneTrapper, sorry it took so long to reply.
m_secondsPerCount is a number used to convert the value to seconds. You can see it being initialized in the constructor for timer.

EDIT: I see that I'm confusing the meaning of deltaTime (I'm using frank luna's book and the article you provided - frameTime in the article is deltaTime in the book). I will correct this tonight and let you know if it fixed things.

EDIT2: the problem is resolved, after reading that article again I came to the conclusion that I wasn't "consuming" my frameTime (that is, I thought that deltaTime was equal to dt if you follow gaffer's example). Thanks for the help Edited by molehill mountaineer