summaryrefslogtreecommitdiff
path: root/jaws/src/game_loop.js
diff options
context:
space:
mode:
Diffstat (limited to 'jaws/src/game_loop.js')
-rwxr-xr-xjaws/src/game_loop.js135
1 files changed, 135 insertions, 0 deletions
diff --git a/jaws/src/game_loop.js b/jaws/src/game_loop.js
new file mode 100755
index 0000000..aa773e5
--- /dev/null
+++ b/jaws/src/game_loop.js
@@ -0,0 +1,135 @@
+if(typeof require !== "undefined") { var jaws = require("./core.js"); }
+
+var jaws = (function(jaws) {
+
+// requestAnim shim layer by Paul Irish
+window.requestAnimFrame = (function(){
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(/* function */ callback, /* DOMElement */ element){
+ window.setTimeout(callback, 16.666);
+ };
+})();
+
+/**
+ * @class A classic game loop forever looping calls to update() / draw() with given framerate. "Field Summary" contains options for the GameLoop()-constructor.
+ *
+ * @property {int} tick_duration duration in ms between the last 2 ticks (often called dt)
+ * @property {int} fps the real fps (as opposed to the target fps), smoothed out with a moving average
+ * @property {int} ticks total amount of ticks since game loops start
+ *
+ * @example
+ *
+ * game = {}
+ * draw: function() { ... your stuff executed every 30 FPS ... }
+ * }
+ *
+ * game_loop = new jaws.GameLoop(game, {fps: 30})
+ * game_loop.start()
+ *
+ * // You can also use the shortcut jaws.start(), it will:
+ * // 1) Load all assets with jaws.assets.loadAll()
+ * // 2) Create a GameLoop() and start it
+ * jaws.start(MyGameState, {fps: 30})
+ *
+ */
+jaws.GameLoop = function GameLoop(game_object, options, game_state_setup_options) {
+ if( !(this instanceof arguments.callee) ) return new arguments.callee( game_object, options );
+
+ this.tick_duration = 0
+ this.fps = 0
+ this.ticks = 0
+
+ var update_id
+ var paused = false
+ var stopped = false
+ var that = this
+ var mean_value = new MeanValue(20) // let's have a smooth, non-jittery FPS-value
+
+ /**
+ * returns how game_loop has been active in milliseconds
+ * does currently not factor in pause-time
+ */
+ this.runtime = function() {
+ return (this.last_tick - this.first_tick)
+ }
+
+ /** Start the game loop by calling setup() once and then loop update()/draw() forever with given FPS */
+ this.start = function() {
+ jaws.log.info("Game loop start", true)
+
+ this.first_tick = (new Date()).getTime();
+ this.current_tick = (new Date()).getTime();
+ this.last_tick = (new Date()).getTime();
+
+ if(options.setup !== false && game_object.setup) { game_object.setup(game_state_setup_options) }
+ step_delay = 1000 / options.fps;
+
+ if(options.fps == 60) {
+ requestAnimFrame(this.loop)
+ }
+ else {
+ update_id = setInterval(this.loop, step_delay);
+ }
+ }
+
+ /** The core of the game loop. Calculate a mean FPS and call update()/draw() if game loop is not paused */
+ this.loop = function() {
+ that.current_tick = (new Date()).getTime();
+ that.tick_duration = that.current_tick - that.last_tick
+ that.fps = mean_value.add(1000/that.tick_duration).get()
+
+ if(!stopped && !paused) {
+ if(game_object.update) { game_object.update() }
+ if(game_object.draw) { game_object.draw() }
+ that.ticks++
+ }
+ if(options.fps == 60 && !stopped) requestAnimFrame(that.loop);
+ that.last_tick = that.current_tick;
+ }
+
+ /** Pause the game loop. loop() will still get called but not update() / draw() */
+ this.pause = function() { paused = true }
+
+ /** unpause the game loop */
+ this.unpause = function() { paused = false }
+
+ /** Stop the game loop */
+ this.stop = function() {
+ if(update_id) clearInterval(update_id);
+ stopped = true;
+ }
+}
+
+/** @ignore */
+function MeanValue(size) {
+ this.size = size
+ this.values = new Array(this.size)
+ this.value
+
+ this.add = function(value) {
+ if(this.values.length > this.size) { // is values filled?
+ this.values.splice(0,1)
+ this.value = 0
+ for(var i=0; this.values[i]; i++) {
+ this.value += this.values[i]
+ }
+ this.value = this.value / this.size
+ }
+ this.values.push(value)
+
+ return this
+ }
+
+ this.get = function() {
+ return parseInt(this.value)
+ }
+
+}
+
+return jaws;
+})(jaws || {});
+