Permalink
Browse files

Clock override WIP

  • Loading branch information...
1 parent e4cf00d commit 0e3a559bcf09e67087b8ae6b833cd1be28958f20 @izb committed May 30, 2013
Showing with 125 additions and 31 deletions.
  1. +13 −7 src/map/staggered-isometric.js
  2. +30 −12 src/polyfills/requestAnimationFrame.js
  3. +27 −11 src/snaps.js
  4. +11 −0 src/sprites/sprite.js
  5. +3 −1 src/util/all.js
  6. +41 −0 src/util/clock.js
@@ -1,5 +1,11 @@
/*global define*/
-define(['map/tile', 'util/bitmap', 'util/debug', 'util/js'], function(Tile, Bitmap, debug, js) {
+define(['map/tile',
+ 'util/bitmap',
+ 'util/debug',
+ 'util/js',
+ 'util/clock'],
+
+function(Tile, Bitmap, debug, js, clock) {
'use strict';
@@ -570,15 +576,15 @@ define(['map/tile', 'util/bitmap', 'util/debug', 'util/js'], function(Tile, Bitm
* @private
*/
StaggeredIsometric.prototype.updateLayers = function(now) {
- var epoch = +new Date();
+ var epoch = clock.now();
var map = this.data;
for (var i = 0; i < map.layers.length; i++) {
var l = map.layers[i];
if (l.hasOwnProperty('update')) {
l.update(now);
}
}
- this.stats.count('updateLayers', (+new Date())-epoch);
+ this.stats.count('updateLayers', clock.now()-epoch);
};
/** Finds the index of the ground layer.
@@ -633,7 +639,7 @@ define(['map/tile', 'util/bitmap', 'util/debug', 'util/js'], function(Tile, Bitm
var startx = Math.floor((this.xoffset+this.clientWidth -1 ) / xstep);
var endx = Math.floor((this.xoffset-xstep/2-this.maxXOverdraw) / xstep);
- epoch = +new Date();
+ epoch = clock.now();
/* Sort sprites first by y-axis, then by height, then creation order */
/* TODO: Cull off-screen sprites first? */
sprites.sort(function(a, b) {
@@ -644,10 +650,10 @@ define(['map/tile', 'util/bitmap', 'util/debug', 'util/js'], function(Tile, Bitm
n = a.h - b.h;
return n!==0?n:a.nuid - b.nuid;
});
- this.stats.count('spriteSort', (+new Date())-epoch);
+ this.stats.count('spriteSort', clock.now()-epoch);
- epoch = +new Date();
+ epoch = clock.now();
var spriteCursor = 0;
var stagger = 0;
var x, y, r, l, i, layerEndY, layerEndX;
@@ -689,7 +695,7 @@ define(['map/tile', 'util/bitmap', 'util/debug', 'util/js'], function(Tile, Bitm
}
}
}
- this.stats.count('paintWorld', (+new Date())-epoch);
+ this.stats.count('paintWorld', clock.now()-epoch);
};
return StaggeredIsometric;
@@ -1,5 +1,5 @@
/*global define*/
-define(function() {
+define(['util/clock'], function(clock) {
'use strict';
@@ -16,6 +16,23 @@ define(function() {
// requestAnimationFrame polyfill by Erik Möller
// fixes from Paul Irish and Tino Zijdel
+ var fixRequestAnimationFrame = function() {
+ window.requestAnimationFrame = function(callback, element) {
+ var currTime = clock.now();
+ var timeToCall = Math.max(0, 16 - (currTime - lastTime));
+ var id = window.setTimeout(function() { callback(currTime + timeToCall); },
+ timeToCall);
+ lastTime = currTime + timeToCall;
+ return id;
+ };
+ };
+
+ var fixCancelAnimationFrame = function() {
+ window.cancelAnimationFrame = function(id) {
+ clearTimeout(id);
+ };
+ };
+
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
@@ -25,20 +42,21 @@ define(function() {
}
if (!window.requestAnimationFrame) {
- window.requestAnimationFrame = function(callback, element) {
- var currTime = new Date().getTime();
- var timeToCall = Math.max(0, 16 - (currTime - lastTime));
- var id = window.setTimeout(function() { callback(currTime + timeToCall); },
- timeToCall);
- lastTime = currTime + timeToCall;
- return id;
- };
+ fixRequestAnimationFrame();
}
if (!window.cancelAnimationFrame) {
- window.cancelAnimationFrame = function(id) {
- clearTimeout(id);
- };
+ fixCancelAnimationFrame();
}
+ /**
+ * Overrides the clock and requestAnimationFrame to allow predictable timings
+ * in unit tests.
+ * @function module:polyfills/requestAnimationFrame#overrideClock
+ */
+ return function() {
+ clock.fixedOutput();
+ fixRequestAnimationFrame();
+ fixCancelAnimationFrame();
+ };
});
View
@@ -17,14 +17,18 @@ define(['sprites/spritedef', 'sprites/sprite', 'sprites/composite',
'ai/proximity-tracker',
'ai/pathfinder',
+ /* Testing */
+ 'polyfills/requestAnimationFrame',
+
/* Non-referenced */
- 'polyfills/requestAnimationFrame', 'polyfills/bind'],
+ 'polyfills/bind'],
function(SpriteDef, Sprite, Composite, Keyboard, Mouse, util, StaggeredIsometric,
regPlugins,
SlowQueue,
tweens,
- ProximityTracker, PathFinder) {
+ ProximityTracker, PathFinder,
+ overrideClock) {
/*
* TODO: https://github.com/izb/snaps.js/wiki/Todo
@@ -44,6 +48,7 @@ function(SpriteDef, Sprite, Composite, Keyboard, Mouse, util, StaggeredIsometric
var MinHeap = util.MinHeap;
var uid = util.uid;
var Stats = util.Stats;
+ var clock = util.clock;
/**
* The main class of the game engine
@@ -363,38 +368,38 @@ function(SpriteDef, Sprite, Composite, Keyboard, Mouse, util, StaggeredIsometric
* @private
*/
this.updateTasks = function() {
- var epoch = +new Date();
+ var epoch = clock.now();
for (var i = _this.taskQueues.length - 1; i >= 0; i--) {
_this.taskQueues[i].run();
}
- this.stats.count('updateTasks', (+new Date())-epoch);
+ this.stats.count('updateTasks', clock.now()-epoch);
};
/**
* @method module:snaps.Snaps#updatePhasers
* @private
*/
this.updatePhasers = function() {
- var epoch = +new Date();
+ var epoch = clock.now();
for (var i = _this.phasers.length - 1; i >= 0; i--) {
_this.phasers[i].rebalance(_this.now);
}
- this.stats.count('updatePhasers', (+new Date())-epoch);
+ this.stats.count('updatePhasers', clock.now()-epoch);
};
/**
* @method module:snaps.Snaps#updateFX
* @private
*/
this.updateFX = function() {
- var epoch = +new Date();
+ var epoch = clock.now();
for (var i = _this.activeFX.length - 1; i >= 0; i--) {
var fx = _this.activeFX[i];
if (!fx.update(_this.now)) {
_this.activeFX.splice(i, 1);
}
}
- this.stats.count('updateFX', (+new Date())-epoch);
+ this.stats.count('updateFX', clock.now()-epoch);
};
/**
@@ -529,7 +534,8 @@ function(SpriteDef, Sprite, Composite, Keyboard, Mouse, util, StaggeredIsometric
}
/* Start the paint loop */
- this.halt = false;
+ _this.halt = false;
+ _this.overrideClock();
setTimeout(function(){loop(0);}, 0);
},
@@ -907,7 +913,7 @@ function(SpriteDef, Sprite, Composite, Keyboard, Mouse, util, StaggeredIsometric
* @private
*/
this.updateSprites = function() {
- var epoch = +new Date();
+ var epoch = clock.now();
var keepsprites = [];
var i, s;
for ( i = _this.sprites.length - 1; i >= 0; i--) {
@@ -929,7 +935,7 @@ function(SpriteDef, Sprite, Composite, Keyboard, Mouse, util, StaggeredIsometric
s = _this.sprites[i];
s.commit(_this.now);
}
- this.stats.count('updateSprites', (+new Date())-epoch);
+ this.stats.count('updateSprites', clock.now()-epoch);
};
/**
@@ -942,6 +948,16 @@ function(SpriteDef, Sprite, Composite, Keyboard, Mouse, util, StaggeredIsometric
};
/**
+ * Overrides the clock in order to create predictable frame timings in
+ * unit tests.
+ * @method module:snaps.Snaps#overrideClock
+ * @private
+ */
+ this.overrideClock = function() {
+ overrideClock();
+ };
+
+ /**
* Spawn a new phaser for use in sprite updates
* @method module:snaps.Snaps#createPhaser
* @param {String} name The name of the phaser plugin to instantiate.
View
@@ -257,6 +257,17 @@ define(['util/js'], function(js) {
this.setState(state, ext, now - this.state.dur * this.state.jogPos(this.epoch, now));
};
+ /** Sets the position in the current state's animation. E.g. set to 0.5 to place the
+ * jog position halfway through the sprite's current animation.
+ * @method module:sprites/sprite.Sprite#setJog
+ * @param {Number} pos A jog position from 0 to 1.
+ */
+ Sprite.prototype.setJog = function(pos) {
+ /* TODO: Validate value? */
+ var now = this.sn.getNow();
+ this.epoch = now - this.state.dur * pos;
+ };
+
/**
* @private
* @method module:sprites/sprite.Sprite#update
View
@@ -8,8 +8,9 @@ define([
'util/minheap',
'util/stats',
'util/uid',
+ 'util/clock',
'util/url'],
-function(Preloader, rnd, Bitmap, debug, js, MinHeap, Stats, uid, Url) {
+function(Preloader, rnd, Bitmap, debug, js, MinHeap, Stats, uid, clock, Url) {
'use strict';
@@ -25,6 +26,7 @@ function(Preloader, rnd, Bitmap, debug, js, MinHeap, Stats, uid, Url) {
MinHeap: MinHeap,
Stats: Stats,
uid: uid,
+ clock: clock,
debug: debug,
Bitmap: Bitmap,
Url: Url
View
@@ -0,0 +1,41 @@
+/*global define*/
+define(function() {
+
+ 'use strict';
+
+ /**
+ * @module util/clock
+ */
+
+ /**
+ * Construct a clock.
+ * @constructor module:util/clock.Clock
+ * @private
+ */
+ function Clock() {
+ }
+
+ /**
+ * Gets the current time.
+ * @function module:util/clock#now
+ * @return {Number} The current time as a millisecond timer value.
+ */
+ Clock.prototype.now = function() {
+ return +new Date();
+ };
+
+ /**
+ * Fixes the output of the clock to predictable values to aid unit testing.
+ * @function module:util/clock#fix
+ * @private
+ */
+ Clock.prototype.fixedOutput = function() {
+ this.now = function() {
+ /* TODO */
+ return +new Date();
+ };
+ };
+
+
+ return new Clock();
+});

0 comments on commit 0e3a559

Please sign in to comment.