Frame independent movement - problem calculating speedFactor
#1 Members - Reputation: 173
Posted 05 December 2012 - 01:48 PM
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*) ¤tTime); 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*) ¤tTime); 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 statevoid 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]
Thanks for reading.
#2 Members - Reputation: 645
Posted 05 December 2012 - 05:13 PM
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& 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, 05 December 2012 - 05:13 PM.
Current projects:
The Wanderer, 2d turn based rpg style game
www.gamedev.net/topic/641117-check-up-the-wanderer/
#3 Members - Reputation: 173
Posted 06 December 2012 - 03:34 AM
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...-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); } m_pPlayerPaddle->tick(p_speedFactor); m_pEnemyPaddle->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) && (*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, 06 December 2012 - 03:35 AM.
#4 Members - Reputation: 645
Posted 06 December 2012 - 05:36 AM
Whats m_secondsPerCount ? and why is it there?//time difference between this frame and the previous frame in seconds
m_deltaTime = (m_currTime - m_prevTime) * m_secondsPerCount;
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
Current projects:
The Wanderer, 2d turn based rpg style game
www.gamedev.net/topic/641117-check-up-the-wanderer/
#5 Members - Reputation: 173
Posted 12 December 2012 - 07:12 AM
Try passing "p_speedFactor" as a float around, possible loss of information.
Whats m_secondsPerCount ? and why is it there?
//time difference between this frame and the previous frame in seconds
m_deltaTime = (m_currTime - m_prevTime) * m_secondsPerCount;
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
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, 12 December 2012 - 03:45 PM.






