• Advertisement
Sign in to follow this  

Time based movement changes with std::cout

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi everybody, I'm trying to create a library to make SDL easier, but I have got stuck with a timer:

#include "timer.h"

SFrameTimer::SFrameTimer()
{
lastTick = SDL_GetTicks();
}

int SFrameTimer::tick()
{
int now = SDL_GetTicks();
int ticks = now - lastTick;
lastTick = now;
return ticks;
}





//test app

#include <iostream>
#include "sdlframe.h"

int main()
{
SFrameInitEverything();

SFrameScreen screen(640,480,32);
SFrameImage image("dot.bmp");
SDL_Event event;
SFrameTimer t;
int x = 0;
int speed = 300;
bool quit = false;

while(quit == false)
{
float distance = t.tick()/1000.;
distance *= speed;
while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
{
quit = true;
}
}
screen.fill(255,255,255);
screen.blit(x,120,image,NULL);
if(screen.flip() == false)
{
quit = true;
}
// std::cout << distance << std::endl;
x += distance;
}
SFrameCloseEverything();
return 1;
}




When I run this as is the dot move jerkily/at different speeds. If I uncomment the cout line it moves very quickly. Why is this?

Share this post


Link to post
Share on other sites
Advertisement
Most likely the speed of your code is too fast for SFrameTimer to measure, you need something more precise.


//.h
#include <windows.h>

class CStopWatch {
private:
LARGE_INTEGER start;
LARGE_INTEGER stop;
LARGE_INTEGER frequency;
public:
CStopWatch() ;
void startTimer( ) ;
void stopTimer( ) ;
double getElapsedTime() ;
};

//.cpp
CStopWatch::CStopWatch(){
start.QuadPart=0;
stop.QuadPart=0;
QueryPerformanceFrequency( &frequency ) ;
}

void CStopWatch::startTimer( ) {
QueryPerformanceCounter(&start) ;
}

void CStopWatch::stopTimer( ) {
QueryPerformanceCounter(&stop) ;
}

double CStopWatch::getElapsedTime() {
LARGE_INTEGER time;
time.QuadPart = stop.QuadPart - start.QuadPart;
return (double)time.QuadPart /(double)frequency.QuadPart;
}

//usage
CStopWatch *timer = new CStopWatch();
timer->startTimer();
while(game_is_running){
timer->stopTimer();
double elapsedTime = timer->getElapsedTime();
timer->startTimer();
//something happens
}
timer->startTimer();
delete timer;


Share this post


Link to post
Share on other sites
Thanks for the reply. I'm not on Windows so I can't use any of those function! Also, why does std::cout change the speed?

Share this post


Link to post
Share on other sites
Without cout elapsed time can be 0, with cout it can vary between 0 and x.

Also I just noticed something.
You change x at the end of frame, try doing that right after you get elapsed time:

while(quit == false)
{
float distance = (float)(t.tick() * speed) / 1000.0f;
x += distance;
std::cout << distance << std::endl;
while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
{
quit = true;
}
}
screen.fill(255,255,255);
screen.blit(x,120,image,NULL);
if(screen.flip() == false)
{
quit = true;
}
}



Edit:
Are you using Linux? I found this post which might help: http://www.gamedev.net/community/forums/topic.asp?topic_id=112732

Share this post


Link to post
Share on other sites
I am using Linux. The post said to use timeval, which doesn't seem to exists anymore...

Share this post


Link to post
Share on other sites
Well 2nd reply has this code:


#include <sys/time.h>

struct timeval startTime, endTime;
struct timezone tz;
gettimeofday(&startTime, &tz);
gettimeofday(&endTime, &tz);

startTime.tv_sec // number of seconds since some epoch
startTime.tv_usec // number of microseconds since last second.




Also first link in Google:

#include <iostream>
#include <sys/time.h> // for gettimeofday()
using namespace std;

int main()
{
timeval t1, t2;
double elapsedTime;

// start timer
gettimeofday(&t1, NULL);

// do something
...

// stop timer
gettimeofday(&t2, NULL);

// compute and print the elapsed time in millisec
elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0; // sec to ms
elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0; // us to ms
cout << elapsedTime << " ms.\n";

return 0;
}


Share this post


Link to post
Share on other sites
Sorry for the confusion, my IDE wasn't showing it with auto-complete. Should I be dividing by 1000, as when I run it now it disappears at a speed of 100

Share this post


Link to post
Share on other sites
It depends how time gets returned - in seconds, ms, ns or etc.

Share this post


Link to post
Share on other sites
std::cout, or almost any kind of output, is slow. Probably, it's taking an erratically large amount of time to complete, thus messing with your frame rate.

Share this post


Link to post
Share on other sites
The problem is that x is declared as an int. This means that when distance (float) is added to it, it is converted back to an int, thereby flooring the value. Now distance is set to milliseconds elapsed times .3 (ticks*300/1000); thus a frame must take at least 4 milliseconds if the statement "x += distance;" is to actually change the value of x. Without the std::cout, most frames will take less than one ms.

Share this post


Link to post
Share on other sites
Quote:
Original post by Chao Yun
The problem is that x is declared as an int. This means that when distance (float) is added to it, it is converted back to an int, thereby flooring the value. Now distance is set to milliseconds elapsed times .3 (ticks*300/1000); thus a frame must take at least 4 milliseconds if the statement "x += distance;" is to actually change the value of x. Without the std::cout, most frames will take less than one ms.


We have a winner.

I took the liberty of fixing this, and also some style issues in your code:


//test app

#include <iostream>
#include "sdlframe.h"

int main()
{
SFrameInitEverything();

SFrameScreen screen(640,480,32);
SFrameImage image("dot.bmp");
SDL_Event event;
SFrameTimer t;

float x = 0;
// Marking 'speed' as const doesn't really help the compiler, but it
// documents that the value won't change. Of course, once you add more
// program logic, that might no longer be the case. :)
const int speed = 300;
bool quit = false;

// Don't compare booleans to 'false' or 'true'. Think of those as just for
// initialization and assignments. Making that comparison is like padding
// your writing with extra words. It doesn't make it any clearer or easier
// to read.
while (!quit) {
// Do your calculation all at once. Breaking it up doesn't make things
// clearer. In fact, it misleads, because 't.tick()/1000.' isn't a
// distance value at all, but a time value. In fact, we can simplify
// even further, by not calculating 'distance' until we need it (at the
// end of the loop), and then observing that we don't actually need a
// variable for it at all.
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
quit = true;
}
}
screen.fill(255, 255, 255);
// Fixing the issue that was pointed out. I put in an explicit cast
// here, although it isn't really necessary.
screen.blit(int(x), 120, image, NULL);
if (!screen.flip()) {
quit = true;
}
x += t.tick() * speed / 1000.;
// This division by 1000 is a bit sketchy. You're converting from
// milliseconds to seconds, yes? why not set it up so you just call
// t.seconds() instead? :)
}
SFrameCloseEverything();
// You should use a return value of 0 to indicate a successful program run,
// not 1. The easiest way to do this is to *not* write a return statement.
// Yes, this is legal and *expected* use of C++. The main() function is a
// special case. For all other functions returning int (rather, anything
// other than void), please do return something explicitly.
}


Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement