0
0
Fork 0
mirror of https://github.com/liabru/matter-js.git synced 2024-12-29 14:19:01 -05:00

improve Matter.Runner

This commit is contained in:
liabru 2024-03-17 23:04:19 +00:00
parent 442814bccf
commit 720660053c

View file

@ -22,7 +22,10 @@ var Common = require('./Common');
(function() { (function() {
Runner._maxFrameDelta = 1000 / 5;
Runner._frameDeltaFallback = 1000 / 60;
Runner._timeBufferMargin = 1.5; Runner._timeBufferMargin = 1.5;
Runner._elapsedNextEstimate = 1;
Runner._smoothingLowerBound = 0.1; Runner._smoothingLowerBound = 0.1;
Runner._smoothingUpperBound = 0.9; Runner._smoothingUpperBound = 0.9;
@ -35,7 +38,7 @@ var Common = require('./Common');
Runner.create = function(options) { Runner.create = function(options) {
var defaults = { var defaults = {
delta: 1000 / 60, delta: 1000 / 60,
frameDelta: 0, frameDelta: null,
frameDeltaSmoothing: true, frameDeltaSmoothing: true,
frameDeltaSnapping: true, frameDeltaSnapping: true,
frameDeltaHistory: [], frameDeltaHistory: [],
@ -44,18 +47,13 @@ var Common = require('./Common');
timeBuffer: 0, timeBuffer: 0,
timeLastTick: null, timeLastTick: null,
maxUpdates: null, maxUpdates: null,
maxFrameTime: 1000 / 50, maxFrameTime: 1000 / 30,
maxFrameDelta: 1000 / 10,
lastUpdatesDeferred: 0, lastUpdatesDeferred: 0,
enabled: true enabled: true
}; };
var runner = Common.extend(defaults, options); var runner = Common.extend(defaults, options);
if (runner.maxUpdates === null) {
runner.maxUpdates = Math.ceil(runner.maxFrameTime / runner.delta);
}
// for temporary back compatibility only // for temporary back compatibility only
runner.fps = 0; runner.fps = 0;
@ -66,7 +64,7 @@ var Common = require('./Common');
* Continuously updates a `Matter.Engine` on every browser frame whilst synchronising updates with the browser frame rate. * Continuously updates a `Matter.Engine` on every browser frame whilst synchronising updates with the browser frame rate.
* It is intended for development and debugging purposes inside a browser environment. * It is intended for development and debugging purposes inside a browser environment.
* This runner favours a smoother user experience over perfect time keeping. * This runner favours a smoother user experience over perfect time keeping.
* The number of updates per frame is kept within limits specified by `runner.maxFrameTime`, `runner.maxUpdates` and `runner.maxFrameDelta`. * The number of updates per frame is kept within performance budgets specified by `runner.maxFrameTime` and `runner.maxUpdates`.
* When device performance is too limited the simulation may appear to slow down compared to real time. * When device performance is too limited the simulation may appear to slow down compared to real time.
* As an alternative see `Engine.update` to directly step the engine in your own game loop implementation. * As an alternative see `Engine.update` to directly step the engine in your own game loop implementation.
* @method run * @method run
@ -76,7 +74,7 @@ var Common = require('./Common');
*/ */
Runner.run = function(runner, engine) { Runner.run = function(runner, engine) {
// initial time buffer for the first frame // initial time buffer for the first frame
runner.timeBuffer = runner.delta * Runner._timeBufferMargin; runner.timeBuffer = Runner._frameDeltaFallback;
(function onFrame(time){ (function onFrame(time){
runner.frameRequestId = Runner._onNextFrame(runner, onFrame); runner.frameRequestId = Runner._onNextFrame(runner, onFrame);
@ -106,10 +104,10 @@ var Common = require('./Common');
// find frame delta time since last call // find frame delta time since last call
var frameDelta = time - runner.timeLastTick; var frameDelta = time - runner.timeLastTick;
// fallback for unexpected frame delta values (e.g. 0, NaN or from long pauses) // fallback for unusable frame delta values (e.g. 0, NaN, on first frame or long pauses)
if (!frameDelta || frameDelta > runner.maxFrameDelta) { if (!frameDelta || !runner.timeLastTick || frameDelta > Runner._maxFrameDelta) {
// reuse last accepted frame delta or fallback to one update // reuse last accepted frame delta else fallback
frameDelta = runner.frameDelta || engineDelta; frameDelta = runner.frameDelta || Runner._frameDeltaFallback;
} }
if (runner.frameDeltaSmoothing) { if (runner.frameDeltaSmoothing) {
@ -151,8 +149,8 @@ var Common = require('./Common');
// reset count of over budget updates // reset count of over budget updates
runner.lastUpdatesDeferred = 0; runner.lastUpdatesDeferred = 0;
// get max updates per second // get max updates per frame
var maxUpdates = runner.maxUpdates; var maxUpdates = runner.maxUpdates || Math.ceil(runner.maxFrameTime / engineDelta);
// create event object // create event object
var event = { var event = {
@ -163,10 +161,10 @@ var Common = require('./Common');
Events.trigger(runner, 'beforeTick', event); Events.trigger(runner, 'beforeTick', event);
Events.trigger(runner, 'tick', event); Events.trigger(runner, 'tick', event);
var updateStartTime = Common.now();
// simulate time elapsed between calls // simulate time elapsed between calls
while (engineDelta > 0 && runner.timeBuffer >= engineDelta * Runner._timeBufferMargin) { while (engineDelta > 0 && runner.timeBuffer >= engineDelta * Runner._timeBufferMargin) {
var updateStartTime = Common.now();
// update the engine // update the engine
Events.trigger(runner, 'beforeUpdate', event); Events.trigger(runner, 'beforeUpdate', event);
Engine.update(engine, engineDelta); Engine.update(engine, engineDelta);
@ -178,10 +176,11 @@ var Common = require('./Common');
// find elapsed time during this tick // find elapsed time during this tick
var elapsedTimeTotal = Common.now() - tickStartTime, var elapsedTimeTotal = Common.now() - tickStartTime,
elapsedTimeUpdate = Common.now() - updateStartTime; elapsedTimeUpdates = Common.now() - updateStartTime,
elapsedNextEstimate = elapsedTimeTotal + Runner._elapsedNextEstimate * elapsedTimeUpdates / updateCount;
// defer updates if over performance budgets for this frame // defer updates if over performance budgets for this frame
if (updateCount >= maxUpdates || elapsedTimeTotal + elapsedTimeUpdate > runner.maxFrameTime) { if (updateCount >= maxUpdates || elapsedNextEstimate > runner.maxFrameTime) {
runner.lastUpdatesDeferred = Math.round(Math.max(0, (runner.timeBuffer / engineDelta) - Runner._timeBufferMargin)); runner.lastUpdatesDeferred = Math.round(Math.max(0, (runner.timeBuffer / engineDelta) - Runner._timeBufferMargin));
break; break;
} }
@ -235,10 +234,10 @@ var Common = require('./Common');
* @return {number} frameRequestId * @return {number} frameRequestId
*/ */
Runner._onNextFrame = function(runner, callback) { Runner._onNextFrame = function(runner, callback) {
if (typeof window !== 'undefined') { if (typeof window !== 'undefined' && window.requestAnimationFrame) {
runner.frameRequestId = window.requestAnimationFrame(callback); runner.frameRequestId = window.requestAnimationFrame(callback);
} else { } else {
Common.warnOnce('Matter.Runner: missing required global window.requestAnimationFrame.'); throw new Error('Matter.Runner: missing required global window.requestAnimationFrame.');
} }
return runner.frameRequestId; return runner.frameRequestId;
@ -251,10 +250,10 @@ var Common = require('./Common');
* @param {runner} runner * @param {runner} runner
*/ */
Runner._cancelNextFrame = function(runner) { Runner._cancelNextFrame = function(runner) {
if (typeof window !== 'undefined') { if (typeof window !== 'undefined' && window.cancelAnimationFrame) {
window.cancelAnimationFrame(runner.frameRequestId); window.cancelAnimationFrame(runner.frameRequestId);
} else { } else {
Common.warnOnce('Matter.Runner: missing required global window.cancelAnimationFrame.'); throw new Error('Matter.Runner: missing required global window.cancelAnimationFrame.');
} }
}; };
@ -384,8 +383,6 @@ var Common = require('./Common');
/** /**
* The measured time elapsed between the last two browser frames measured in milliseconds. * The measured time elapsed between the last two browser frames measured in milliseconds.
* This value is clamped inside `runner.maxFrameDelta`.
*
* You may use this to estimate the browser FPS (for the current frame) whilst running as `1000 / runner.frameDelta`. * You may use this to estimate the browser FPS (for the current frame) whilst running as `1000 / runner.frameDelta`.
* *
* @readonly * @readonly
@ -411,15 +408,6 @@ var Common = require('./Common');
* @default true * @default true
*/ */
/**
* Clamps the maximum measured `runner.frameDelta` in milliseconds.
* Therefore avoids simulating long periods measured between frames e.g. periods the thread is frozen whilst the browser has been minimised.
*
* @property maxFrameDelta
* @type number
* @default 500
*/
/** /**
* A performance budget that limits execution time allowed for this runner per display frame in milliseconds. * A performance budget that limits execution time allowed for this runner per display frame in milliseconds.
* *
@ -435,7 +423,7 @@ var Common = require('./Common');
* *
* @property maxFrameTime * @property maxFrameTime
* @type number * @type number
* @default 1000 / 50 * @default 1000 / 30
*/ */
/** /**