Dart Documentationgame_loopGameLoop

GameLoop class

The game loop

class GameLoop {
 final Element element;
 bool _initialized = false;
 bool _interrupt = false;
 int _frameCounter = 0;
 double _previousFrameTime;
 double _frameTime = 0.0;

 /** The time step used for game updates. */
 double updateTimeStep = 0.015;

 /** Maximum amount of time between subsequent request animation frame
  * calls that is accumulated. Accumulated time is used to drive onUpdate
  * calls.
  */
 double maxAccumulatedTime = 0.03;
 double _accumulatedTime = 0.0;
 /** Seconds of accumulated time. */
 double get accumulatedTime => _accumulatedTime;
 /** Width of game display [Element] */
 int get width => element.clientWidth;
 /** Height of game display [Element] */
 int get height => element.clientHeight;

 /** Frame counter value. Incremented once per frame. */
 int get frame => _frameCounter;
 /** Current time as seen by onUpdate calls. */
 double get gameTime => _gameTime;
 double _gameTime = 0.0;
 /** Seconds between requestAnimationFrameTime calls. */
 double get requestAnimationFrameTime => _frameTime;
 /** Time elapsed in current frame. */
 double get dt => updateTimeStep;
 double _renderInterpolationFactor = 0.0;
 /** Interpolation value between 0.0 and 1.0 */
 double get renderInterpolationFactor => _renderInterpolationFactor;
 static double timeStampToSeconds(timeStamp) => timeStamp / 1000.0;
 static double milliseconds(int x) => x / 1000.0;
 static double seconds(int x) => x.toDouble();
 static double minutes(int x) => x.toDouble() * 60.0;

 /** Current time. */
 double get time => timeStampToSeconds(new Date.now().millisecondsSinceEpoch);

 GameLoopPointerLock _pointerLock;
 GameLoopPointerLock get pointerLock => _pointerLock;

 GameLoopKeyboard _keyboard;
 /** Keyboard. */
 GameLoopKeyboard get keyboard => _keyboard;
 GameLoopMouse _mouse;
 /** Mouse. */
 GameLoopMouse get mouse => _mouse;
 GameLoopGamepad _gamepad0;
 /** Gamepad #0. */
 GameLoopGamepad get gamepad0 => _gamepad0;

 /** Construct a new game loop attaching it to [element] */
 GameLoop(this.element) {
   _keyboard = new GameLoopKeyboard(this);
   _mouse = new GameLoopMouse(this);
   _gamepad0 = new GameLoopGamepad(this);
   _pointerLock = new GameLoopPointerLock(this);
 }

 void _processInputEvents() {
   for (KeyboardEvent keyboardEvent in _keyboardEvents) {
     GameLoopDigitalButtonEvent event;
     bool down = keyboardEvent.type == "keydown";
     double time = timeStampToSeconds(keyboardEvent.timeStamp);
     int buttonId = keyboardEvent.keyCode;
     event = new GameLoopDigitalButtonEvent(buttonId, down, frame, time);
     _keyboard.digitalButtonEvent(event);
   }
   _keyboardEvents.clear();
   mouse._resetAccumulators();
   for (MouseEvent mouseEvent in _mouseEvents) {
     bool moveEvent = mouseEvent.type == 'mousemove';
     bool down = mouseEvent.type == 'mousedown';
     double time = timeStampToSeconds(mouseEvent.timeStamp);
     if (moveEvent) {
       int x = mouseEvent.offsetX;
       int y = mouseEvent.offsetY;
       int dx = mouseEvent.webkitMovementX;
       int dy = mouseEvent.webkitMovementY;
       GameLoopMouseEvent event = new GameLoopMouseEvent(x, y, dx, dy,
                                                         time, frame);
       _mouse.gameLoopMouseEvent(event);
     } else {
       GameLoopDigitalButtonEvent event;
       int buttonId = mouseEvent.button;
       event = new GameLoopDigitalButtonEvent(buttonId, down, frame, time);
       _mouse.digitalButtonEvent(event);
     }
   }
   _mouseEvents.clear();
 }

 void _processTimers() {
   for (GameLoopTimer timer in _timers) {
     timer._update(dt);
   }
   for (int i = _timers.length-1; i >= 0; i--) {
     int lastElement = _timers.length-1;
     if (_timers[i]._dead) {
       if (i != lastElement) {
         // Swap into i's place.
         _timers[i] = _timers[lastElement];
       }
       _timers.removeLast();
     }
   }
 }

 void _requestAnimationFrame(num _) {
   if (_previousFrameTime == null) {
     _frameTime = time;
     _previousFrameTime = _frameTime;
     _processInputEvents();
     window.requestAnimationFrame(_requestAnimationFrame);
     return;
   }
   if (_interrupt == true) {
     return;
   }
   window.requestAnimationFrame(_requestAnimationFrame);
   _frameCounter++;
   _previousFrameTime = _frameTime;
   _frameTime = time;
   double timeDelta = _frameTime - _previousFrameTime;
   _accumulatedTime += timeDelta;
   if (_accumulatedTime > maxAccumulatedTime) {
     // If the animation frame callback was paused we may end up with
     // a huge time delta. Clamp it to something reasonable.
     _accumulatedTime = maxAccumulatedTime;
   }
   // TODO(johnmccutchan): Process input events in update loop.
   _processInputEvents();
   while (_accumulatedTime >= updateTimeStep) {
     _processTimers();
     _gameTime += updateTimeStep;
     if (onUpdate != null) {
       onUpdate(this);
     }
     _accumulatedTime -= updateTimeStep;
   }
   if (onRender != null) {
     double interpolationValue = _accumulatedTime/updateTimeStep;
     onRender(this);
   }
 }

 void _fullscreenChange(Event _) {
   if (onFullscreenChange == null) {
     return;
   }
   onFullscreenChange(this);
 }

 void _fullscreenError(Event _) {
   if (onFullscreenChange == null) {
     return;
   }
   onFullscreenChange(this);
 }

 final List<KeyboardEvent> _keyboardEvents = new List<KeyboardEvent>();
 void _keyDown(KeyboardEvent event) {
   _keyboardEvents.add(event);
 }

 void _keyUp(KeyboardEvent event) {
   _keyboardEvents.add(event);
 }

 final List<MouseEvent> _mouseEvents = new List<MouseEvent>();
 void _mouseDown(MouseEvent event) {
   _mouseEvents.add(event);
 }

 void _mouseUp(MouseEvent event) {
   _mouseEvents.add(event);
 }

 void _mouseMove(MouseEvent event) {
   _mouseEvents.add(event);
 }

 void _resize(Event _) {
   if (onResize != null) {
     onResize(this);
   }
 }

 /** Start the game loop. */
 void start() {
   if (_initialized == false) {
     document.onFullscreenError.listen(_fullscreenError);
     document.onFullscreenChange.listen(_fullscreenChange);
     window.onKeyDown.listen(_keyDown);
     window.onKeyUp.listen(_keyUp);
     window.onResize.listen(_resize);
     element.onMouseMove.listen(_mouseMove);
     element.onMouseDown.listen(_mouseDown);
     element.onMouseUp.listen(_mouseUp);
     _initialized = true;
   }
   _interrupt = false;
   window.requestAnimationFrame(_requestAnimationFrame);
 }

 /** Stop the game loop. */
 void stop() {
   _interrupt = true;
 }

 /** Is the element being displayed full screen? */
 bool get isFullscreen => document.webkitFullscreenElement == element;

 /** Enable or disable fullscreen display of the element. */
 void enableFullscreen(bool enable) {
   if (enable) {
     element.webkitRequestFullscreen();
     return;
   }
   document.webkitExitFullscreen();
 }

 final List<GameLoopTimer> _timers = new List<GameLoopTimer>();

 /** Add a new timer which calls [callback] in [delay] seconds. */
 GameLoopTimer addTimer(GameLoopTimerFunction callback, double delay) {
   GameLoopTimer timer = new GameLoopTimer._internal(this, delay, callback);
   _timers.add(timer);
   return timer;
 }

 /** Clear all existing timers. */
 void clearTimers() {
   _timers.clear();
 }

 /** Called once per game logic frame. */
 GameLoopUpdateFunction onUpdate;
 /** Called when it is time to draw. */
 GameLoopRenderFunction onRender;
 /** Called when element is resized. */
 GameLoopResizeFunction onResize;
 /** Called when element enters or exits fullscreen mode. */
 GameLoopFullscreenChangeFunction onFullscreenChange;
 /** Called when the element moves between owning and not
  *  owning the pointer.
  */
 GameLoopPointerLockChangeFunction onPointerLockChange;
}

Static Methods

double timeStampToSeconds(timeStamp) #

static double timeStampToSeconds(timeStamp) => timeStamp / 1000.0;

double milliseconds(int x) #

static double milliseconds(int x) => x / 1000.0;

double seconds(int x) #

static double seconds(int x) => x.toDouble();

double minutes(int x) #

static double minutes(int x) => x.toDouble() * 60.0;

Constructors

new GameLoop(Element element) #

Construct a new game loop attaching it to element

GameLoop(this.element) {
 _keyboard = new GameLoopKeyboard(this);
 _mouse = new GameLoopMouse(this);
 _gamepad0 = new GameLoopGamepad(this);
 _pointerLock = new GameLoopPointerLock(this);
}

Properties

final double accumulatedTime #

Seconds of accumulated time.

double get accumulatedTime => _accumulatedTime;

final double dt #

Time elapsed in current frame.

double get dt => updateTimeStep;

final Element element #

element

final int frame #

Frame counter value. Incremented once per frame.

int get frame => _frameCounter;

final GameLoopGamepad gamepad0 #

Gamepad #0.

GameLoopGamepad get gamepad0 => _gamepad0;

final double gameTime #

Current time as seen by onUpdate calls.

double get gameTime => _gameTime;

final int height #

Height of game display Element

int get height => element.clientHeight;

final bool isFullscreen #

Is the element being displayed full screen?

bool get isFullscreen => document.webkitFullscreenElement == element;

final GameLoopKeyboard keyboard #

Keyboard.

GameLoopKeyboard get keyboard => _keyboard;

double maxAccumulatedTime #

maxAccumulatedTime = 0.03

final GameLoopMouse mouse #

Mouse.

GameLoopMouse get mouse => _mouse;

GameLoopFullscreenChangeFunction onFullscreenChange #

onFullscreenChange

GameLoopPointerLockChangeFunction onPointerLockChange #

onPointerLockChange

GameLoopRenderFunction onRender #

onRender

GameLoopResizeFunction onResize #

onResize

GameLoopUpdateFunction onUpdate #

onUpdate

final GameLoopPointerLock pointerLock #

GameLoopPointerLock get pointerLock => _pointerLock;

final double renderInterpolationFactor #

Interpolation value between 0.0 and 1.0

double get renderInterpolationFactor => _renderInterpolationFactor;

final double requestAnimationFrameTime #

Seconds between requestAnimationFrameTime calls.

double get requestAnimationFrameTime => _frameTime;

final double time #

Current time.

double get time => timeStampToSeconds(new Date.now().millisecondsSinceEpoch);

double updateTimeStep #

updateTimeStep = 0.015

final int width #

Width of game display Element

int get width => element.clientWidth;

Methods

GameLoopTimer addTimer(GameLoopTimerFunction callback, double delay) #

Add a new timer which calls callback in delay seconds.

GameLoopTimer addTimer(GameLoopTimerFunction callback, double delay) {
 GameLoopTimer timer = new GameLoopTimer._internal(this, delay, callback);
 _timers.add(timer);
 return timer;
}

void clearTimers() #

Clear all existing timers.

void clearTimers() {
 _timers.clear();
}

void enableFullscreen(bool enable) #

Enable or disable fullscreen display of the element.

void enableFullscreen(bool enable) {
 if (enable) {
   element.webkitRequestFullscreen();
   return;
 }
 document.webkitExitFullscreen();
}

void start() #

Start the game loop.

void start() {
 if (_initialized == false) {
   document.onFullscreenError.listen(_fullscreenError);
   document.onFullscreenChange.listen(_fullscreenChange);
   window.onKeyDown.listen(_keyDown);
   window.onKeyUp.listen(_keyUp);
   window.onResize.listen(_resize);
   element.onMouseMove.listen(_mouseMove);
   element.onMouseDown.listen(_mouseDown);
   element.onMouseUp.listen(_mouseUp);
   _initialized = true;
 }
 _interrupt = false;
 window.requestAnimationFrame(_requestAnimationFrame);
}

void stop() #

Stop the game loop.

void stop() {
 _interrupt = true;
}