UNPKG

phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers.

270 lines (226 loc) 8.72 kB
/** * The `Matter.Runner` module is an optional utility which provides a game loop, * that handles continuously updating a `Matter.Engine` for you within a browser. * It is intended for development and debugging purposes, but may also be suitable for simple games. * If you are using your own game loop instead, then you do not need the `Matter.Runner` module. * Instead just call `Engine.update(engine, delta)` in your own loop. * * See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples). * * @class Runner */ var Runner = {}; module.exports = Runner; var Events = require('./Events'); var Engine = require('./Engine'); var Common = require('./Common'); (function() { var _requestAnimationFrame, _cancelAnimationFrame; if (typeof window !== 'undefined') { _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame; _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame; } if (!_requestAnimationFrame) { var _frameTimeout; _requestAnimationFrame = function(callback){ _frameTimeout = setTimeout(function() { callback(Common.now()); }, 1000 / 60); }; _cancelAnimationFrame = function() { clearTimeout(_frameTimeout); }; } /** * Creates a new Runner. The options parameter is an object that specifies any properties you wish to override the defaults. * @method create * @param {} options */ Runner.create = function(options) { var defaults = { fps: 60, deltaSampleSize: 60, counterTimestamp: 0, frameCounter: 0, deltaHistory: [], timePrev: null, frameRequestId: null, isFixed: false, enabled: true }; var runner = Common.extend(defaults, options); runner.delta = runner.delta || 1000 / runner.fps; runner.deltaMin = runner.deltaMin || 1000 / runner.fps; runner.deltaMax = runner.deltaMax || 1000 / (runner.fps * 0.5); runner.fps = 1000 / runner.delta; return runner; }; /** * Continuously ticks a `Matter.Engine` by calling `Runner.tick` on the `requestAnimationFrame` event. * @method run * @param {engine} engine */ Runner.run = function(runner, engine) { // create runner if engine is first argument if (typeof runner.positionIterations !== 'undefined') { engine = runner; runner = Runner.create(); } (function run(time){ runner.frameRequestId = _requestAnimationFrame(run); if (time && runner.enabled) { Runner.tick(runner, engine, time); } })(); return runner; }; /** * A game loop utility that updates the engine and renderer by one step (a 'tick'). * Features delta smoothing, time correction and fixed or dynamic timing. * Consider just `Engine.update(engine, delta)` if you're using your own loop. * @method tick * @param {runner} runner * @param {engine} engine * @param {number} time */ Runner.tick = function(runner, engine, time) { var timing = engine.timing, delta; if (runner.isFixed) { // fixed timestep delta = runner.delta; } else { // dynamic timestep based on wall clock between calls delta = (time - runner.timePrev) || runner.delta; runner.timePrev = time; // optimistically filter delta over a few frames, to improve stability runner.deltaHistory.push(delta); runner.deltaHistory = runner.deltaHistory.slice(-runner.deltaSampleSize); delta = Math.min.apply(null, runner.deltaHistory); // limit delta delta = delta < runner.deltaMin ? runner.deltaMin : delta; delta = delta > runner.deltaMax ? runner.deltaMax : delta; // update engine timing object runner.delta = delta; } // create an event object var event = { timestamp: timing.timestamp }; Events.trigger(runner, 'beforeTick', event); // fps counter runner.frameCounter += 1; if (time - runner.counterTimestamp >= 1000) { runner.fps = runner.frameCounter * ((time - runner.counterTimestamp) / 1000); runner.counterTimestamp = time; runner.frameCounter = 0; } Events.trigger(runner, 'tick', event); // update Events.trigger(runner, 'beforeUpdate', event); Engine.update(engine, delta); Events.trigger(runner, 'afterUpdate', event); Events.trigger(runner, 'afterTick', event); }; /** * Ends execution of `Runner.run` on the given `runner`, by canceling the animation frame request event loop. * If you wish to only temporarily pause the engine, see `engine.enabled` instead. * @method stop * @param {runner} runner */ Runner.stop = function(runner) { _cancelAnimationFrame(runner.frameRequestId); }; /** * Alias for `Runner.run`. * @method start * @param {runner} runner * @param {engine} engine */ Runner.start = function(runner, engine) { Runner.run(runner, engine); }; /* * * Events Documentation * */ /** * Fired at the start of a tick, before any updates to the engine or timing * * @event beforeTick * @param {} event An event object * @param {number} event.timestamp The engine.timing.timestamp of the event * @param {} event.source The source object of the event * @param {} event.name The name of the event */ /** * Fired after engine timing updated, but just before update * * @event tick * @param {} event An event object * @param {number} event.timestamp The engine.timing.timestamp of the event * @param {} event.source The source object of the event * @param {} event.name The name of the event */ /** * Fired at the end of a tick, after engine update and after rendering * * @event afterTick * @param {} event An event object * @param {number} event.timestamp The engine.timing.timestamp of the event * @param {} event.source The source object of the event * @param {} event.name The name of the event */ /** * Fired before update * * @event beforeUpdate * @param {} event An event object * @param {number} event.timestamp The engine.timing.timestamp of the event * @param {} event.source The source object of the event * @param {} event.name The name of the event */ /** * Fired after update * * @event afterUpdate * @param {} event An event object * @param {number} event.timestamp The engine.timing.timestamp of the event * @param {} event.source The source object of the event * @param {} event.name The name of the event */ /* * * Properties Documentation * */ /** * A flag that specifies whether the runner is running or not. * * @property enabled * @type boolean * @default true */ /** * A `Boolean` that specifies if the runner should use a fixed timestep (otherwise it is variable). * If timing is fixed, then the apparent simulation speed will change depending on the frame rate (but behaviour will be deterministic). * If the timing is variable, then the apparent simulation speed will be constant (approximately, but at the cost of determininism). * * @property isFixed * @type boolean * @default false */ /** * A `Number` that specifies the time step between updates in milliseconds. * If `engine.timing.isFixed` is set to `true`, then `delta` is fixed. * If it is `false`, then `delta` can dynamically change to maintain the correct apparent simulation speed. * * @property delta * @type number * @default 1000 / 60 */ })();