This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
~function(window, define, module, Array, Object){ | |
'use strict'; | |
var slice = Array.slice, create = Object.create; | |
function partial(func) { | |
var args1 = slice.call(arguments, 1); | |
return function(){ | |
return func.apply(this, args1.concat(slice.call(arguments))); | |
}; | |
} | |
function mixIn(target, ref) { | |
for (var key in ref) { | |
if (ref.hasOwnProperty(key)) { | |
target[key] = ref[key]; | |
} | |
} | |
return target; | |
} | |
function argsMixInExec(args, prev, next) { | |
typeof next === 'function' ? next.apply(prev, args) : mixIn(prev, next); | |
return prev; | |
} | |
function SnowBlower(proto) { | |
var closures; | |
proto = proto || {}; | |
closures = slice.call(arguments,1); | |
return function() { | |
return closures.reduce(partial(argsMixInExec, slice.call(arguments)), create(proto)); | |
}; | |
} | |
SnowBlower.mixIn = mixIn; | |
SnowBlower.partial = partial; | |
if(define){ | |
define(SnowBlower); | |
} else if(module) { | |
module.exports = SnowBlower; | |
} else { | |
window.SnowBlower = SnowBlower; | |
} | |
}(typeof window !== 'undefined'?window:{},typeof define==='function'?define:null,typeof module!=='undefined'?module:null,[], Object); |
In whatever context you want, make a SnowBlower factory for a stage. Your runtime should create one instance of a stage for every canvas you need.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function _animationFunctions(){ | |
//locally cached reference for speed | |
var animationFunctions = this.animationFunctions = [], | |
slice = [].slice; | |
//we use this as a reference to a no Op function to give our API a way to remove animation functions later | |
function noOp(){} | |
//store these variable out of here so they never have to be allocated inside of your draw loop | |
var _funcIndex = -1, _animationIndex = 0, _len = 0; | |
requestAnimationFrame(function draw(){ | |
_animationIndex = 0; | |
_len = animationFunctions.length; | |
for(;_animationIndex < _len;_animationIndex++) { | |
animationFunctions[_animationIndex]();//call the function! | |
} | |
//find noOps that were declared inside of the draw loop | |
_funcIndex = animationFunctions.indexOf(noOp); | |
while(_funcIndex > -1){ | |
//Always remove EVERY noOp function reference outside of the loop | |
animationFunctions.splice(_funcIndex, 1); | |
//get the next index | |
_funcIndex = animationFunctions.indexOf(noOp); | |
} | |
}); | |
this.removeAnimationFunctions = function(){ | |
var idx = 0, funcIdx = -1, len = arguments.length; | |
for(;idx<len;idx++){ | |
funcIdx = animationFunctions.indexOf(arguments[idx]); | |
if(funcIdx>0){ | |
//this can be called INSIDE OF THE ANIMATION LOOP | |
animationFunctions = noOp; | |
//DO NOT SPLICE HERE | |
} | |
} | |
}; | |
} | |
var Stage = SnowBlower({}, _animationFunctions); |
Here it is folks. I did not write specific code for your rendering engine. You need to expose whatever stage to the objects your are creating so they can call this code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var myStage = Stage(); | |
function _drawFunc(options){ | |
options.stage.animationFunctions.push(function(){ | |
//do your draw stuff and animation here | |
}) | |
} | |
var ObjectOnStage = SnowBlower({}, _drawFunc); | |
var obj = ObjectOnStage({ | |
stage: myStage | |
}); |
Piece of cake. Now all you have to do is pick a rendering engine, render the view in the request animation loop, and create your game.
I suggest using PIXI.js or phaser.js because it's a really great API for canvas rendering. Make sure you do all the work before adding the item to the stage. Remove as many variable declarations outside of the draw function as possible to prevent as much resource allocation and memory leaking as possible. Keep it simple. If you want to pass the draw function a parameter or use "this" as the stage, you can modify your request animation loop like this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//reference this for use in other functions | |
var self = this; | |
//modify loop.... | |
requestAnimationFrame(function draw(){ | |
_animationIndex = 0; | |
_len = animationFunctions.length; | |
for(;_animationIndex < _len;_animationIndex++) { | |
//call the function with a reference to the stage object and some arguments | |
//passing information to the animation functions can definitely be useful | |
animationFunctions[_animationIndex].call(self, arguments...); | |
} | |
//find noOps that were declared inside of the draw loop | |
_funcIndex = animationFunctions.indexOf(noOp); | |
while(_funcIndex > -1){ | |
//Always remove EVERY noOp function reference outside of the loop | |
animationFunctions.splice(_funcIndex, 1); | |
//get the next index | |
_funcIndex = animationFunctions.indexOf(noOp); | |
} | |
}); |
In the end, everything is logical and fun.
Have any suggestions? Feel free to comment/post on Google Plus.
Thanks!
~function(){'use awesome';console.log('josh')}();