Вопрос

How should I update the canvas I created in HTML using Dart so that the game I'm creating runs at an 'x' number of FPS?

Это было полезно?

Решение

To control the frame rate of your game :

  • Use requestAnimationFrame (in window lib).
  • measure the time between two calls.
  • drop the frame if actual frame rate is too high.
  • consider just one frame elapsed if too much time elapsed since last frame. This happens if game was tabbed out / application set idle by the OS.

requestAnimationFrame(callback) will fire the callback right when the Browser is ready to draw.
So it will fire all full fps rate of the screen (provided your draws/computations do not take too much time). The callback takes a time argument which, depending on Browser, is the current time in high resolution (Dart VM, Chrome js) or low resolution (FF, Sf).

The only choice you have about frame rate is to have a frame rate lower or equal to the screen's.
So if, say, you want a 25Hz one, and you are on a 50Hz screen, then by dropping one frame over two you'll be at 25Hz. Fine.
But if you ask for 25Hz in a 60Hz screen, 30 fps is still too high, so you'll get 15 fps most of the time.
( Maybe a good idea would be not limit the fps to a constant, but rather compute the ratio that is required for your desired fps ( 1/2 or 1/3 or even 1/4th or more for >=100Hz screen ).

Anyway here's a game loop that will control the fps of your game (with constant limit), and that handles game time, meaning the time that elapsed for your game (which will differ from real time if the user tabs out, which stops requestAnimationFrame as well as timers.) :

class Game {

   num gameTime = 0 ; // actual time elapsed within game since game started.

   num minFrameTime = 20 ; // limit to 50 fps. 

   num maxFrameTime = 200 ; // consider game was tabbed out after 200ms

   num get currentFrameRate => (_lastdt == 0) ? -1 : 1000 / _lastdt ;  

   void launchAnimation() {
        window.requestAnimationFrame(_getAnimateTime);     
    }

   void _animate(num animateCallTime) {
       window.requestAnimationFrame(_animate); // keep animating.
       // ---- time handling
       num dt = animateCallTime - _lastAnimateTime ; // time elapsed since last frame.
       if (dt<minFrameTime) return; // frame rate too high, drop this frame.
       if (dt>maxFrameTime) dt = minFrameTime ; // consider just one frame elapsed if game tabbed out.
       gameTime += dt ;
       _lastdt = dt ;
       _lastAnimateTime = animateCallTime ;
       // ---- actual animation 
       // draw :  must be done first (we're on sync with screen)

       // update
   }

   void _getAnimateTime(num animateCallTime) { 
       _lastAnimateTime = animateCallTime ; // now we have start time with right resolution
       window.requestAnimationFrame(_animate); // start animating
   }

   num _lastAnimateTime = 0;

   num _lastdt = 0; // last valid frame duration.
 }

Rq : I'd recommend limiting to 60 fps for Desktop, 30 fps for mobile.
Rq2 : the code above is in fact a stripped down version of the game loop i use, which is like 3 times bigger, to adress 'all' issues of an animation loop (all... or at least the ones i saw :-) ).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top