limit loop frame rate

  • Last Update :
  • Techknowledgy :

You could just use time.sleep(1./25) to wait 1/25 of a second.

while current_frame <= max_frames:
   #...do stuff
   time.sleep(1. / 25)

Note that will will always wait that time additionally to whatever time the loop body takes anyway. Alternatively, memorize the last execution time and wait until this time + 1/25 of a second.

while current_frame <= max_frames:
   start = time.time()
#...do stuff that might take significant time
   time.sleep(max(1. / 25 - (time.time() - start), 0))

Assuming that by "natively in python" you meant using the Python standard library, the time module does provide sufficient building blocks, but it rather likely not what you want. At its core, frame rate limiting is simply waiting for the right amount of time to pass:

from time
import time, sleep

fps = 5
frameperiod = 1.0 / fps
now = time()
nextframe = now + frameperiod
for frame in range(120):
   print frame, now
while now < nextframe:
   sleep(nextframe - now)
now = time()
nextframe += frameperiod

Suggestion : 2

Why not just use the time variable passed from requestAnimationFrame, instead of var now = new Date().getTime();?:),Can I ask a quesiton? I just couldn't figure out the reason using "delta % interval" instead of "delta - interval", I think in this case they are the same, or did I miss some point? Hope someone could explain, thx.,Let's make an example to clarify: FPS = 20, interval = 50ms. tolerance = 0; Formulas: const delta = now - then; then = now - (delta % interval); thenMinus = now - (delta - interval); if (delta >= interval - tolerance),tolerance = 0.1; // RAF could call the callback a little bit earlier

return (function loop(time) {
   // again, Date.now() if it's available
   var now = new Date().getTime();
   var delta = now - then;

   if (delta > interval) {
      // Update time
      // now - (delta % interval) is an improvement over just 
      // using then = now, which can end up lowering overall fps
      then = now - (delta % interval);

      // call the fn
      requestAnimationFrame(fn);
   }
}(0));
class AnimationFrame {
   constructor(animate, fps = 60) {
      this.requestID = 0;
      this.fps = fps;
      this.animate = animate;
   }

   start() {
      let then = performance.now();
      const interval = 1000 / this.fps;

      const animateLoop = (now) => {
         this.requestID = requestAnimationFrame(animateLoop);
         const delta = now - then;

         if (delta > interval) {
            then = now - (delta % interval);
            this.animate(delta);
         }
      };
      this.requestID = requestAnimationFrame(animateLoop);
   }

   stop() {
      cancelAnimationFrame(this.requestID);
   }

}
class AnimationFrame {
   constructor(fps = 60, animate) {
      this.requestID = 0;
      this.fps = fps;
      this.animate = animate;
   }

   start() {
      let then = performance.now();
      const interval = 1000 / this.fps;
      const tolerance = 0.1;

      const animateLoop = (now) => {
         this.requestID = requestAnimationFrame(animateLoop);
         const delta = now - then;

         if (delta >= interval - tolerance) {
            then = now - (delta % interval);
            this.animate(delta);
         }
      };
      this.requestID = requestAnimationFrame(animateLoop);
   }

   stop() {
      cancelAnimationFrame(this.requestID);
   }

}

Suggestion : 3

You will usually want to cap your FPS to 60, as this is by far the most common refresh rate. This means spending 16 and 2/3 milliseconds per frame. Note that you can easily change this cap. , Otherwise, this system is used in exactly the same way as ticks. To time an interval more precisely, capture the starting and ending performance counter values. , Capping your FPS is quite simple: just subtract your frame time from your desired time and wait out the difference with SDL_Delay(). However, this function only takes delay in milliseconds—unfortunately, you cannot cap your FPS with very much precision. (At least with SDL—look at std::chrono for more.) , A common application of timing is to calculate the FPS, or frames per second, your program is running at. A frame is simply one iteration of your main game or program loop. Hence, timing it is quite straightforward: log the time at the start and end of each frame. Then, in some form output the elapsed time or its inverse (the FPS).

The most basic form of timing is SDL_GetTicks(). This function simply returns the number of ticks that have elapsed since SDL was initialized. One tick is one millisecond, a tolerable resolution for physics simulation and animation.

Uint32 ticks = SDL_GetTicks()

For example, to time an interval in ticks, simply request the time at the start and end...

Uint32 start = SDL_GetTicks();

// Do long operation

Uint32 end = SDL_GetTicks();

float secondsElapsed = (end - start) / 1000.0 f;

Otherwise, this system is used in exactly the same way as ticks. To time an interval more precisely, capture the starting and ending performance counter values.

Uint64 start = SDL_GetPerformanceCounter();

// Do some operation

Uint64 end = SDL_GetPerformanceCounter();

float secondsElapsed = (end - start) / (float) SDL_GetPerformanceFrequency();

You will usually want to cap your FPS to 60, as this is by far the most common refresh rate. This means spending 16 and 2/3 milliseconds per frame. Note that you can easily change this cap.

bool running = true;
while (running) {

   Uint64 start = SDL_GetPerformanceCounter();

   // Do event loop

   // Do physics loop

   // Do rendering loop

   Uint64 end = SDL_GetPerformanceCounter();

   float elapsedMS = (end - start) / (float) SDL_GetPerformanceFrequency() * 1000.0 f;

   // Cap to 60 FPS
   SDL_Delay(floor(16.666 f - elapsedMS));

}

To use it, you must enable VSync when creating your renderer. To do so, simply pass the flag SDL_RENDERER_PRESENTVSYNC to SDL_CreateRenderer(). Subsequent calls to SDL_RenderPresent() will wait before showing the window.

SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);