1
\$\begingroup\$

So I've read the famous article at http://www.koonsolo.com/news/dewitters-gameloop/comment-page-2/#comments which describes different methods of implementing a game loop. I've tried to implement the final method that is described in the article in Javascript (ignoring interpolation for the time being):

var Timer = {
        pastTime : 0,
        currentTime : 0,
        started : false,
        //starts the timer
        start: function(){
            if(!this.started){
                this.started = true;
                this.pastTime = new Date().getTime();
            }
        },
        //gets the time in MILLSECONDS
        getTime: function(){
            return new Date().getTime() - this.pastTime;
        },
        //stops the timer but does not reset it (i.e. getTime() can still be     
          called to get the time between start() and end())
        end: function(){
            if(this.started){
                this.currentTime = new Date().getTime();
                this.started = false;
                return this.currentTime - this.pastTime;
            }
        },
        //resets the timer
        reset: function(){
            this.pastTime = 0;
            this.currentTime = 0;
            this.started = false;
}

var maxFrameSkip = 5;
var nextTick = new Date().getTime();
var TICKS_PER_SECOND = 25;
var tickTimeMillis = 1000 / TICKS_PER_SECOND;

var ticksPerSecondReal = 0;
var ticksCounter = 0;

var timer = Object.create(Timer);

var loops = 0;

 function gameLoop(){         
    loops = 0;          

    timer.start(); 

    while(new Date().getTime() > nextTick && loops < maxFrameSkip){
        update();  
        ticksCounter++;
        nextTick += tickTimeMillis;
        loops++;
    }

    draw();      

    if(timer.getTime() >= 1000){
        ticksPerSecondReal = ticksCounter;
        ticksCounter = 0;
        timer.reset();
    } 

    console.log(ticksPerSecondReal);   

    window.requestAnimationFrame(gameLoop);
}

 gameLoop();

So the problem that I'm having is that the console.log(ticksPerSecondReal) should always be giving me 25 because that's the constant ticks per second that I want and have set up. What I end up getting is an alternating number that is 25 and 26. So periodically (~1 second) it will be 25 and then 26 and then 25 and so on. And sometimes (much less frequently) it will even give a result of 27. It keeps switching back and forth when it should be constant at 25. What is the issue here?

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Not sure i (bother to :-)) understand your code, but i'd like to point out that accumulated time will never be accurate on the long term. If it is crucial that you have consumed exactly 2500 frames in 100 seconds, you likely cannot rely on exact sum of the individual frames.

Instead you must make it "absolute". If you require 25 ms per frame, you know for sure that the trigger times for the 20 first frames are

0 0.04 0.08 0.12 0.16 0.2 0.24 0.28 0.32 0.36 0.4 0.44 0.48 0.52 0.56 0.6 0.64 0.68 0.72 0.76

Do not expect the sum of your frame times to be an exact multiple of 0.04 any longer after 1000 frames, after always having delayed the loop cycle relatively. It will diverge.

Instead implement a system where you always check the clock time (DateTime, whatever) against a pre-generated "next trigger time". Ie. if your next frame is the 11th frame, calculate 11*0.04 (which is 0.44) and sit somewhere and compare current time against 0.44. When current time exceeds 0.44, paint the frame, and then next time sit and wait for currenttime to exceed 0.48. And so on.

n*0.04 will be an accurate value even if n is 100000.

\$\endgroup\$
0
\$\begingroup\$

You should move the call of timer.start() to be before your call of gameLoop(). You should also make a call to it right after the call of timer.reset().

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .