From a56ba92210222571faa77666c0691d52db5229fb Mon Sep 17 00:00:00 2001 From: straker Date: Mon, 18 May 2015 01:05:05 -0600 Subject: [PATCH] adding more examples, changing _proto to prototype to make it more obvious --- examples/extendingSprite.html | 101 ++++++++++++++++++++++++++++ examples/galaxian/js/galaxian.js | 2 +- examples/particleEngine.html | 110 +++++++++++++++++++++++++++++++ kontra.js | 55 ++++++++-------- kontra.min.js | 2 +- kontra.min.js.map | 2 +- src/gameLoop.js | 6 +- src/pool.js | 6 +- src/quadtree.js | 6 +- src/sprite.js | 25 +++---- src/spriteSheet.js | 12 ++-- 11 files changed, 270 insertions(+), 57 deletions(-) create mode 100644 examples/extendingSprite.html create mode 100644 examples/particleEngine.html diff --git a/examples/extendingSprite.html b/examples/extendingSprite.html new file mode 100644 index 00000000..e0df21c3 --- /dev/null +++ b/examples/extendingSprite.html @@ -0,0 +1,101 @@ + + + + Extend Sprite + + + + + + + + \ No newline at end of file diff --git a/examples/galaxian/js/galaxian.js b/examples/galaxian/js/galaxian.js index b6a023c8..8356ee2b 100644 --- a/examples/galaxian/js/galaxian.js +++ b/examples/galaxian/js/galaxian.js @@ -20,7 +20,7 @@ kontra.loadAssets( /* * Audio pools */ - // create an audio sprite for use in an audio pool, mimicing a normal image sprite + // create an audio sprite for use in an audio pool, mimicking a normal image sprite var audioSprite = { isAlive: function() { return !this.audio.ended; diff --git a/examples/particleEngine.html b/examples/particleEngine.html new file mode 100644 index 00000000..24397727 --- /dev/null +++ b/examples/particleEngine.html @@ -0,0 +1,110 @@ + + + + Particle Engine + + + + + + + + \ No newline at end of file diff --git a/kontra.js b/kontra.js index 9515ccb8..9e4c6f3c 100644 --- a/kontra.js +++ b/kontra.js @@ -976,16 +976,16 @@ var kontra = (function(kontra, window) { * Game loop that updates and renders the game every frame. * @memberof kontra * - * @see kontra.gameLoop._proto.set for list of parameters. + * @see kontra.gameLoop.prototype.set for list of parameters. */ kontra.gameLoop = function(properties) { - var gameLoop = Object.create(kontra.gameLoop._proto); + var gameLoop = Object.create(kontra.gameLoop.prototype); gameLoop.set(properties); return gameLoop; }; - kontra.gameLoop._proto = { + kontra.gameLoop.prototype = { /** * Set properties on the game loop. * @memberof kontra.gameLoop @@ -1382,16 +1382,16 @@ var kontra = (function(kontra) { * Unused items are at the front of the pool and in use items are at the of the pool. * @memberof kontra * - * @see kontra.pool._proto.set for list of parameters. + * @see kontra.pool.prototype.set for list of parameters. */ kontra.pool = function(properties) { - var pool = Object.create(kontra.pool._proto); + var pool = Object.create(kontra.pool.prototype); pool.set(properties); return pool; }; - kontra.pool._proto = { + kontra.pool.prototype = { /** * Set properties on the pool. * @@ -1577,7 +1577,7 @@ var kontra = (function(kontra, undefined) { * collapses to avoid garbage collection. * @memberof kontra * - * @see kontra.quadtree._proto.set for list of parameters. + * @see kontra.quadtree.prototype.set for list of parameters. *L * The quadrant indices are numbered as follows (following a z-order curve): * | @@ -1587,13 +1587,13 @@ var kontra = (function(kontra, undefined) { * | */ kontra.quadtree = function(properties) { - var quadtree = Object.create(kontra.quadtree._proto); + var quadtree = Object.create(kontra.quadtree.prototype); quadtree.set(properties); return quadtree; }; - kontra.quadtree._proto = { + kontra.quadtree.prototype = { /** * Set properties on the quadtree. * @memberof kontra.quadtree @@ -1845,26 +1845,30 @@ var kontra = (function(kontra, Math, undefined) { * A vector for 2D space. * @memberof kontra * - * @see kontra.vector._proto.set for list of parameters. + * @see kontra.vector.prototype.set for list of parameters. */ kontra.vector = function(x, y) { - var vector = Object.create(kontra.vector._proto); + var vector = Object.create(kontra.vector.prototype); vector.set(x, y); return vector; }; - kontra.vector._proto = { + kontra.vector.prototype = { /** * Set the vector's x and y position. * @memberof kontra.vector * * @param {number} x=0 - Center x coordinate. * @param {number} y=0 - Center y coordinate. + * + * @returns {vector} */ set: function set(x, y) { this.x = x || 0; this.y = y || 0; + + return this; }, /** @@ -1914,16 +1918,13 @@ var kontra = (function(kontra, Math, undefined) { * @see kontra.sprite._prot.set for list of parameters. */ kontra.sprite = function(properties) { - var sprite = Object.create(kontra.sprite._proto); - sprite.position = kontra.vector(); - sprite.velocity = kontra.vector(); - sprite.acceleration = kontra.vector(); + var sprite = Object.create(kontra.sprite.prototype); sprite.set(properties); return sprite; }; - kontra.sprite._proto = { + kontra.sprite.prototype = { /** * Move the sprite by its velocity. * @memberof kontra.sprite @@ -2034,11 +2035,11 @@ var kontra = (function(kontra, Math, undefined) { var _this = this; - _this.position.set(properties.x, properties.y); - _this.velocity.set(properties.dx, properties.dy); - _this.acceleration.set(properties.ddx, properties.ddy); - _this.timeToLive = properties.timeToLive || 0; + _this.position = (_this.position || kontra.vector()).set(properties.x, properties.y); + _this.velocity = (_this.velocity || kontra.vector()).set(properties.dx, properties.dy); + _this.acceleration = (_this.acceleration || kontra.vector()).set(properties.ddx, properties.ddy); + _this.timeToLive = properties.timeToLive || 0; _this.context = properties.context || kontra.context; // image sprite @@ -2172,16 +2173,16 @@ var kontra = (function(kontra, undefined) { * Single animation from a sprite sheet. * @memberof kontra * - * @see kontra.pool._proto.set for list of parameters. + * @see kontra.pool.prototype.set for list of parameters. */ kontra.animation = function(properties) { - var animation = Object.create(kontra.animation._proto); + var animation = Object.create(kontra.animation.prototype); animation.set(properties); return animation; }; - kontra.animation._proto = { + kontra.animation.prototype = { /** * Set properties on the animation. * @memberof kontra.animation @@ -2298,16 +2299,16 @@ var kontra = (function(kontra, undefined) { * Create a sprite sheet from an image. * @memberof kontra * - * @see kontra.spriteSheet._proto.set for list of parameters. + * @see kontra.spriteSheet.prototype.set for list of parameters. */ kontra.spriteSheet = function(properties) { - var spriteSheet = Object.create(kontra.spriteSheet._proto); + var spriteSheet = Object.create(kontra.spriteSheet.prototype); spriteSheet.set(properties); return spriteSheet; }; - kontra.spriteSheet._proto = { + kontra.spriteSheet.prototype = { /** * Set properties on the spriteSheet. * @memberof kontra diff --git a/kontra.min.js b/kontra.min.js index 8185d427..bc216f05 100644 --- a/kontra.min.js +++ b/kontra.min.js @@ -1,2 +1,2 @@ -function qFactory(t,e){function n(t,e,r){var i;if(t)if(a(t))for(i in t)"prototype"==i||"length"==i||"name"==i||t.hasOwnProperty&&!t.hasOwnProperty(i)||e.call(r,t[i],i);else if(t.forEach&&t.forEach!==n)t.forEach(e,r);else if(c(t))for(i=0;ie;e++)t=r[e],n.then(t[0],t[1],t[2])})}},reject:function(t){o.resolve(f(t))},notify:function(e){if(s){var n=s;s.length&&t(function(){for(var t,r=0,i=n.length;i>r;r++)t=n[r],t[2](e)})}},promise:{then:function(t,o,c){var h=u(),d=function(n){try{h.resolve((a(t)?t:r)(n))}catch(i){h.reject(i),e(i)}},f=function(t){try{h.resolve((a(o)?o:i)(t))}catch(n){h.reject(n),e(n)}},p=function(t){try{h.notify((a(c)?c:r)(t))}catch(n){e(n)}};return s?s.push([d,f,p]):n.then(d,f,p),h.promise},"catch":function(t){return this.then(null,t)},"finally":function(t){function e(t,e){var n=u();return e?n.resolve(t):n.reject(t),n.promise}function n(n,i){var o=null;try{o=(t||r)()}catch(s){return e(s,!1)}return o&&a(o.then)?o.then(function(){return e(n,i)},function(t){return e(t,!1)}):e(n,i)}return this.then(function(t){return n(t,!0)},function(t){return n(t,!1)})}}}},h=function(e){return e&&a(e.then)?e:{then:function(n){var r=u();return t(function(){r.resolve(n(e))}),r.promise}}},d=function(t){var e=u();return e.reject(t),e.promise},f=function(n){return{then:function(r,o){var s=u();return t(function(){try{s.resolve((a(o)?o:i)(n))}catch(t){s.reject(t),e(t)}}),s.promise}}},p=function(n,o,s,c){var f,p=u(),l=function(t){try{return(a(o)?o:r)(t)}catch(n){return e(n),d(n)}},m=function(t){try{return(a(s)?s:i)(t)}catch(n){return e(n),d(n)}},v=function(t){try{return(a(c)?c:r)(t)}catch(n){e(n)}};return t(function(){h(n).then(function(t){f||(f=!0,p.resolve(h(t).then(l,m,v)))},function(t){f||(f=!0,p.resolve(m(t)))},function(t){f||p.notify(v(t))})}),p.promise};return{defer:u,reject:d,when:p,all:o}}window.q=qFactory(function(t){setTimeout(function(){t()},0)},function(t){console.error("qLite: "+t.stack)});var kontra=function(t){var e=/(jpeg|jpg|gif|png)$/,n=/(wav|mp3|ogg|aac|m4a)$/;t.images={},t.audios={},t.data={},t.assetPaths={images:"",audios:"",data:""};var r=new Audio;return t.canUse=t.canUse||{},t.canUse.wav="",t.canUse.mp3=r.canPlayType("audio/mpeg;").replace(/^no$/,""),t.canUse.ogg=r.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),t.canUse.aac=r.canPlayType("audio/aac;").replace(/^no$/,""),t.canUse.m4a=(r.canPlayType("audio/x-m4a;")||t.canUse.aac).replace(/^no$/,""),t.getAssetExtension=function(t){return t.substr((~-t.lastIndexOf(".")>>>0)+2)},t.getAssetType=function(t){var r=this.getAssetExtension(t);return r.match(e)?"Image":r.match(n)?"Audio":"Data"},t.getAssetName=function(t){return t.replace(/\.[^/.]+$/,"")},t}(kontra||{}),kontra=function(t,e){return t.loadAssets=function(){var n,r,i=e.defer(),o=[],s=0,a=arguments.length;arguments.length||i.resolve();for(var c,u=0;c=arguments[u];u++)r=Array.isArray(c)?c[0]:c,n=this.getAssetType(r),function(e){o.push(e.promise),t["load"+n](r).then(function(){e.resolve(),i.notify({loaded:++s,total:a})},function(t){e.reject(t)})}(e.defer());return e.all(o).then(function(){i.resolve()},function(t){i.reject(t)}),i.promise},t.loadImage=function(n){var r=e.defer(),i=this.getAssetName(n),o=new Image;return n=this.assetPaths.images+n,o.onload=function(){t.images[i]=t.images[n]=this,r.resolve(this)},o.onerror=function(){r.reject("Unable to load image "+n)},o.src=n,r.promise},t.loadAudio=function(n){var r,i,o,s,a=e.defer();Array.isArray(n)||(n=[n]);for(var c=0;r=n[c];c++)if(this.canUse[this.getAssetExtension(r)]){o=r;break}return o?(i=this.getAssetName(o),s=new Audio,r=this.assetPaths.audios+o,s.addEventListener("canplay",function(){t.audios[i]=t.audios[r]=this,a.resolve(this)}),s.onerror=function(){a.reject("Unable to load audio "+r)},s.src=r,s.preload="auto",s.load()):a.reject("Browser cannot play any of the audio formats provided"),a.promise},t.loadData=function(n){var r=e.defer(),i=new XMLHttpRequest,o=this.getAssetName(n),s=this.assetPaths.data+n;return i.addEventListener("load",function(){if(200!==i.status)return void r.reject(i.responseText);try{var e=JSON.parse(i.responseText);t.data[o]=t.data[s]=e,r.resolve(e)}catch(n){var a=i.responseText;t.data[o]=t.data[s]=a,r.resolve(a)}}),i.open("GET",s,!0),i.send(),r.promise},t}(kontra||{},q),kontra=function(t,e){return t.bundles={},t.createBundle=function(t,e){this.bundles[t]||(this.bundles[t]=e||[])},t.loadBundles=function(){for(var t,n,r=e.defer(),i=[],o=0,s=0,a=0;n=arguments[a];a++)(t=this.bundles[n])?(s+=t.length,i.push(this.loadAssets.apply(this,t))):r.reject("Bundle '"+n+"' has not been created.");return e.all(i).then(function(){r.resolve()},function(t){r.reject(t)},function(){r.notify({loaded:++o,total:s})}),r.promise},t}(kontra||{},q),kontra=function(t,e){return t.loadManifest=function(n){var r,i=e.defer();return t.loadData(n).then(function(e){t.assetPaths.images=e.imagePath||"",t.assetPaths.audios=e.audioPath||"",t.assetPaths.data=e.dataPath||"";for(var n,o=0;n=e.bundles[o];o++)t.createBundle(n.name,n.assets);return e.loadBundles?(r="all"===e.loadBundles?Object.keys(t.bundles||{}):Array.isArray(e.loadBundles)?e.loadBundles:[e.loadBundles],void t.loadBundles.apply(t,r).then(function(){i.resolve()},function(t){i.reject(t)},function(t){i.notify(t)})):void i.resolve()},function(t){i.reject(t)}),i.promise},t}(kontra||{},q),kontra=function(t,e){"use strict";return t.init=function(n){if(n=n||{},t.isString(n.canvas))this.canvas=e.getElementById(n.canvas);else if(t.isCanvas(n.canvas))this.canvas=n.canvas;else if(this.canvas=e.getElementsByTagName("canvas")[0],!this.canvas){var r=new ReferenceError("No canvas element found.");return void t.logError(r,"You must provide a canvas element for the game.")}this.context=this.canvas.getContext("2d"),this.game={width:this.canvas.width,height:this.canvas.height}},t.logError=function(t,e){console.error("Kontra: "+e+"\n "+t.stack)},t.noop=function(){},t.isArray=Array.isArray,t.isString=function(t){return"string"==typeof t},t.isNumber=function(t){return"number"==typeof t},t.isImage=function(t){return t&&"img"===t.nodeName.toLowerCase()},t.isCanvas=function(t){return t&&"canvas"===t.nodeName.toLowerCase()},t}(kontra||{},document),kontra=function(t,e){"use strict";return t.timestamp=function(){return e.performance&&e.performance.now?function(){return e.performance.now()}:function(){return(new Date).getTime()}}(),t.gameLoop=function(e){var n=Object.create(t.gameLoop._proto);return n.set(e),n},t.gameLoop._proto={set:function(e){if(e=e||{},"function"!=typeof e.update||"function"!=typeof e.render){var n=new ReferenceError("Required functions not found");return void t.logError(n,"You must provide update() and render() functions to create a game loop.")}this.isStopped=!1,this._accumulator=0,this._delta=1e3/(e.fps||60),this.update=e.update,this.render=e.render},frame:function(){var e=this;if(e._rAF=requestAnimationFrame(e.frame.bind(e)),e._now=t.timestamp(),e._dt=e._now-e._last,e._last=e._now,!(e._dt>1e3)){for(e._accumulator+=e._dt;e._accumulator>=e._delta;)e.update(e._delta/1e3),e._accumulator-=e._delta;e.render()}},start:function(){this._last=t.timestamp(),this.isStopped=!1,requestAnimationFrame(this.frame.bind(this))},stop:function(){this.isStopped=!0,cancelAnimationFrame(this._rAF)}},t}(kontra||{},window),kontra=function(t,e){"use strict";function n(t){return"number"==typeof t.which?t.which:t.keyCode}function r(t){var e=[];t=t.trim().replace("++","+plus");for(var n,r=0;n=l[r];r++)-1!==t.indexOf(n)&&(e.push(n),t=t.replace(n,""));return t=t.replace(/\+/g,"").toLowerCase(),f[t]?e.push("shift+"+f[t]):t&&e.push(t),e.join("+")}function i(t){for(var e,r=[],i=0;e=l[i];i++)t[e+"Key"]&&r.push(e);var o=h[n(t)];return-1===r.indexOf(o)&&r.push(o),r.join("+")}function o(t){for(var e,n=i(t),r=0,o=n.split("+");e=o[r];r++)u[e]=!0;c[n]&&(c[n](t,n),t.preventDefault())}function s(t){var e=h[n(t)];u[e]=!1,p[e]&&(u[p[e]]=!1)}function a(){u={}}for(var c={},u={},h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"delete",91:"leftwindow",92:"rightwindow",93:"select",144:"numlock",145:"scrolllock",106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},d=0;26>d;d++)h[65+d]=String.fromCharCode(65+d).toLowerCase();for(d=0;10>d;d++)h[48+d]=""+d;for(d=1;20>d;d++)h[111+d]="f"+d;for(d=0;10>d;d++)h[96+d]="numpad"+d;var f={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\",plus:"="},p={leftwindow:"meta",select:"meta"},l=["meta","ctrl","alt","shift"];return e.addEventListener("keydown",o),e.addEventListener("keyup",s),e.addEventListener("blur",a),t.keys={},t.keys.bind=function(e,n){if("function"!=typeof n){var i=new SyntaxError("Invalid function.");return void t.logError(i,"You must provide a function as the second parameter.")}e=t.isArray(e)?e:[e];for(var o,s=0;o=e[s];s++){var a=r(o);c[a]=n}},t.keys.unbind=function(e){e=t.isArray(e)?e:[e];for(var n,i=0;n=e[i];i++){var o=r(n);c[o]=void 0}},t.keys.pressed=function(t){var e=r(t),n=!0;t=e.split("+");for(var i,o=0;i=t[o];o++)n=n&&!!u[i];return n},t}(kontra||{},window),kontra=function(t){"use strict";return t.pool=function(e){var n=Object.create(t.pool._proto);return n.set(e),n},t.pool._proto={set:function(e){e=e||{};var n,r;if("function"!=typeof e.create)return n=new SyntaxError("Required function not found."),void t.logError(n,"Parameter 'create' must be a function that returns an object.");if(this.create=e.create.bind(this,e.createProperties||{}),r=this.create(),!r||"function"!=typeof r.render||"function"!=typeof r.update||"function"!=typeof r.set||"function"!=typeof r.isAlive)return n=new ReferenceError("Create object required functions not found."),void t.logError(n,"Objects to be pooled must implement render(), update(), set() and isAlive() functions.");if(this.objects=[r],this.size=1,this.maxSize=e.maxSize||1/0,this.lastIndex=0,this.inUse=0,e.fill)for(;this.objects.length=n;)if(t=this.objects[e],t.update(),t.isAlive())e--;else{for(var r=e;r>0;r--)this.objects[r]=this.objects[r-1];this.objects[0]=t,this.inUse--,n++}},render:function(){for(var t=Math.max(this.objects.length-this.inUse,0),e=this.lastIndex;e>=t;e--)this.objects[e].render()}},t}(kontra||{}),kontra=function(t,e){"use strict";return t.quadtree=function(e){var n=Object.create(t.quadtree._proto);return n.set(e),n},t.quadtree._proto={set:function(e){e=e||{},this.depth=e.depth||0,this.maxDepth=e.maxDepth||3,this.maxObjects=e.maxObjects||25,this.isBranchNode=!1,this.parentNode=e.parentNode,this.bounds=e.bounds||{x:0,y:0,width:t.game.width,height:t.game.height},this.objects=[],this.subnodes=[]},clear:function(){if(this.isBranchNode)for(var t=0;4>t;t++)this.subnodes[t].clear();this.isBranchNode=!1,this.objects.length=0},get:function(t){for(var e,n,r=this,i=[];r.subnodes.length&&this.isBranchNode;){e=this._getIndex(t);for(var o=0,s=e.length;s>o;o++)n=e[o],i.push.apply(i,this.subnodes[n].get(t));return i}return r.objects},add:function(){for(var e,n,r,i=this,o=0,s=arguments.length;s>o;o++)if(n=arguments[o],t.isArray(n))i.add.apply(this,n);else if(i.subnodes.length&&i.isBranchNode)i._addToSubnode(n);else if(i.objects.push(n),i.objects.length>i.maxObjects&&i.depthn;n++)this.subnodes[e[n]].add(t)},_getIndex:function(t){var n=[],r=this.bounds.x+this.bounds.width/2,i=this.bounds.y+this.bounds.height/2,o=t.x!==e?t.x:t.position.x,s=t.y!==e?t.y:t.position.y,a=i>s&&s+t.height>=this.bounds.y,c=s+t.height>=i&&so&&o+t.width>=this.bounds.x&&(a&&n.push(0),c&&n.push(2)),o+t.width>=r&&oo;o++)this.subnodes[o]=t.quadtree({bounds:{x:r+(o%2===1?e:0),y:i+(o>=2?n:0),width:e,height:n},depth:this.depth+1,maxDepth:this.maxDepth,maxObjects:this.maxObjects,parentNode:this})},render:function(){if((this.objects.length||0===this.depth||this.parentNode&&this.parentNode.isBranchNode)&&(t.context.strokeStyle="red",t.context.strokeRect(this.bounds.x,this.bounds.y,this.bounds.width,this.bounds.height),this.subnodes.length))for(var e=0;4>e;e++)this.subnodes[e].render()}},t}(kontra||{}),kontra=function(t,e,n){"use strict";return t.vector=function(e,n){var r=Object.create(t.vector._proto);return r.set(e,n),r},t.vector._proto={set:function(t,e){this.x=t||0,this.y=e||0},add:function(t,e){this.x+=(t.x||0)*(e||1),this.y+=(t.y||0)*(e||1)},clamp:function(t,n,r,i){this.add=function(o,s){var a=this.x+(o.x||0)*(s||1),c=this.y+(o.y||0)*(s||1);this.x=e.min(e.max(a,t),r),this.y=e.min(e.max(c,n),i)}}},t.sprite=function(e){var n=Object.create(t.sprite._proto);return n.position=t.vector(),n.velocity=t.vector(),n.acceleration=t.vector(),n.set(e),n},t.sprite._proto={advanceSprite:function(t){this.velocity.add(this.acceleration,t),this.position.add(this.velocity,t),this.timeToLive--},drawRect:function(){this.context.fillStyle=this.color,this.context.fillRect(this.position.x,this.position.y,this.width,this.height)},drawImage:function(){this.context.drawImage(this.image,this.position.x,this.position.y)},advanceAnimation:function(t){this.advanceSprite(t),this.currentAnimation.update(t)},drawAnimation:function(){this.currentAnimation.render({context:this.context,x:this.position.x,y:this.position.y})},playAnimation:function(t){this.currentAnimation=this.animations[t]},isAlive:function(){return this.timeToLive>0},set:function(e){e=e||{};var n=this;n.position.set(e.x,e.y),n.velocity.set(e.dx,e.dy),n.acceleration.set(e.ddx,e.ddy),n.timeToLive=e.timeToLive||0,n.context=e.context||t.context,t.isImage(e.image)||t.isCanvas(e.image)?(n.image=e.image,n.width=e.image.width,n.height=e.image.height,n.advance=n.advanceSprite,n.draw=n.drawImage):e.animations?(n.animations=e.animations,n.currentAnimation=e.animations[Object.keys(e.animations)[0]],n.width=n.currentAnimation.width,n.height=n.currentAnimation.height,n.advance=n.advanceAnimation,n.draw=n.drawAnimation):(n.color=e.color,n.width=e.width,n.height=e.height,n.advance=n.advanceSprite,n.draw=n.drawRect),e.update&&(n.update=e.update),e.render&&(n.render=e.render);for(var r in e.properties)e.properties.hasOwnProperty(r)&&(n[r]=e.properties[r])},collidesWith:function(t){var e=t.x!==n?t.x:t.position.x,r=t.y!==n?t.y:t.position.y;return this.position.xe&&this.position.yr?!0:!1},update:function(t){this.advance(t)},render:function(){this.draw()}},t}(kontra||{},Math),kontra=function(t,e){"use strict";return t.animation=function(e){var n=Object.create(t.animation._proto);return n.set(e),n},t.animation._proto={set:function(t){t=t||{},this.spriteSheet=t.spriteSheet,this.frames=t.frames,this.frameSpeed=t.frameSpeed,this.width=t.spriteSheet.frame.width,this.height=t.spriteSheet.frame.height,this.currentFrame=0,this._accumulator=0,this.update=this.advance,this.render=this.draw},advance:function(t){for(t=(1>t?1e3*t:t)||1,this._accumulator+=t;this._accumulator>=this.frameSpeed;)this.currentFrame=++this.currentFrame%this.frames.length,this._accumulator-=this.frameSpeed},draw:function(e){e=e||{};var n=e.context||t.context,r=this.frames[this.currentFrame]/this.spriteSheet.framesPerRow|0,i=this.frames[this.currentFrame]%this.spriteSheet.framesPerRow|0;n.drawImage(this.spriteSheet.image,i*this.spriteSheet.frame.width,r*this.spriteSheet.frame.height,this.spriteSheet.frame.width,this.spriteSheet.frame.height,e.x,e.y,this.spriteSheet.frame.width,this.spriteSheet.frame.height)},play:function(){this.update=this.advance,this.render=this.draw},stop:function(){this.update=t.noop,this.render=t.noop},pause:function(){this.update=t.noop}},t.spriteSheet=function(e){var n=Object.create(t.spriteSheet._proto);return n.set(e),n},t.spriteSheet._proto={set:function(e){if(e=e||{},this.animations={},!t.isImage(e.image)&&!t.isCanvas(e.image)){var n=new SyntaxError("Invalid image.");return void t.logError(n,"You must provide an Image for the SpriteSheet.")}this.image=e.image,this.frame={width:e.frameWidth,height:e.frameHeight},this.framesPerRow=e.image.width/e.frameWidth|0,e.animations&&this.createAnimations(e.animations)},createAnimations:function(n){var r;if(!n||0===Object.keys(n).length)return r=new ReferenceError("No animations found."),void t.logError(r,"You must provide at least one named animation to create an Animation.");var i,o,s,a;for(var c in n)if(n.hasOwnProperty(c)){if(i=n[c],o=i.frames,s=i.frameSpeed,a=[],o===e)return r=new ReferenceError("No animation frames found."),void t.logError(r,"Animation "+c+" must provide a frames property.");if(t.isNumber(o))a.push(o);else if(t.isString(o))a=this._parseFrames(o);else if(t.isArray(o))for(var u,h=0;u=o[h];h++)t.isString(u)?a.push.apply(a,this._parseFrames(u)):a.push(u);this.animations[c]=t.animation({spriteSheet:this,frames:a,frameSpeed:s})}},_parseFrames:function(t){var e,n=[],r=t.split("..").map(Number),i=r[0]=r[1];e--)n.push(e);return n}},t}(kontra||{}),kontra=function(t,e,n,r){"use strict";return t.canUse=t.canUse||{},t.canUse.localStorage="localStorage"in e&&null!==e.localStorage,t.canUse.localStorage?(t.store={},t.store.set=function(t,e){e===r?this.remove(t):n.setItem(t,JSON.stringify(e))},t.store.get=function(t){var e=n.getItem(t);try{e=JSON.parse(e)}catch(r){}return e},t.store.remove=function(t){n.removeItem(t)},t.store.clear=function(){n.clear()},t):t}(kontra||{},window,window.localStorage); +function qFactory(t,e){function n(t,e,r){var i;if(t)if(a(t))for(i in t)"prototype"==i||"length"==i||"name"==i||t.hasOwnProperty&&!t.hasOwnProperty(i)||e.call(r,t[i],i);else if(t.forEach&&t.forEach!==n)t.forEach(e,r);else if(c(t))for(i=0;ie;e++)t=r[e],n.then(t[0],t[1],t[2])})}},reject:function(t){o.resolve(f(t))},notify:function(e){if(s){var n=s;s.length&&t(function(){for(var t,r=0,i=n.length;i>r;r++)t=n[r],t[2](e)})}},promise:{then:function(t,o,c){var h=u(),d=function(n){try{h.resolve((a(t)?t:r)(n))}catch(i){h.reject(i),e(i)}},f=function(t){try{h.resolve((a(o)?o:i)(t))}catch(n){h.reject(n),e(n)}},p=function(t){try{h.notify((a(c)?c:r)(t))}catch(n){e(n)}};return s?s.push([d,f,p]):n.then(d,f,p),h.promise},"catch":function(t){return this.then(null,t)},"finally":function(t){function e(t,e){var n=u();return e?n.resolve(t):n.reject(t),n.promise}function n(n,i){var o=null;try{o=(t||r)()}catch(s){return e(s,!1)}return o&&a(o.then)?o.then(function(){return e(n,i)},function(t){return e(t,!1)}):e(n,i)}return this.then(function(t){return n(t,!0)},function(t){return n(t,!1)})}}}},h=function(e){return e&&a(e.then)?e:{then:function(n){var r=u();return t(function(){r.resolve(n(e))}),r.promise}}},d=function(t){var e=u();return e.reject(t),e.promise},f=function(n){return{then:function(r,o){var s=u();return t(function(){try{s.resolve((a(o)?o:i)(n))}catch(t){s.reject(t),e(t)}}),s.promise}}},p=function(n,o,s,c){var f,p=u(),l=function(t){try{return(a(o)?o:r)(t)}catch(n){return e(n),d(n)}},m=function(t){try{return(a(s)?s:i)(t)}catch(n){return e(n),d(n)}},v=function(t){try{return(a(c)?c:r)(t)}catch(n){e(n)}};return t(function(){h(n).then(function(t){f||(f=!0,p.resolve(h(t).then(l,m,v)))},function(t){f||(f=!0,p.resolve(m(t)))},function(t){f||p.notify(v(t))})}),p.promise};return{defer:u,reject:d,when:p,all:o}}window.q=qFactory(function(t){setTimeout(function(){t()},0)},function(t){console.error("qLite: "+t.stack)});var kontra=function(t){var e=/(jpeg|jpg|gif|png)$/,n=/(wav|mp3|ogg|aac|m4a)$/;t.images={},t.audios={},t.data={},t.assetPaths={images:"",audios:"",data:""};var r=new Audio;return t.canUse=t.canUse||{},t.canUse.wav="",t.canUse.mp3=r.canPlayType("audio/mpeg;").replace(/^no$/,""),t.canUse.ogg=r.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),t.canUse.aac=r.canPlayType("audio/aac;").replace(/^no$/,""),t.canUse.m4a=(r.canPlayType("audio/x-m4a;")||t.canUse.aac).replace(/^no$/,""),t.getAssetExtension=function(t){return t.substr((~-t.lastIndexOf(".")>>>0)+2)},t.getAssetType=function(t){var r=this.getAssetExtension(t);return r.match(e)?"Image":r.match(n)?"Audio":"Data"},t.getAssetName=function(t){return t.replace(/\.[^/.]+$/,"")},t}(kontra||{}),kontra=function(t,e){return t.loadAssets=function(){var n,r,i=e.defer(),o=[],s=0,a=arguments.length;arguments.length||i.resolve();for(var c,u=0;c=arguments[u];u++)r=Array.isArray(c)?c[0]:c,n=this.getAssetType(r),function(e){o.push(e.promise),t["load"+n](r).then(function(){e.resolve(),i.notify({loaded:++s,total:a})},function(t){e.reject(t)})}(e.defer());return e.all(o).then(function(){i.resolve()},function(t){i.reject(t)}),i.promise},t.loadImage=function(n){var r=e.defer(),i=this.getAssetName(n),o=new Image;return n=this.assetPaths.images+n,o.onload=function(){t.images[i]=t.images[n]=this,r.resolve(this)},o.onerror=function(){r.reject("Unable to load image "+n)},o.src=n,r.promise},t.loadAudio=function(n){var r,i,o,s,a=e.defer();Array.isArray(n)||(n=[n]);for(var c=0;r=n[c];c++)if(this.canUse[this.getAssetExtension(r)]){o=r;break}return o?(i=this.getAssetName(o),s=new Audio,r=this.assetPaths.audios+o,s.addEventListener("canplay",function(){t.audios[i]=t.audios[r]=this,a.resolve(this)}),s.onerror=function(){a.reject("Unable to load audio "+r)},s.src=r,s.preload="auto",s.load()):a.reject("Browser cannot play any of the audio formats provided"),a.promise},t.loadData=function(n){var r=e.defer(),i=new XMLHttpRequest,o=this.getAssetName(n),s=this.assetPaths.data+n;return i.addEventListener("load",function(){if(200!==i.status)return void r.reject(i.responseText);try{var e=JSON.parse(i.responseText);t.data[o]=t.data[s]=e,r.resolve(e)}catch(n){var a=i.responseText;t.data[o]=t.data[s]=a,r.resolve(a)}}),i.open("GET",s,!0),i.send(),r.promise},t}(kontra||{},q),kontra=function(t,e){return t.bundles={},t.createBundle=function(t,e){this.bundles[t]||(this.bundles[t]=e||[])},t.loadBundles=function(){for(var t,n,r=e.defer(),i=[],o=0,s=0,a=0;n=arguments[a];a++)(t=this.bundles[n])?(s+=t.length,i.push(this.loadAssets.apply(this,t))):r.reject("Bundle '"+n+"' has not been created.");return e.all(i).then(function(){r.resolve()},function(t){r.reject(t)},function(){r.notify({loaded:++o,total:s})}),r.promise},t}(kontra||{},q),kontra=function(t,e){return t.loadManifest=function(n){var r,i=e.defer();return t.loadData(n).then(function(e){t.assetPaths.images=e.imagePath||"",t.assetPaths.audios=e.audioPath||"",t.assetPaths.data=e.dataPath||"";for(var n,o=0;n=e.bundles[o];o++)t.createBundle(n.name,n.assets);return e.loadBundles?(r="all"===e.loadBundles?Object.keys(t.bundles||{}):Array.isArray(e.loadBundles)?e.loadBundles:[e.loadBundles],void t.loadBundles.apply(t,r).then(function(){i.resolve()},function(t){i.reject(t)},function(t){i.notify(t)})):void i.resolve()},function(t){i.reject(t)}),i.promise},t}(kontra||{},q),kontra=function(t,e){"use strict";return t.init=function(n){if(n=n||{},t.isString(n.canvas))this.canvas=e.getElementById(n.canvas);else if(t.isCanvas(n.canvas))this.canvas=n.canvas;else if(this.canvas=e.getElementsByTagName("canvas")[0],!this.canvas){var r=new ReferenceError("No canvas element found.");return void t.logError(r,"You must provide a canvas element for the game.")}this.context=this.canvas.getContext("2d"),this.game={width:this.canvas.width,height:this.canvas.height}},t.logError=function(t,e){console.error("Kontra: "+e+"\n "+t.stack)},t.noop=function(){},t.isArray=Array.isArray,t.isString=function(t){return"string"==typeof t},t.isNumber=function(t){return"number"==typeof t},t.isImage=function(t){return t&&"img"===t.nodeName.toLowerCase()},t.isCanvas=function(t){return t&&"canvas"===t.nodeName.toLowerCase()},t}(kontra||{},document),kontra=function(t,e){"use strict";return t.timestamp=function(){return e.performance&&e.performance.now?function(){return e.performance.now()}:function(){return(new Date).getTime()}}(),t.gameLoop=function(e){var n=Object.create(t.gameLoop.prototype);return n.set(e),n},t.gameLoop.prototype={set:function(e){if(e=e||{},"function"!=typeof e.update||"function"!=typeof e.render){var n=new ReferenceError("Required functions not found");return void t.logError(n,"You must provide update() and render() functions to create a game loop.")}this.isStopped=!1,this._accumulator=0,this._delta=1e3/(e.fps||60),this.update=e.update,this.render=e.render},frame:function(){var e=this;if(e._rAF=requestAnimationFrame(e.frame.bind(e)),e._now=t.timestamp(),e._dt=e._now-e._last,e._last=e._now,!(e._dt>1e3)){for(e._accumulator+=e._dt;e._accumulator>=e._delta;)e.update(e._delta/1e3),e._accumulator-=e._delta;e.render()}},start:function(){this._last=t.timestamp(),this.isStopped=!1,requestAnimationFrame(this.frame.bind(this))},stop:function(){this.isStopped=!0,cancelAnimationFrame(this._rAF)}},t}(kontra||{},window),kontra=function(t,e){"use strict";function n(t){return"number"==typeof t.which?t.which:t.keyCode}function r(t){var e=[];t=t.trim().replace("++","+plus");for(var n,r=0;n=l[r];r++)-1!==t.indexOf(n)&&(e.push(n),t=t.replace(n,""));return t=t.replace(/\+/g,"").toLowerCase(),f[t]?e.push("shift+"+f[t]):t&&e.push(t),e.join("+")}function i(t){for(var e,r=[],i=0;e=l[i];i++)t[e+"Key"]&&r.push(e);var o=h[n(t)];return-1===r.indexOf(o)&&r.push(o),r.join("+")}function o(t){for(var e,n=i(t),r=0,o=n.split("+");e=o[r];r++)u[e]=!0;c[n]&&(c[n](t,n),t.preventDefault())}function s(t){var e=h[n(t)];u[e]=!1,p[e]&&(u[p[e]]=!1)}function a(){u={}}for(var c={},u={},h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"delete",91:"leftwindow",92:"rightwindow",93:"select",144:"numlock",145:"scrolllock",106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},d=0;26>d;d++)h[65+d]=String.fromCharCode(65+d).toLowerCase();for(d=0;10>d;d++)h[48+d]=""+d;for(d=1;20>d;d++)h[111+d]="f"+d;for(d=0;10>d;d++)h[96+d]="numpad"+d;var f={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\",plus:"="},p={leftwindow:"meta",select:"meta"},l=["meta","ctrl","alt","shift"];return e.addEventListener("keydown",o),e.addEventListener("keyup",s),e.addEventListener("blur",a),t.keys={},t.keys.bind=function(e,n){if("function"!=typeof n){var i=new SyntaxError("Invalid function.");return void t.logError(i,"You must provide a function as the second parameter.")}e=t.isArray(e)?e:[e];for(var o,s=0;o=e[s];s++){var a=r(o);c[a]=n}},t.keys.unbind=function(e){e=t.isArray(e)?e:[e];for(var n,i=0;n=e[i];i++){var o=r(n);c[o]=void 0}},t.keys.pressed=function(t){var e=r(t),n=!0;t=e.split("+");for(var i,o=0;i=t[o];o++)n=n&&!!u[i];return n},t}(kontra||{},window),kontra=function(t){"use strict";return t.pool=function(e){var n=Object.create(t.pool.prototype);return n.set(e),n},t.pool.prototype={set:function(e){e=e||{};var n,r;if("function"!=typeof e.create)return n=new SyntaxError("Required function not found."),void t.logError(n,"Parameter 'create' must be a function that returns an object.");if(this.create=e.create.bind(this,e.createProperties||{}),r=this.create(),!r||"function"!=typeof r.render||"function"!=typeof r.update||"function"!=typeof r.set||"function"!=typeof r.isAlive)return n=new ReferenceError("Create object required functions not found."),void t.logError(n,"Objects to be pooled must implement render(), update(), set() and isAlive() functions.");if(this.objects=[r],this.size=1,this.maxSize=e.maxSize||1/0,this.lastIndex=0,this.inUse=0,e.fill)for(;this.objects.length=n;)if(t=this.objects[e],t.update(),t.isAlive())e--;else{for(var r=e;r>0;r--)this.objects[r]=this.objects[r-1];this.objects[0]=t,this.inUse--,n++}},render:function(){for(var t=Math.max(this.objects.length-this.inUse,0),e=this.lastIndex;e>=t;e--)this.objects[e].render()}},t}(kontra||{}),kontra=function(t,e){"use strict";return t.quadtree=function(e){var n=Object.create(t.quadtree.prototype);return n.set(e),n},t.quadtree.prototype={set:function(e){e=e||{},this.depth=e.depth||0,this.maxDepth=e.maxDepth||3,this.maxObjects=e.maxObjects||25,this.isBranchNode=!1,this.parentNode=e.parentNode,this.bounds=e.bounds||{x:0,y:0,width:t.game.width,height:t.game.height},this.objects=[],this.subnodes=[]},clear:function(){if(this.isBranchNode)for(var t=0;4>t;t++)this.subnodes[t].clear();this.isBranchNode=!1,this.objects.length=0},get:function(t){for(var e,n,r=this,i=[];r.subnodes.length&&this.isBranchNode;){e=this._getIndex(t);for(var o=0,s=e.length;s>o;o++)n=e[o],i.push.apply(i,this.subnodes[n].get(t));return i}return r.objects},add:function(){for(var e,n,r,i=this,o=0,s=arguments.length;s>o;o++)if(n=arguments[o],t.isArray(n))i.add.apply(this,n);else if(i.subnodes.length&&i.isBranchNode)i._addToSubnode(n);else if(i.objects.push(n),i.objects.length>i.maxObjects&&i.depthn;n++)this.subnodes[e[n]].add(t)},_getIndex:function(t){var n=[],r=this.bounds.x+this.bounds.width/2,i=this.bounds.y+this.bounds.height/2,o=t.x!==e?t.x:t.position.x,s=t.y!==e?t.y:t.position.y,a=i>s&&s+t.height>=this.bounds.y,c=s+t.height>=i&&so&&o+t.width>=this.bounds.x&&(a&&n.push(0),c&&n.push(2)),o+t.width>=r&&oo;o++)this.subnodes[o]=t.quadtree({bounds:{x:r+(o%2===1?e:0),y:i+(o>=2?n:0),width:e,height:n},depth:this.depth+1,maxDepth:this.maxDepth,maxObjects:this.maxObjects,parentNode:this})},render:function(){if((this.objects.length||0===this.depth||this.parentNode&&this.parentNode.isBranchNode)&&(t.context.strokeStyle="red",t.context.strokeRect(this.bounds.x,this.bounds.y,this.bounds.width,this.bounds.height),this.subnodes.length))for(var e=0;4>e;e++)this.subnodes[e].render()}},t}(kontra||{}),kontra=function(t,e,n){"use strict";return t.vector=function(e,n){var r=Object.create(t.vector.prototype);return r.set(e,n),r},t.vector.prototype={set:function(t,e){return this.x=t||0,this.y=e||0,this},add:function(t,e){this.x+=(t.x||0)*(e||1),this.y+=(t.y||0)*(e||1)},clamp:function(t,n,r,i){this.add=function(o,s){var a=this.x+(o.x||0)*(s||1),c=this.y+(o.y||0)*(s||1);this.x=e.min(e.max(a,t),r),this.y=e.min(e.max(c,n),i)}}},t.sprite=function(e){var n=Object.create(t.sprite.prototype);return n.set(e),n},t.sprite.prototype={advanceSprite:function(t){this.velocity.add(this.acceleration,t),this.position.add(this.velocity,t),this.timeToLive--},drawRect:function(){this.context.fillStyle=this.color,this.context.fillRect(this.position.x,this.position.y,this.width,this.height)},drawImage:function(){this.context.drawImage(this.image,this.position.x,this.position.y)},advanceAnimation:function(t){this.advanceSprite(t),this.currentAnimation.update(t)},drawAnimation:function(){this.currentAnimation.render({context:this.context,x:this.position.x,y:this.position.y})},playAnimation:function(t){this.currentAnimation=this.animations[t]},isAlive:function(){return this.timeToLive>0},set:function(e){e=e||{};var n=this;n.position=(n.position||t.vector()).set(e.x,e.y),n.velocity=(n.velocity||t.vector()).set(e.dx,e.dy),n.acceleration=(n.acceleration||t.vector()).set(e.ddx,e.ddy),n.timeToLive=e.timeToLive||0,n.context=e.context||t.context,t.isImage(e.image)||t.isCanvas(e.image)?(n.image=e.image,n.width=e.image.width,n.height=e.image.height,n.advance=n.advanceSprite,n.draw=n.drawImage):e.animations?(n.animations=e.animations,n.currentAnimation=e.animations[Object.keys(e.animations)[0]],n.width=n.currentAnimation.width,n.height=n.currentAnimation.height,n.advance=n.advanceAnimation,n.draw=n.drawAnimation):(n.color=e.color,n.width=e.width,n.height=e.height,n.advance=n.advanceSprite,n.draw=n.drawRect),e.update&&(n.update=e.update),e.render&&(n.render=e.render);for(var r in e.properties)e.properties.hasOwnProperty(r)&&(n[r]=e.properties[r])},collidesWith:function(t){var e=t.x!==n?t.x:t.position.x,r=t.y!==n?t.y:t.position.y;return this.position.xe&&this.position.yr?!0:!1},update:function(t){this.advance(t)},render:function(){this.draw()}},t}(kontra||{},Math),kontra=function(t,e){"use strict";return t.animation=function(e){var n=Object.create(t.animation.prototype);return n.set(e),n},t.animation.prototype={set:function(t){t=t||{},this.spriteSheet=t.spriteSheet,this.frames=t.frames,this.frameSpeed=t.frameSpeed,this.width=t.spriteSheet.frame.width,this.height=t.spriteSheet.frame.height,this.currentFrame=0,this._accumulator=0,this.update=this.advance,this.render=this.draw},advance:function(t){for(t=(1>t?1e3*t:t)||1,this._accumulator+=t;this._accumulator>=this.frameSpeed;)this.currentFrame=++this.currentFrame%this.frames.length,this._accumulator-=this.frameSpeed},draw:function(e){e=e||{};var n=e.context||t.context,r=this.frames[this.currentFrame]/this.spriteSheet.framesPerRow|0,i=this.frames[this.currentFrame]%this.spriteSheet.framesPerRow|0;n.drawImage(this.spriteSheet.image,i*this.spriteSheet.frame.width,r*this.spriteSheet.frame.height,this.spriteSheet.frame.width,this.spriteSheet.frame.height,e.x,e.y,this.spriteSheet.frame.width,this.spriteSheet.frame.height)},play:function(){this.update=this.advance,this.render=this.draw},stop:function(){this.update=t.noop,this.render=t.noop},pause:function(){this.update=t.noop}},t.spriteSheet=function(e){var n=Object.create(t.spriteSheet.prototype);return n.set(e),n},t.spriteSheet.prototype={set:function(e){if(e=e||{},this.animations={},!t.isImage(e.image)&&!t.isCanvas(e.image)){var n=new SyntaxError("Invalid image.");return void t.logError(n,"You must provide an Image for the SpriteSheet.")}this.image=e.image,this.frame={width:e.frameWidth,height:e.frameHeight},this.framesPerRow=e.image.width/e.frameWidth|0,e.animations&&this.createAnimations(e.animations)},createAnimations:function(n){var r;if(!n||0===Object.keys(n).length)return r=new ReferenceError("No animations found."),void t.logError(r,"You must provide at least one named animation to create an Animation.");var i,o,s,a;for(var c in n)if(n.hasOwnProperty(c)){if(i=n[c],o=i.frames,s=i.frameSpeed,a=[],o===e)return r=new ReferenceError("No animation frames found."),void t.logError(r,"Animation "+c+" must provide a frames property.");if(t.isNumber(o))a.push(o);else if(t.isString(o))a=this._parseFrames(o);else if(t.isArray(o))for(var u,h=0;u=o[h];h++)t.isString(u)?a.push.apply(a,this._parseFrames(u)):a.push(u);this.animations[c]=t.animation({spriteSheet:this,frames:a,frameSpeed:s})}},_parseFrames:function(t){var e,n=[],r=t.split("..").map(Number),i=r[0]=r[1];e--)n.push(e);return n}},t}(kontra||{}),kontra=function(t,e,n,r){"use strict";return t.canUse=t.canUse||{},t.canUse.localStorage="localStorage"in e&&null!==e.localStorage,t.canUse.localStorage?(t.store={},t.store.set=function(t,e){e===r?this.remove(t):n.setItem(t,JSON.stringify(e))},t.store.get=function(t){var e=n.getItem(t);try{e=JSON.parse(e)}catch(r){}return e},t.store.remove=function(t){n.removeItem(t)},t.store.clear=function(){n.clear()},t):t}(kontra||{},window,window.localStorage); //# sourceMappingURL=kontra.min.js.map \ No newline at end of file diff --git a/kontra.min.js.map b/kontra.min.js.map index 28291208..84928ce3 100644 --- a/kontra.min.js.map +++ b/kontra.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["kontraAssetLoader.js","core.js","gameLoop.js","keyboard.js","pool.js","quadtree.js","sprite.js","spriteSheet.js","store.js"],"names":["qFactory","nextTick","exceptionHandler","forEach","obj","iterator","context","key","isFunction","hasOwnProperty","call","isArray","length","defaultCallback","value","defaultErrback","reason","reject","all","promises","deferred","defer","counter","results","promise","ref","then","resolve","notify","toString","pending","val","callbacks","undefined","callback","i","ii","createInternalRejectedPromise","progress","errback","progressback","result","wrappedCallback","e","wrappedErrback","wrappedProgressback","push","catch","this","finally","makePromise","resolved","handleCallback","isResolved","callbackOutput","error","when","done","window","q","setTimeout","console","stack","kontra","isImage","isAudio","images","audios","data","assetPaths","audio","Audio","canUse","wav","mp3","canPlayType","replace","ogg","aac","m4a","getAssetExtension","url","substr","lastIndexOf","getAssetType","extension","match","getAssetName","loadAssets","type","numLoaded","numAssets","arguments","asset","Array","assetDeferred","loaded","total","loadImage","name","image","Image","onload","onerror","src","loadAudio","source","playableSource","addEventListener","preload","load","loadData","req","XMLHttpRequest","dataUrl","status","responseText","json","JSON","parse","open","send","bundles","createBundle","bundle","assets","loadBundles","apply","loadManifest","manifest","imagePath","audioPath","dataPath","Object","keys","document","init","properties","isString","canvas","getElementById","isCanvas","getElementsByTagName","ReferenceError","logError","getContext","game","width","height","message","noop","isNumber","nodeName","toLowerCase","timestamp","performance","now","Date","getTime","gameLoop","create","_proto","set","update","render","isStopped","_accumulator","_delta","fps","frame","_this","_rAF","requestAnimationFrame","bind","_now","_dt","_last","start","stop","cancelAnimationFrame","normalizeKeyCode","which","keyCode","normalizeKeys","combination","trim","modifier","modifierOrder","indexOf","shiftKeys","join","getKeyCombination","keyMap","keydownEventHandler","split","pressedKeys","preventDefault","keyupEventHandler","aliases","blurEventHandler",8,9,13,16,17,18,20,27,32,33,34,35,36,37,38,39,40,45,46,91,92,93,144,145,106,107,109,110,111,186,187,188,189,190,191,192,219,220,221,222,"String","fromCharCode","~","!","@","#","$","%","^","&","*","(",")","_","+",":","\"","<",">","?","|","plus","leftwindow","select","SyntaxError","unbind","pressed","pool","createProperties","isAlive","objects","size","maxSize","Infinity","lastIndex","inUse","fill","unshift","get","x","getAliveObjects","slice","clear","index","Math","max","j","quadtree","depth","maxDepth","maxObjects","isBranchNode","parentNode","bounds","y","subnodes","object","indices","node","_getIndex","add","_addToSubnode","_split","verticalMidpoint","horizontalMidpoint","position","intersectsTopQuadrants","intersectsBottomQuadrants","subWidth","subHeight","strokeStyle","strokeRect","vector","dt","clamp","xMin","yMin","xMax","yMax","min","sprite","velocity","acceleration","advanceSprite","timeToLive","drawRect","fillStyle","color","fillRect","drawImage","advanceAnimation","currentAnimation","drawAnimation","playAnimation","animations","dx","dy","ddx","ddy","advance","draw","prop","collidesWith","animation","spriteSheet","frames","frameSpeed","currentFrame","row","framesPerRow","col","play","pause","frameWidth","frameHeight","createAnimations","sequence","_parseFrames","consecutiveFrames","map","Number","direction","localStorage","store","remove","setItem","stringify","getItem","removeItem"],"mappings":"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","file":"kontra.min.js","sourcesContent":["/**\n * The MIT License\n *\n * Copyright (c) 2010-2012 Google, Inc. http://angularjs.org\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\nwindow.q = qFactory(function(callback) {\n setTimeout(function() {\n callback();\n }, 0);\n}, function(e) {\n console.error('qLite: ' + e.stack);\n});\n\n/**\n * Constructs a promise manager.\n *\n * @param {function(Function)} nextTick Function for executing functions in the next turn.\n * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for\n * debugging purposes.\n * @returns {object} Promise manager.\n */\nfunction qFactory(nextTick, exceptionHandler) {\n var toString = ({}).toString;\n var isFunction = function isFunction(value){return typeof value == 'function';};\n var isArray = function isArray(value) {return toString.call(value) === '[object Array]';};\n\n function forEach(obj, iterator, context) {\n var key;\n if (obj) {\n if (isFunction(obj)) {\n for (key in obj) {\n // Need to check if hasOwnProperty exists,\n // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function\n if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {\n iterator.call(context, obj[key], key);\n }\n }\n } else if (obj.forEach && obj.forEach !== forEach) {\n obj.forEach(iterator, context);\n } else if (isArray(obj)) {\n for (key = 0; key < obj.length; key++)\n iterator.call(context, obj[key], key);\n } else {\n for (key in obj) {\n if (obj.hasOwnProperty(key)) {\n iterator.call(context, obj[key], key);\n }\n }\n }\n }\n return obj;\n }\n\n /**\n * @ngdoc method\n * @name $q#defer\n * @function\n *\n * @description\n * Creates a `Deferred` object which represents a task which will finish in the future.\n *\n * @returns {Deferred} Returns a new instance of deferred.\n */\n var defer = function() {\n var pending = [],\n value, deferred;\n\n deferred = {\n\n resolve: function(val) {\n if (pending) {\n var callbacks = pending;\n pending = undefined;\n value = ref(val);\n\n if (callbacks.length) {\n nextTick(function() {\n var callback;\n for (var i = 0, ii = callbacks.length; i < ii; i++) {\n callback = callbacks[i];\n value.then(callback[0], callback[1], callback[2]);\n }\n });\n }\n }\n },\n\n\n reject: function(reason) {\n deferred.resolve(createInternalRejectedPromise(reason));\n },\n\n\n notify: function(progress) {\n if (pending) {\n var callbacks = pending;\n\n if (pending.length) {\n nextTick(function() {\n var callback;\n for (var i = 0, ii = callbacks.length; i < ii; i++) {\n callback = callbacks[i];\n callback[2](progress);\n }\n });\n }\n }\n },\n\n\n promise: {\n then: function(callback, errback, progressback) {\n var result = defer();\n\n var wrappedCallback = function(value) {\n try {\n result.resolve((isFunction(callback) ? callback : defaultCallback)(value));\n } catch(e) {\n result.reject(e);\n exceptionHandler(e);\n }\n };\n\n var wrappedErrback = function(reason) {\n try {\n result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));\n } catch(e) {\n result.reject(e);\n exceptionHandler(e);\n }\n };\n\n var wrappedProgressback = function(progress) {\n try {\n result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));\n } catch(e) {\n exceptionHandler(e);\n }\n };\n\n if (pending) {\n pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);\n } else {\n value.then(wrappedCallback, wrappedErrback, wrappedProgressback);\n }\n\n return result.promise;\n },\n\n \"catch\": function(callback) {\n return this.then(null, callback);\n },\n\n \"finally\": function(callback) {\n\n function makePromise(value, resolved) {\n var result = defer();\n if (resolved) {\n result.resolve(value);\n } else {\n result.reject(value);\n }\n return result.promise;\n }\n\n function handleCallback(value, isResolved) {\n var callbackOutput = null;\n try {\n callbackOutput = (callback ||defaultCallback)();\n } catch(e) {\n return makePromise(e, false);\n }\n if (callbackOutput && isFunction(callbackOutput.then)) {\n return callbackOutput.then(function() {\n return makePromise(value, isResolved);\n }, function(error) {\n return makePromise(error, false);\n });\n } else {\n return makePromise(value, isResolved);\n }\n }\n\n return this.then(function(value) {\n return handleCallback(value, true);\n }, function(error) {\n return handleCallback(error, false);\n });\n }\n }\n };\n\n return deferred;\n };\n\n\n var ref = function(value) {\n if (value && isFunction(value.then)) return value;\n return {\n then: function(callback) {\n var result = defer();\n nextTick(function() {\n result.resolve(callback(value));\n });\n return result.promise;\n }\n };\n };\n\n\n /**\n * @ngdoc method\n * @name $q#reject\n * @function\n *\n * @description\n * Creates a promise that is resolved as rejected with the specified `reason`. This api should be\n * used to forward rejection in a chain of promises. If you are dealing with the last promise in\n * a promise chain, you don't need to worry about it.\n *\n * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of\n * `reject` as the `throw` keyword in JavaScript. This also means that if you \"catch\" an error via\n * a promise error callback and you want to forward the error to the promise derived from the\n * current promise, you have to \"rethrow\" the error by returning a rejection constructed via\n * `reject`.\n *\n * ```js\n * promiseB = promiseA.then(function(result) {\n * // success: do something and resolve promiseB\n * // with the old or a new result\n * return result;\n * }, function(reason) {\n * // error: handle the error if possible and\n * // resolve promiseB with newPromiseOrValue,\n * // otherwise forward the rejection to promiseB\n * if (canHandle(reason)) {\n * // handle the error and recover\n * return newPromiseOrValue;\n * }\n * return $q.reject(reason);\n * });\n * ```\n *\n * @param {*} reason Constant, message, exception or an object representing the rejection reason.\n * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.\n */\n var reject = function(reason) {\n var result = defer();\n result.reject(reason);\n return result.promise;\n };\n\n var createInternalRejectedPromise = function(reason) {\n return {\n then: function(callback, errback) {\n var result = defer();\n nextTick(function() {\n try {\n result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));\n } catch(e) {\n result.reject(e);\n exceptionHandler(e);\n }\n });\n return result.promise;\n }\n };\n };\n\n\n /**\n * @ngdoc method\n * @name $q#when\n * @function\n *\n * @description\n * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.\n * This is useful when you are dealing with an object that might or might not be a promise, or if\n * the promise comes from a source that can't be trusted.\n *\n * @param {*} value Value or a promise\n * @returns {Promise} Returns a promise of the passed value or promise\n */\n var when = function(value, callback, errback, progressback) {\n var result = defer(),\n done;\n\n var wrappedCallback = function(value) {\n try {\n return (isFunction(callback) ? callback : defaultCallback)(value);\n } catch (e) {\n exceptionHandler(e);\n return reject(e);\n }\n };\n\n var wrappedErrback = function(reason) {\n try {\n return (isFunction(errback) ? errback : defaultErrback)(reason);\n } catch (e) {\n exceptionHandler(e);\n return reject(e);\n }\n };\n\n var wrappedProgressback = function(progress) {\n try {\n return (isFunction(progressback) ? progressback : defaultCallback)(progress);\n } catch (e) {\n exceptionHandler(e);\n }\n };\n\n nextTick(function() {\n ref(value).then(function(value) {\n if (done) return;\n done = true;\n result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));\n }, function(reason) {\n if (done) return;\n done = true;\n result.resolve(wrappedErrback(reason));\n }, function(progress) {\n if (done) return;\n result.notify(wrappedProgressback(progress));\n });\n });\n\n return result.promise;\n };\n\n\n function defaultCallback(value) {\n return value;\n }\n\n\n function defaultErrback(reason) {\n return reject(reason);\n }\n\n\n /**\n * @ngdoc method\n * @name $q#all\n * @function\n *\n * @description\n * Combines multiple promises into a single promise that is resolved when all of the input\n * promises are resolved.\n *\n * @param {Array.|Object.} promises An array or hash of promises.\n * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,\n * each value corresponding to the promise at the same index/key in the `promises` array/hash.\n * If any of the promises is resolved with a rejection, this resulting promise will be rejected\n * with the same rejection value.\n */\n function all(promises) {\n var deferred = defer(),\n counter = 0,\n results = isArray(promises) ? [] : {};\n\n forEach(promises, function(promise, key) {\n counter++;\n ref(promise).then(function(value) {\n if (results.hasOwnProperty(key)) return;\n results[key] = value;\n if (!(--counter)) deferred.resolve(results);\n }, function(reason) {\n if (results.hasOwnProperty(key)) return;\n deferred.reject(reason);\n }, function(reason) {\n if (results.hasOwnProperty(key)) return;\n deferred.notify(reason);\n });\n });\n\n if (counter === 0) {\n deferred.resolve(results);\n }\n\n return deferred.promise;\n }\n\n return {\n defer: defer,\n reject: reject,\n when: when,\n all: all\n };\n}\nvar kontra = (function(kontra) {\n var isImage = /(jpeg|jpg|gif|png)$/;\n var isAudio = /(wav|mp3|ogg|aac|m4a)$/;\n var folderSeparator = /(\\\\|\\/)/g;\n\n // all assets are stored by name as well as by URL\n kontra.images = {};\n kontra.audios = {};\n kontra.data = {};\n\n // base asset path for determining asset URLs\n kontra.assetPaths = {\n images: '',\n audios: '',\n data: '',\n };\n\n // audio playability\n // @see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/audio.js\n var audio = new Audio();\n kontra.canUse = kontra.canUse || {};\n kontra.canUse.wav = '';\n kontra.canUse.mp3 = audio.canPlayType('audio/mpeg;').replace(/^no$/,'');\n kontra.canUse.ogg = audio.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/^no$/,'');\n kontra.canUse.aac = audio.canPlayType('audio/aac;').replace(/^no$/,'');\n kontra.canUse.m4a = (audio.canPlayType('audio/x-m4a;') || kontra.canUse.aac).replace(/^no$/,'');\n\n /**\n * Get the extension of an asset.\n * @see http://jsperf.com/extract-file-extension\n * @memberOf kontra\n *\n * @param {string} url - The URL to the asset.\n *\n * @returns {string}\n */\n kontra.getAssetExtension = function getAssetExtension(url) {\n return url.substr((~-url.lastIndexOf(\".\") >>> 0) + 2);\n };\n\n /**\n * Get the type of asset based on its extension.\n * @memberOf kontra\n *\n * @param {string} url - The URL to the asset.\n *\n * @returns {string} Image, Audio, Data.\n */\n kontra.getAssetType = function getAssetType(url) {\n var extension = this.getAssetExtension(url);\n\n if (extension.match(isImage)) {\n return 'Image';\n }\n else if (extension.match(isAudio)) {\n return 'Audio';\n }\n else {\n return 'Data';\n }\n };\n\n /**\n * Get the name of an asset.\n * @memberOf kontra\n *\n * @param {string} url - The URL to the asset.\n *\n * @returns {string}\n */\n kontra.getAssetName = function getAssetName(url) {\n return url.replace(/\\.[^/.]+$/, \"\");\n };\n\n return kontra;\n})(kontra || {});\n/*jshint -W084 */\n\nvar kontra = (function(kontra, q) {\n /**\n * Load an Image, Audio, or data file.\n * @memberOf kontra\n *\n * @param {string|string[]} - Comma separated list of assets to load.\n *\n * @returns {Promise} A deferred promise.\n *\n * @example\n * kontra.loadAsset('car.png');\n * kontra.loadAsset(['explosion.mp3', 'explosion.ogg']);\n * kontra.loadAsset('bio.json');\n * kontra.loadAsset('car.png', ['explosion.mp3', 'explosion.ogg'], 'bio.json');\n */\n kontra.loadAssets = function loadAsset() {\n var deferred = q.defer();\n var promises = [];\n var numLoaded = 0;\n var numAssets = arguments.length;\n var type, name, url;\n\n if (!arguments.length) {\n deferred.resolve();\n }\n\n for (var i = 0, asset; asset = arguments[i]; i++) {\n if (!Array.isArray(asset)) {\n url = asset;\n }\n else {\n url = asset[0];\n }\n\n type = this.getAssetType(url);\n\n // create a closure for event binding\n (function(assetDeferred) {\n promises.push(assetDeferred.promise);\n\n kontra['load' + type](url).then(\n function loadAssetSuccess() {\n assetDeferred.resolve();\n deferred.notify({'loaded': ++numLoaded, 'total': numAssets});\n },\n function loadAssetError(error) {\n assetDeferred.reject(error);\n });\n })(q.defer());\n }\n\n q.all(promises).then(\n function loadAssetsSuccess() {\n deferred.resolve();\n },\n function loadAssetsError(error) {\n deferred.reject(error);\n });\n\n return deferred.promise;\n };\n\n /**\n * Load an Image file. Uses assetPaths.images to resolve URL.\n * @memberOf kontra\n *\n * @param {string} url - The URL to the Image file.\n *\n * @returns {Promise} A deferred promise. Promise resolves with the Image.\n *\n * @example\n * kontra.loadImage('car.png');\n * kontra.loadImage('autobots/truck.png');\n */\n kontra.loadImage = function(url) {\n var deferred = q.defer();\n var name = this.getAssetName(url);\n var image = new Image();\n\n url = this.assetPaths.images + url;\n\n image.onload = function loadImageOnLoad() {\n kontra.images[name] = kontra.images[url] = this;\n deferred.resolve(this);\n };\n\n image.onerror = function loadImageOnError() {\n deferred.reject('Unable to load image ' + url);\n };\n\n image.src = url;\n\n return deferred.promise;\n };\n\n /**\n * Load an Audio file. Supports loading multiple audio formats which will be resolved by\n * the browser in the order listed. Uses assetPaths.audios to resolve URL.\n * @memberOf kontra\n *\n * @param {string|string[]} url - The URL to the Audio file.\n *\n * @returns {Promise} A deferred promise. Promise resolves with the Audio.\n *\n * @example\n * kontra.loadAudio('sound_effects/laser.mp3');\n * kontra.loadAudio(['explosion.mp3', 'explosion.m4a', 'explosion.ogg']);\n *\n * There are two ways to load Audio in the web: HTML5 Audio or the Web Audio API.\n * HTML5 Audio has amazing browser support, including back to IE9\n * (http://caniuse.com/#feat=audio). However, the web Audio API isn't supported in\n * IE nor Android Browsers (http://caniuse.com/#search=Web%20Audio%20API).\n *\n * To support the most browsers we'll use HTML5 Audio. However, doing so means we'll\n * have to work around mobile device limitations as well as Audio implementation\n * limitations.\n *\n * Android browsers require playing Audio through user interaction whereas iOS 6+ can\n * play through normal JavaScript. Moreover, Android can only play one sound source at\n * a time whereas iOS 6+ can handle more than one. See this article for more details\n * (http://pupunzi.open-lab.com/2013/03/13/making-html5-audio-actually-work-on-mobile/)\n *\n * Both iOS and Android will download an Audio through JavaScript, but neither will play\n * it until user interaction. You can get around this issue by having a splash screen\n * that requires user interaction to start the game and using that event to play the audio.\n * (http://jsfiddle.net/straker/5dsm6jgt/)\n */\n kontra.loadAudio = function(url) {\n var deferred = q.defer();\n var source, name, playableSource, audio;\n\n if (!Array.isArray(url)) {\n url = [url];\n }\n\n // determine which audio format the browser can play\n for (var i = 0; source = url[i]; i++) {\n if ( this.canUse[this.getAssetExtension(source)] ) {\n playableSource = source;\n break;\n }\n }\n\n if (!playableSource) {\n deferred.reject('Browser cannot play any of the audio formats provided');\n }\n else {\n name = this.getAssetName(playableSource);\n audio = new Audio();\n\n source = this.assetPaths.audios + playableSource;\n\n audio.addEventListener('canplay', function loadAudioOnLoad() {\n kontra.audios[name] = kontra.audios[source] = this;\n deferred.resolve(this);\n });\n\n audio.onerror = function loadAudioOnError() {\n deferred.reject('Unable to load audio ' + source);\n };\n\n audio.src = source;\n audio.preload = 'auto';\n audio.load();\n }\n\n return deferred.promise;\n };\n\n\n /**\n * Load a data file (be it text or JSON). Uses assetPaths.data to resolve URL.\n * @memberOf kontra\n *\n * @param {string} url - The URL to the data file.\n *\n * @returns {Promise} A deferred promise. Resolves with the data or parsed JSON.\n *\n * @example\n * kontra.loadData('bio.json');\n * kontra.loadData('dialog.txt');\n */\n kontra.loadData = function(url) {\n var deferred = q.defer();\n var req = new XMLHttpRequest();\n var name = this.getAssetName(url);\n var dataUrl = this.assetPaths.data + url;\n\n req.addEventListener('load', function loadDataOnLoad() {\n if (req.status !== 200) {\n deferred.reject(req.responseText);\n return;\n }\n\n try {\n var json = JSON.parse(req.responseText);\n kontra.data[name] = kontra.data[dataUrl] = json;\n\n deferred.resolve(json);\n }\n catch(e) {\n var data = req.responseText;\n kontra.data[name] = kontra.data[dataUrl] = data;\n\n deferred.resolve(data);\n }\n });\n\n req.open('GET', dataUrl, true);\n req.send();\n\n return deferred.promise;\n };\n\n return kontra;\n})(kontra || {}, q);\n/*jshint -W084 */\n\nvar kontra = (function(kontra, q) {\n kontra.bundles = {};\n\n /**\n * Create a group of assets that can be loaded using kontra.loadBundle().\n * @memberOf kontra\n *\n * @param {string} bundle - The name of the bundle.\n * @param {string[]} assets - Assets to add to the bundle.\n *\n * @example\n * kontra.createBundle('myBundle', ['car.png', ['explosion.mp3', 'explosion.ogg']]);\n */\n kontra.createBundle = function createBundle(bundle, assets) {\n if (this.bundles[bundle]) {\n return;\n }\n\n this.bundles[bundle] = assets || [];\n };\n\n /**\n * Load all assets that are part of a bundle.\n * @memberOf kontra\n *\n * @param {string|string[]} - Comma separated list of bundles to load.\n *\n * @returns {Promise} A deferred promise.\n *\n * @example\n * kontra.loadBundles('myBundle');\n * kontra.loadBundles('myBundle', 'myOtherBundle');\n */\n kontra.loadBundles = function loadBundles() {\n var deferred = q.defer();\n var promises = [];\n var numLoaded = 0;\n var numAssets = 0;\n var assets;\n\n for (var i = 0, bundle; bundle = arguments[i]; i++) {\n if (!(assets = this.bundles[bundle])) {\n deferred.reject('Bundle \\'' + bundle + '\\' has not been created.');\n continue;\n }\n\n numAssets += assets.length;\n\n promises.push(this.loadAssets.apply(this, assets));\n }\n\n q.all(promises).then(\n function loadBundlesSuccess() {\n deferred.resolve();\n },\n function loadBundlesError(error) {\n deferred.reject(error);\n },\n function loadBundlesNofity() {\n deferred.notify({'loaded': ++numLoaded, 'total': numAssets});\n });\n\n return deferred.promise;\n };\n\n return kontra;\n})(kontra || {}, q);\n/*jshint -W084 */\n\nvar kontra = (function(kontra, q) {\n /**\n * Load an asset manifest file.\n * @memberOf kontra\n *\n * @param {string} url - The URL to the asset manifest file.\n *\n * @returns {Promise} A deferred promise.\n */\n kontra.loadManifest = function loadManifest(url) {\n var deferred = q.defer();\n var bundles;\n\n kontra.loadData(url).then(\n function loadManifestSuccess(manifest) {\n kontra.assetPaths.images = manifest.imagePath || '';\n kontra.assetPaths.audios = manifest.audioPath || '';\n kontra.assetPaths.data = manifest.dataPath || '';\n\n // create bundles and add assets\n for (var i = 0, bundle; bundle = manifest.bundles[i]; i++) {\n kontra.createBundle(bundle.name, bundle.assets);\n }\n\n if (!manifest.loadBundles) {\n deferred.resolve();\n return;\n }\n\n // load all bundles\n if (manifest.loadBundles === 'all') {\n bundles = Object.keys(kontra.bundles || {});\n }\n // load a single bundle\n else if (!Array.isArray(manifest.loadBundles)) {\n bundles = [manifest.loadBundles];\n }\n // load multiple bundles\n else {\n bundles = manifest.loadBundles;\n }\n\n kontra.loadBundles.apply(kontra, bundles).then(\n function loadBundlesSuccess() {\n deferred.resolve();\n },\n function loadBundlesError(error) {\n deferred.reject(error);\n },\n function loadBundlesNotify(progress) {\n deferred.notify(progress);\n });\n },\n function loadManifestError(error) {\n deferred.reject(error);\n });\n\n return deferred.promise;\n };\n\n return kontra;\n})(kontra || {}, q);","/* global console */\n\nvar kontra = (function(kontra, document) {\n 'use strict';\n\n /**\n * Set up the canvas.\n * @memberof kontra\n *\n * @param {object} properties - Properties for the game.\n * @param {string|Canvas} properties.canvas - Main canvas ID or Element for the game.\n */\n kontra.init = function init(properties) {\n properties = properties || {};\n\n if (kontra.isString(properties.canvas)) {\n this.canvas = document.getElementById(properties.canvas);\n }\n else if (kontra.isCanvas(properties.canvas)) {\n this.canvas = properties.canvas;\n }\n else {\n this.canvas = document.getElementsByTagName('canvas')[0];\n\n if (!this.canvas) {\n var error = new ReferenceError('No canvas element found.');\n kontra.logError(error, 'You must provide a canvas element for the game.');\n return;\n }\n }\n\n this.context = this.canvas.getContext('2d');\n this.game = {\n width: this.canvas.width,\n height: this.canvas.height\n };\n };\n\n /**\n * Throw an error message to the user with readable formating.\n * @memberof kontra\n *\n * @param {Error} error - Error object.\n * @param {string} message - Error message.\n */\n kontra.logError = function logError(error, message) {\n console.error('Kontra: ' + message + '\\n\\t' + error.stack);\n };\n\n /**\n * Noop function.\n * @memberof kontra\n */\n kontra.noop = function noop() {};\n\n /**\n * Determine if a value is an Array.\n * @memberof kontra\n *\n * @param {*} value - Value to test.\n *\n * @returns {boolean}\n */\n kontra.isArray = Array.isArray;\n\n /**\n * Determine if a value is a String.\n * @memberof kontra\n *\n * @param {*} value - Value to test.\n *\n * @returns {boolean}\n */\n kontra.isString = function isString(value) {\n return typeof value === 'string';\n };\n\n /**\n * Determine if a value is a Number.\n * @memberof kontra\n *\n * @param {*} value - Value to test.\n *\n * @returns {boolean}\n */\n kontra.isNumber = function isNumber(value) {\n return typeof value === 'number';\n };\n\n /**\n * Determine if a value is an Image.\n * @memberof kontra\n *\n * @param {*} value - Value to test.\n *\n * @returns {boolean}\n */\n kontra.isImage = function isImage(value) {\n return value && value.nodeName.toLowerCase() === 'img';\n };\n\n /**\n * Determine if a value is a Canvas.\n * @memberof kontra\n *\n * @param {*} value - Value to test.\n *\n * @returns {boolean}\n */\n kontra.isCanvas = function isCanvas(value) {\n return value && value.nodeName.toLowerCase() === 'canvas';\n };\n\n return kontra;\n})(kontra || {}, document);","var kontra = (function(kontra, window) {\n 'use strict';\n\n /**\n * Get the current time. Uses the User Timing API if it's available or defaults to using\n * Date().getTime()\n * @private\n *\n * @returns {number}\n */\n kontra.timestamp = (function() {\n if (window.performance && window.performance.now) {\n return function timestampPerformance() {\n return window.performance.now();\n };\n }\n else {\n return function timestampDate() {\n return new Date().getTime();\n };\n }\n })();\n\n /**\n * Game loop that updates and renders the game every frame.\n * @memberof kontra\n *\n * @see kontra.gameLoop._proto.set for list of parameters.\n */\n kontra.gameLoop = function(properties) {\n var gameLoop = Object.create(kontra.gameLoop._proto);\n gameLoop.set(properties);\n\n return gameLoop;\n };\n\n kontra.gameLoop._proto = {\n /**\n * Set properties on the game loop.\n * @memberof kontra.gameLoop\n *\n * @param {object} properties - Configure the game loop.\n * @param {number} [properties.fps=60] - Desired frame rate.\n * @param {function} properties.update - Function called to update the game.\n * @param {function} properties.render - Function called to render the game.\n */\n set: function set(properties) {\n properties = properties || {};\n\n // check for required functions\n if (typeof properties.update !== 'function' || typeof properties.render !== 'function') {\n var error = new ReferenceError('Required functions not found');\n kontra.logError(error, 'You must provide update() and render() functions to create a game loop.');\n return;\n }\n\n this.isStopped = false;\n\n // animation variables\n this._accumulator = 0;\n this._delta = 1E3 / (properties.fps || 60);\n\n this.update = properties.update;\n this.render = properties.render;\n },\n\n /**\n * Called every frame of the game loop.\n * @memberof kontra.gameLoop\n */\n frame: function frame() {\n var _this = this;\n\n _this._rAF = requestAnimationFrame(_this.frame.bind(_this));\n\n _this._now = kontra.timestamp();\n _this._dt = _this._now - _this._last;\n _this._last = _this._now;\n\n // prevent updating the game with a very large dt if the game were to lose focus\n // and then regain focus later\n if (_this._dt > 1E3) {\n return;\n }\n\n _this._accumulator += _this._dt;\n\n while (_this._accumulator >= _this._delta) {\n _this.update(_this._delta / 1E3);\n\n _this._accumulator -= _this._delta;\n }\n\n _this.render();\n },\n\n /**\n * Start the game loop.\n * @memberof kontra.gameLoop\n */\n start: function start() {\n this._last = kontra.timestamp();\n this.isStopped = false;\n requestAnimationFrame(this.frame.bind(this));\n },\n\n /**\n * Stop the game loop.\n */\n stop: function stop() {\n this.isStopped = true;\n cancelAnimationFrame(this._rAF);\n }\n };\n\n return kontra;\n})(kontra || {}, window);","/*jshint -W084 */\n\nvar kontra = (function(kontra, window) {\n 'use strict';\n\n var callbacks = {};\n var pressedKeys = {};\n\n var keyMap = {\n // named keys\n 8: 'backspace',\n 9: 'tab',\n 13: 'enter',\n 16: 'shift',\n 17: 'ctrl',\n 18: 'alt',\n 20: 'capslock',\n 27: 'esc',\n 32: 'space',\n 33: 'pageup',\n 34: 'pagedown',\n 35: 'end',\n 36: 'home',\n 37: 'left',\n 38: 'up',\n 39: 'right',\n 40: 'down',\n 45: 'insert',\n 46: 'delete',\n 91: 'leftwindow',\n 92: 'rightwindow',\n 93: 'select',\n 144: 'numlock',\n 145: 'scrolllock',\n\n // special characters\n 106: '*',\n 107: '+',\n 109: '-',\n 110: '.',\n 111: '/',\n 186: ';',\n 187: '=',\n 188: ',',\n 189: '-',\n 190: '.',\n 191: '/',\n 192: '`',\n 219: '[',\n 220: '\\\\',\n 221: ']',\n 222: '\\''\n };\n\n // alpha keys\n for (var i = 0; i < 26; i++) {\n keyMap[65+i] = String.fromCharCode(65+i).toLowerCase();\n }\n // numeric keys\n for (i = 0; i < 10; i++) {\n keyMap[48+i] = ''+i;\n }\n // f keys\n for (i = 1; i < 20; i++) {\n keyMap[111+i] = 'f'+i;\n }\n // keypad\n for (i = 0; i < 10; i++) {\n keyMap[96+i] = 'numpad'+i;\n }\n\n // shift keys mapped to their non-shift equivalent\n var shiftKeys = {\n '~': '`',\n '!': '1',\n '@': '2',\n '#': '3',\n '$': '4',\n '%': '5',\n '^': '6',\n '&': '7',\n '*': '8',\n '(': '9',\n ')': '0',\n '_': '-',\n '+': '=',\n ':': ';',\n '\"': '\\'',\n '<': ',',\n '>': '.',\n '?': '/',\n '|': '\\\\',\n 'plus': '='\n };\n\n // aliases modifier keys to their actual key for keyup event\n var aliases = {\n 'leftwindow': 'meta', // mac\n 'select': 'meta' // mac\n };\n\n // modifier order for combinations\n var modifierOrder = ['meta', 'ctrl', 'alt', 'shift'];\n\n window.addEventListener('keydown', keydownEventHandler);\n window.addEventListener('keyup', keyupEventHandler);\n window.addEventListener('blur', blurEventHandler);\n\n /**\n * Object for using the keyboard.\n */\n kontra.keys = {};\n\n /**\n * Register a function to be called on a keyboard keys.\n * Please note that not all keyboard combinations can be executed due to ghosting.\n * @memberof kontra.keys\n *\n * @param {string|string[]} keys - keys combination string(s).\n *\n * @throws {SyntaxError} If callback is not a function.\n */\n kontra.keys.bind = function bindKey(keys, callback) {\n if (typeof callback !== 'function') {\n var error = new SyntaxError('Invalid function.');\n kontra.logError(error, 'You must provide a function as the second parameter.');\n return;\n }\n\n keys = (kontra.isArray(keys) ? keys : [keys]);\n\n for (var i = 0, key; key = keys[i]; i++) {\n var combination = normalizeKeys(key);\n\n callbacks[combination] = callback;\n }\n };\n\n /**\n * Remove the callback function for a key combination.\n * @memberof kontra.keys\n *\n * @param {string|string[]} keys - keys combination string.\n */\n kontra.keys.unbind = function unbindKey(keys) {\n keys = (kontra.isArray(keys) ? keys : [keys]);\n\n for (var i = 0, key; key = keys[i]; i++) {\n var combination = normalizeKeys(key);\n\n callbacks[combination] = undefined;\n }\n };\n\n /**\n * Returns whether a key is pressed.\n * @memberof kontra.keys\n *\n * @param {string} keys - Keys combination string.\n *\n * @returns {boolean}\n */\n kontra.keys.pressed = function keyPressed(keys) {\n var combination = normalizeKeys(keys);\n var pressed = true;\n\n // loop over each key in the combination and verify that it is pressed\n keys = combination.split('+');\n for (var i = 0, key; key = keys[i]; i++) {\n pressed = pressed && !!pressedKeys[key];\n }\n\n return pressed;\n };\n\n /**\n * Normalize the event keycode\n * @private\n *\n * @param {Event} e\n *\n * @returns {number}\n */\n function normalizeKeyCode(e) {\n return (typeof e.which === 'number' ? e.which : e.keyCode);\n }\n\n /**\n * Normalize keys combination order.\n * @private\n *\n * @param {string} keys - keys combination string.\n *\n * @returns {string} Normalized combination.\n *\n * @example\n * normalizeKeys('c+ctrl'); //=> 'ctrl+c'\n * normalizeKeys('shift+++meta+alt'); //=> 'meta+alt+shift+plus'\n */\n function normalizeKeys(keys) {\n var combination = [];\n\n // handle '++' combinations\n keys = keys.trim().replace('++', '+plus');\n\n // put modifiers in the correct order\n for (var i = 0, modifier; modifier = modifierOrder[i]; i++) {\n\n // check for the modifier\n if (keys.indexOf(modifier) !== -1) {\n combination.push(modifier);\n keys = keys.replace(modifier, '');\n }\n }\n\n // remove all '+'s to leave only the last key\n keys = keys.replace(/\\+/g, '').toLowerCase();\n\n // check for shift key\n if (shiftKeys[keys]) {\n combination.push('shift+'+shiftKeys[keys]);\n }\n else if(keys) {\n combination.push(keys);\n }\n\n return combination.join('+');\n }\n\n /**\n * Get the key combination from an event.\n * @private\n *\n * @param {Event} e\n *\n * @return {string} normalized combination.\n */\n function getKeyCombination(e) {\n var combination = [];\n\n // check for modifiers\n for (var i = 0, modifier; modifier = modifierOrder[i]; i++) {\n if (e[modifier+'Key']) {\n combination.push(modifier);\n }\n }\n\n var key = keyMap[normalizeKeyCode(e)];\n\n // prevent duplicate keys from being added to the combination\n // for example 'ctrl+ctrl' since ctrl is both a modifier and\n // a regular key\n if (combination.indexOf(key) === -1) {\n combination.push(key);\n }\n\n return combination.join('+');\n }\n\n /**\n * Execute a function that corresponds to a keyboard combination.\n * @private\n *\n * @param {Event} e\n */\n function keydownEventHandler(e) {\n var combination = getKeyCombination(e);\n\n // set pressed keys\n for (var i = 0, keys = combination.split('+'), key; key = keys[i]; i++) {\n pressedKeys[key] = true;\n }\n\n if (callbacks[combination]) {\n callbacks[combination](e, combination);\n e.preventDefault();\n }\n }\n\n /**\n * Set the released key to not being pressed.\n * @private\n *\n * @param {Event} e\n */\n function keyupEventHandler(e) {\n var key = keyMap[normalizeKeyCode(e)];\n pressedKeys[key] = false;\n\n if (aliases[key]) {\n pressedKeys[ aliases[key] ] = false;\n }\n }\n\n /**\n * Reset pressed keys.\n * @private\n *\n * @param {Event} e\n */\n function blurEventHandler(e) {\n pressedKeys = {};\n }\n\n return kontra;\n})(kontra || {}, window);","/*jshint -W084 */\n\nvar kontra = (function(kontra) {\n 'use strict';\n\n /**\n * Object pool. The pool will grow in size to accommodate as many objects as are needed.\n * Unused items are at the front of the pool and in use items are at the of the pool.\n * @memberof kontra\n *\n * @see kontra.pool._proto.set for list of parameters.\n */\n kontra.pool = function(properties) {\n var pool = Object.create(kontra.pool._proto);\n pool.set(properties);\n\n return pool;\n };\n\n kontra.pool._proto = {\n /**\n * Set properties on the pool.\n *\n * @param {object} properties - Properties of the pool.\n * @param {object} properties.create - Function that returns the object to use in the pool.\n * @param {object} properties.createProperties - Properties that will be passed to the create function.\n * @param {number} properties.maxSize - The maximum size that the pool will grow to.\n * @param {boolean} properties.fill - Fill the pool to max size instead of slowly growing.\n *\n * Objects inside the pool must implement render(), update(),\n * set(), and isAlive() functions.\n */\n set: function set(properties) {\n properties = properties || {};\n\n var error, obj;\n\n if (typeof properties.create !== 'function') {\n error = new SyntaxError('Required function not found.');\n kontra.logError(error, 'Parameter \\'create\\' must be a function that returns an object.');\n return;\n }\n\n // bind the create function to always use the create properties\n this.create = properties.create.bind(this, properties.createProperties || {});\n\n // ensure objects for the pool have required functions\n obj = this.create();\n\n if (!obj || typeof obj.render !== 'function' || typeof obj.update !== 'function' ||\n typeof obj.set !== 'function' || typeof obj.isAlive !== 'function') {\n error = new ReferenceError('Create object required functions not found.');\n kontra.logError(error, 'Objects to be pooled must implement render(), update(), set() and isAlive() functions.');\n return;\n }\n\n // start the pool with an object\n this.objects = [obj];\n this.size = 1;\n this.maxSize = properties.maxSize || Infinity;\n this.lastIndex = 0;\n this.inUse = 0;\n\n // fill the pool\n if (properties.fill) {\n while (this.objects.length < this.maxSize) {\n this.objects.unshift(this.create());\n }\n }\n },\n\n /**\n * Get an object from the pool.\n * @memberof kontra.pool\n *\n * @param {object} properties - Properties to pass to object.set().\n */\n get: function get(properties) {\n properties = properties || {};\n\n var _this = this;\n\n // the pool is out of objects if the first object is in use and it can't grow\n if (_this.objects[0].isAlive()) {\n if (_this.size === _this.maxSize) {\n return;\n }\n // 'double' the size of the array by filling it with twice as many objects\n else {\n for (var x = 0; x < _this.size && _this.objects.length < _this.maxSize; x++) {\n _this.objects.unshift(_this.create());\n }\n\n _this.size = _this.objects.length;\n _this.lastIndex = _this.size - 1;\n }\n }\n\n // save off first object in pool to reassign to last object after unshift\n var obj = _this.objects[0];\n obj.set(properties);\n\n // unshift the array\n for (var i = 1; i < _this.size; i++) {\n _this.objects[i-1] = _this.objects[i];\n }\n\n _this.objects[_this.lastIndex] = obj;\n _this.inUse++;\n },\n\n /**\n * Return all objects that are alive from the pool.\n * @memberof kontra.pool\n *\n * @returns {object[]}\n */\n getAliveObjects: function getAliveObjects() {\n return this.objects.slice(this.objects.length - this.inUse);\n },\n\n /**\n * Clear the object pool.\n * @memberof kontra.pool\n */\n clear: function clear() {\n this.inUse = 0;\n this.size = 1;\n this.lastIndex = 0;\n this.objects.length = 0;\n this.objects.push(this.create({}));\n },\n\n /**\n * Update all alive pool objects.\n * @memberof kontra.pool\n */\n update: function update() {\n var i = this.lastIndex;\n var obj;\n\n // only iterate over the objects that are alive\n //\n // If the user kills an object outside of the update cycle, the pool won't know of\n // the change until the next update and inUse won't be decremented. If the user then\n // gets an object when inUse is the same size as objects.length, inUse will increment\n // and this statement will evaluate to -1.\n //\n // I don't like having to go through the pool to kill an object as it forces you to know\n // which object came from which pool. Instead, we'll just prevent the index from going below\n // 0 and accept the fact that inUse may be out of sync for a frame.\n var index = Math.max(this.objects.length - this.inUse, 0);\n\n while (i >= index) {\n obj = this.objects[i];\n\n obj.update();\n\n // if the object is dead, move it to the front of the pool\n if (!obj.isAlive()) {\n\n // push an object from the middle of the pool to the front of the pool\n // without returning a new array through Array#splice to avoid garbage\n // collection of the old array\n // @see http://jsperf.com/object-pools-array-vs-loop\n for (var j = i; j > 0; j--) {\n this.objects[j] = this.objects[j-1];\n }\n\n this.objects[0] = obj;\n this.inUse--;\n index++;\n }\n else {\n i--;\n }\n }\n },\n\n /**\n * render all alive pool objects.\n * @memberof kontra.pool\n */\n render: function render() {\n var index = Math.max(this.objects.length - this.inUse, 0);\n\n for (var i = this.lastIndex; i >= index; i--) {\n this.objects[i].render();\n }\n }\n };\n\n return kontra;\n})(kontra || {});","/*jshint -W084 */\n\nvar kontra = (function(kontra, undefined) {\n 'use strict';\n\n /**\n * A quadtree for 2D collision checking. The quadtree acts like an object pool in that it\n * will create subnodes as objects are needed but it won't clean up the subnodes when it\n * collapses to avoid garbage collection.\n * @memberof kontra\n *\n * @see kontra.quadtree._proto.set for list of parameters.\n *L\n * The quadrant indices are numbered as follows (following a z-order curve):\n * |\n * 0 | 1\n * ----+----\n * 2 | 3\n * |\n */\n kontra.quadtree = function(properties) {\n var quadtree = Object.create(kontra.quadtree._proto);\n quadtree.set(properties);\n\n return quadtree;\n };\n\n kontra.quadtree._proto = {\n /**\n * Set properties on the quadtree.\n * @memberof kontra.quadtree\n *\n * @param {number} [depth=0] - Current node depth.\n * @param {number} [maxDepth=3] - Maximum node depths the quadtree can have.\n * @param {number} [maxObjects=25] - Maximum number of objects a node can support before splitting.\n * @param {object} [parentNode] - The node that contains this node.\n * @param {object} [bounds] - The 2D space this node occupies.\n */\n set: function set(properties) {\n properties = properties || {};\n\n this.depth = properties.depth || 0;\n this.maxDepth = properties.maxDepth || 3;\n this.maxObjects = properties.maxObjects || 25;\n\n // since we won't clean up any subnodes, we need to keep track of which nodes are\n // currently the leaf node so we know which nodes to add objects to\n this.isBranchNode = false;\n\n this.parentNode = properties.parentNode;\n\n this.bounds = properties.bounds || {\n x: 0,\n y: 0,\n width: kontra.game.width,\n height: kontra.game.height\n };\n\n this.objects = [];\n this.subnodes = [];\n },\n\n /**\n * Clear the quadtree\n * @memberof kontra.quadtree\n */\n clear: function clear() {\n if (this.isBranchNode) {\n for (var i = 0; i < 4; i++) {\n this.subnodes[i].clear();\n }\n }\n\n this.isBranchNode = false;\n this.objects.length = 0;\n },\n\n /**\n * Find the leaf node the object belongs to and get all objects that are part of\n * that node.\n * @memberof kontra.quadtree\n *\n * @param {object} object - Object to use for finding the leaf node.\n *\n * @returns {object[]} A list of objects in the same leaf node as the object.\n */\n get: function get(object) {\n var node = this;\n var objects = [];\n var indices, index;\n\n // traverse the tree until we get to a leaf node\n while (node.subnodes.length && this.isBranchNode) {\n indices = this._getIndex(object);\n\n for (var i = 0, length = indices.length; i < length; i++) {\n index = indices[i];\n\n objects.push.apply(objects, this.subnodes[index].get(object));\n }\n\n return objects;\n }\n\n return node.objects;\n },\n\n /**\n * Add an object to the quadtree. Once the number of objects in the node exceeds\n * the maximum number of objects allowed, it will split and move all objects to their\n * corresponding subnodes.\n * @memberof kontra.quadtree\n */\n add: function add() {\n var _this = this;\n var i, object, obj, indices, index;\n\n for (var j = 0, length = arguments.length; j < length; j++) {\n object = arguments[j];\n\n // add a group of objects separately\n if (kontra.isArray(object)) {\n _this.add.apply(this, object);\n\n continue;\n }\n\n // current node has subnodes, so we need to add this object into a subnode\n if (_this.subnodes.length && _this.isBranchNode) {\n _this._addToSubnode(object);\n\n continue;\n }\n\n // this node is a leaf node so add the object to it\n _this.objects.push(object);\n\n // split the node if there are too many objects\n if (_this.objects.length > _this.maxObjects && _this.depth < _this.maxDepth) {\n _this._split();\n\n // move all objects to their corresponding subnodes\n for (i = 0; obj = _this.objects[i]; i++) {\n _this._addToSubnode(obj);\n }\n\n _this.objects.length = 0;\n }\n }\n },\n\n /**\n * Add an object to a subnode.\n * @memberof kontra.quadtree\n * @private\n *\n * @param {object} object - Object to add into a subnode\n */\n _addToSubnode: function _addToSubnode(object) {\n var indices = this._getIndex(object);\n\n // add the object to all subnodes it intersects\n for (var i = 0, length = indices.length; i < length; i++) {\n this.subnodes[ indices[i] ].add(object);\n }\n },\n\n /**\n * Determine which subnodes the object intersects with.\n * @memberof kontra.quadtree\n * @private\n *\n * @param {object} object - Object to check.\n *\n * @returns {number[]} List of all subnodes object intersects.\n */\n _getIndex: function getIndex(object) {\n var indices = [];\n\n var verticalMidpoint = this.bounds.x + this.bounds.width / 2;\n var horizontalMidpoint = this.bounds.y + this.bounds.height / 2;\n\n // handle non-kontra.sprite objects as well as kontra.sprite objects\n var x = (object.x !== undefined ? object.x : object.position.x);\n var y = (object.y !== undefined ? object.y : object.position.y);\n\n // save off quadrant checks for reuse\n var intersectsTopQuadrants = y < horizontalMidpoint && y + object.height >= this.bounds.y;\n var intersectsBottomQuadrants = y + object.height >= horizontalMidpoint && y < this.bounds.y + this.bounds.height;\n\n // object intersects with the left quadrants\n if (x < verticalMidpoint && x + object.width >= this.bounds.x) {\n if (intersectsTopQuadrants) { // top left\n indices.push(0);\n }\n\n if (intersectsBottomQuadrants) { // bottom left\n indices.push(2);\n }\n }\n\n // object intersects with the right quadrants\n if (x + object.width >= verticalMidpoint && x < this.bounds.x + this.bounds.width) { // top right\n if (intersectsTopQuadrants) {\n indices.push(1);\n }\n\n if (intersectsBottomQuadrants) { // bottom right\n indices.push(3);\n }\n }\n\n return indices;\n },\n\n /**\n * Split the node into four subnodes.\n * @memberof kontra.quadtree\n * @private\n */\n _split: function split() {\n this.isBranchNode = true;\n\n // only split if we haven't split before\n if (this.subnodes.length) {\n return;\n }\n\n var subWidth = this.bounds.width / 2 | 0;\n var subHeight = this.bounds.height / 2 | 0;\n var x = this.bounds.x;\n var y = this.bounds.y;\n\n for (var i = 0; i < 4; i++) {\n this.subnodes[i] = kontra.quadtree({\n bounds: {\n x: x + (i % 2 === 1 ? subWidth : 0), // nodes 1 and 3\n y: y + (i >= 2 ? subHeight : 0), // nodes 2 and 3\n width: subWidth,\n height: subHeight\n },\n depth: this.depth+1,\n maxDepth: this.maxDepth,\n maxObjects: this.maxObjects,\n parentNode: this\n });\n }\n },\n\n /**\n * Draw the quadtree. Useful for visual debugging.\n * @memberof kontra.quadtree\n */\n render: function() {\n // don't draw empty leaf nodes, always draw branch nodes and the first node\n if (this.objects.length || this.depth === 0 ||\n (this.parentNode && this.parentNode.isBranchNode)) {\n\n kontra.context.strokeStyle = 'red';\n kontra.context.strokeRect(this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height);\n\n if (this.subnodes.length) {\n for (var i = 0; i < 4; i++) {\n this.subnodes[i].render();\n }\n }\n }\n }\n };\n\n return kontra;\n})(kontra || {});","var kontra = (function(kontra, Math, undefined) {\n 'use strict';\n\n /**\n * A vector for 2D space.\n * @memberof kontra\n *\n * @see kontra.vector._proto.set for list of parameters.\n */\n kontra.vector = function(x, y) {\n var vector = Object.create(kontra.vector._proto);\n vector.set(x, y);\n\n return vector;\n };\n\n kontra.vector._proto = {\n /**\n * Set the vector's x and y position.\n * @memberof kontra.vector\n *\n * @param {number} x=0 - Center x coordinate.\n * @param {number} y=0 - Center y coordinate.\n */\n set: function set(x, y) {\n this.x = x || 0;\n this.y = y || 0;\n },\n\n /**\n * Add a vector to this vector.\n * @memberof kontra.vector\n *\n * @param {vector} vector - Vector to add.\n * @param {number} dt=1 - Time since last update.\n */\n add: function add(vector, dt) {\n this.x += (vector.x || 0) * (dt || 1);\n this.y += (vector.y || 0) * (dt || 1);\n },\n\n /**\n * Clamp the vector between two points that form a rectangle.\n * Please note that clamping will only work if the add function is called.\n * @memberof kontra.vector\n *\n * @param {number} xMin - Min x value.\n * @param {number} yMin - Min y value.\n * @param {number} xMax - Max x value.\n * @param {number} yMax - Max y value.\n */\n clamp: function clamp(xMin, yMin, xMax, yMax) {\n\n // overwrite add function to clamp the final values.\n this.add = function clampAdd(vector, dt) {\n var x = this.x + (vector.x || 0) * (dt || 1);\n var y = this.y + (vector.y || 0) * (dt || 1);\n\n this.x = Math.min( Math.max(x, xMin), xMax );\n this.y = Math.min( Math.max(y, yMin), yMax );\n };\n }\n };\n\n\n\n\n\n /**\n * A sprite with a position, velocity, and acceleration.\n * @memberof kontra\n * @requires kontra.vector\n *\n * @see kontra.sprite._prot.set for list of parameters.\n */\n kontra.sprite = function(properties) {\n var sprite = Object.create(kontra.sprite._proto);\n sprite.position = kontra.vector();\n sprite.velocity = kontra.vector();\n sprite.acceleration = kontra.vector();\n sprite.set(properties);\n\n return sprite;\n };\n\n kontra.sprite._proto = {\n /**\n * Move the sprite by its velocity.\n * @memberof kontra.sprite\n *\n * @param {number} dt - Time since last update.\n */\n advanceSprite: function advanceSprite(dt) {\n this.velocity.add(this.acceleration, dt);\n this.position.add(this.velocity, dt);\n\n this.timeToLive--;\n },\n\n /**\n * Draw a simple rectangle. Useful for prototyping.\n * @memberof kontra.sprite\n */\n drawRect: function drawRect() {\n this.context.fillStyle = this.color;\n this.context.fillRect(this.position.x, this.position.y, this.width, this.height);\n },\n\n /**\n * Draw the sprite.\n * @memberof kontra.sprite\n */\n drawImage: function drawImage() {\n this.context.drawImage(this.image, this.position.x, this.position.y);\n },\n\n /**\n * Update the currently playing animation. Used when animations are passed to the sprite.\n * @memberof kontra.sprite\n *\n * @param {number} dt - Time since last update.\n */\n advanceAnimation: function advanceAnimation(dt) {\n this.advanceSprite(dt);\n\n this.currentAnimation.update(dt);\n },\n\n /**\n * Draw the currently playing animation. Used when animations are passed to the sprite.\n * @memberof kontra.sprite\n */\n drawAnimation: function drawAnimation() {\n this.currentAnimation.render({\n context: this.context,\n x: this.position.x,\n y: this.position.y\n });\n },\n\n /**\n * Play an animation.\n * @memberof kontra.sprite\n *\n * @param {string} name - Name of the animation to play.\n */\n playAnimation: function playAnimation(name) {\n this.currentAnimation = this.animations[name];\n },\n\n /**\n * Determine if the sprite is alive.\n * @memberof kontra.sprite\n *\n * @returns {boolean}\n */\n isAlive: function isAlive() {\n return this.timeToLive > 0;\n },\n\n /**\n * Set properties on the sprite.\n * @memberof kontra.sprite\n *\n * @param {object} properties - Properties to set on the sprite.\n * @param {number} properties.x - X coordinate of the sprite.\n * @param {number} properties.y - Y coordinate of the sprite.\n * @param {number} [properties.dx] - Change in X position.\n * @param {number} [properties.dy] - Change in Y position.\n * @param {number} [properties.ddx] - Change in X velocity.\n * @param {number} [properties.ddy] - Change in Y velocity.\n *\n * @param {object} [properties.properties] - Additional properties to set on the sprite.\n * @param {number} [properties.timeToLive=0] - How may frames the sprite should be alive.\n * @param {Context} [properties.context=kontra.context] - Provide a context for the sprite to draw on.\n *\n * @param {Image|Canvas} [properties.image] - Image for the sprite.\n *\n * @param {object} [properties.animations] - Animations for the sprite instead of an image.\n *\n * @param {string} [properties.color] - If no image or animation is provided, use color to draw a rectangle for the sprite.\n * @param {number} [properties.width] - Width of the sprite for drawing a rectangle.\n * @param {number} [properties.height] - Height of the sprite for drawing a rectangle.\n *\n * @param {function} [properties.update] - Function to use to update the sprite.\n * @param {function} [properties.render] - Function to use to render the sprite.\n *\n * If you need the sprite to live forever, or just need it to stay on screen until you\n * decide when to kill it, you can set timeToLive to Infinity.\n * Just be sure to set timeToLive to 0 when you want the sprite to die.\n */\n set: function set(properties) {\n properties = properties || {};\n\n var _this = this;\n\n _this.position.set(properties.x, properties.y);\n _this.velocity.set(properties.dx, properties.dy);\n _this.acceleration.set(properties.ddx, properties.ddy);\n _this.timeToLive = properties.timeToLive || 0;\n\n _this.context = properties.context || kontra.context;\n\n // image sprite\n if (kontra.isImage(properties.image) || kontra.isCanvas(properties.image)) {\n _this.image = properties.image;\n _this.width = properties.image.width;\n _this.height = properties.image.height;\n\n // change the advance and draw functions to work with images\n _this.advance = _this.advanceSprite;\n _this.draw = _this.drawImage;\n }\n // animation sprite\n else if (properties.animations) {\n _this.animations = properties.animations;\n\n // default the current animation to the first one in the list\n _this.currentAnimation = properties.animations[ Object.keys(properties.animations)[0] ];\n _this.width = _this.currentAnimation.width;\n _this.height = _this.currentAnimation.height;\n\n // change the advance and draw functions to work with animations\n _this.advance = _this.advanceAnimation;\n _this.draw = _this.drawAnimation;\n }\n // rectangle sprite\n else {\n _this.color = properties.color;\n _this.width = properties.width;\n _this.height = properties.height;\n\n // change the advance and draw functions to work with rectangles\n _this.advance = _this.advanceSprite;\n _this.draw = _this.drawRect;\n }\n\n if (properties.update) {\n _this.update = properties.update;\n }\n\n if (properties.render) {\n _this.render = properties.render;\n }\n\n // loop through all additional properties and add them to the sprite\n for (var prop in properties.properties) {\n if (properties.properties.hasOwnProperty(prop)) {\n _this[prop] = properties.properties[prop];\n }\n }\n },\n\n /**\n * Simple bounding box collision test.\n * @memberof kontra.sprite\n *\n * @param {object} object - Object to check collision against.\n *\n * @returns {boolean} True if the objects collide, false otherwise.\n */\n collidesWith: function collidesWith(object) {\n // handle non-kontra.sprite objects as well as kontra.sprite objects\n var x = (object.x !== undefined ? object.x : object.position.x);\n var y = (object.y !== undefined ? object.y : object.position.y);\n\n if (this.position.x < x + object.width &&\n this.position.x + this.width > x &&\n this.position.y < y + object.height &&\n this.position.y + this.height > y) {\n return true;\n }\n\n return false;\n },\n\n /**\n * Update the sprites velocity and position.\n * @memberof kontra.sprite\n * @abstract\n *\n * @param {number} dt - Time since last update.\n *\n * This function can be overridden on a per sprite basis if more functionality\n * is needed in the update step. Just call this.advance() when you need\n * the sprite to update its position.\n *\n * @example\n * sprite = kontra.sprite({\n * update: function update(dt) {\n * // do some logic\n *\n * this.advance(dt);\n * }\n * });\n */\n update: function update(dt) {\n this.advance(dt);\n },\n\n /**\n * Render the sprite.\n * @memberof kontra.sprite.\n * @abstract\n *\n * This function can be overridden on a per sprite basis if more functionality\n * is needed in the render step. Just call this.draw() when you need the\n * sprite to draw its image.\n *\n * @example\n * sprite = kontra.sprite({\n * render: function render() {\n * // do some logic\n *\n * this.draw();\n * }\n * });\n */\n render: function render() {\n this.draw();\n }\n };\n\n return kontra;\n})(kontra || {}, Math);","/*jshint -W084 */\n\nvar kontra = (function(kontra, undefined) {\n 'use strict';\n\n /**\n * Single animation from a sprite sheet.\n * @memberof kontra\n *\n * @see kontra.pool._proto.set for list of parameters.\n */\n kontra.animation = function(properties) {\n var animation = Object.create(kontra.animation._proto);\n animation.set(properties);\n\n return animation;\n };\n\n kontra.animation._proto = {\n /**\n * Set properties on the animation.\n * @memberof kontra.animation\n *\n * @param {object} properties - Properties of the animation.\n * @param {spriteSheet} properties.spriteSheet - Sprite sheet for the animation.\n * @param {number[]} properties.frames - List of frames of the animation.\n * @param {number} properties.frameSpeed - Time to wait before transitioning the animation to the next frame.\n */\n set: function set(properties) {\n properties = properties || {};\n\n this.spriteSheet = properties.spriteSheet;\n this.frames = properties.frames;\n this.frameSpeed = properties.frameSpeed;\n\n this.width = properties.spriteSheet.frame.width;\n this.height = properties.spriteSheet.frame.height;\n\n this.currentFrame = 0;\n this._accumulator = 0;\n this.update = this.advance;\n this.render = this.draw;\n },\n\n /**\n * Update the animation. Used when the animation is not paused or stopped.\n * @memberof kontra.animation\n * @private\n *\n * @param {number} dt=1 - Time since last update.\n */\n advance: function advance(dt) {\n // normalize dt to work with milliseconds as a decimal or an integer\n dt = (dt < 1 ? dt * 1E3 : dt) || 1;\n\n this._accumulator += dt;\n\n // update to the next frame if it's time\n while (this._accumulator >= this.frameSpeed) {\n this.currentFrame = ++this.currentFrame % this.frames.length;\n\n this._accumulator -= this.frameSpeed;\n }\n },\n\n /**\n * Draw the current frame. Used when the animation is not stopped.\n * @memberof kontra.animation\n * @private\n *\n * @param {object} properties - How to draw the animation.\n * @param {integer} properties.x - X position to draw\n * @param {integer} properties.y - Y position to draw\n * @param {Context} [properties.context=kontra.context] - Provide a context for the sprite to draw on.\n */\n draw: function draw(properties) {\n properties = properties || {};\n\n var context = properties.context || kontra.context;\n\n // get the row and col of the frame\n var row = this.frames[this.currentFrame] / this.spriteSheet.framesPerRow | 0;\n var col = this.frames[this.currentFrame] % this.spriteSheet.framesPerRow | 0;\n\n context.drawImage(\n this.spriteSheet.image,\n col * this.spriteSheet.frame.width, row * this.spriteSheet.frame.height,\n this.spriteSheet.frame.width, this.spriteSheet.frame.height,\n properties.x, properties.y,\n this.spriteSheet.frame.width, this.spriteSheet.frame.height\n );\n },\n\n /**\n * Play the animation.\n * @memberof kontra.animation\n */\n play: function play() {\n // restore references to update and render functions only if overridden\n this.update = this.advance;\n this.render = this.draw;\n },\n\n /**\n * Stop the animation and prevent update and render.\n * @memberof kontra.animation\n */\n stop: function stop() {\n\n // instead of putting an if statement in both render/update functions that checks\n // a variable to determine whether to render or update, we can just reassign the\n // functions to noop and save processing time in the game loop.\n // @see http://jsperf.com/boolean-check-vs-noop\n this.update = kontra.noop;\n this.render = kontra.noop;\n },\n\n /**\n * Pause the animation and prevent update.\n * @memberof kontra.animation\n */\n pause: function pause() {\n this.update = kontra.noop;\n }\n };\n\n\n\n\n\n\n /**\n * Create a sprite sheet from an image.\n * @memberof kontra\n *\n * @see kontra.spriteSheet._proto.set for list of parameters.\n */\n kontra.spriteSheet = function(properties) {\n var spriteSheet = Object.create(kontra.spriteSheet._proto);\n spriteSheet.set(properties);\n\n return spriteSheet;\n };\n\n kontra.spriteSheet._proto = {\n /**\n * Set properties on the spriteSheet.\n * @memberof kontra\n * @constructor\n *\n * @param {object} properties - Configure the sprite sheet.\n * @param {Image|Canvas} properties.image - Image for the sprite sheet.\n * @param {number} properties.frameWidth - Width (in px) of each frame.\n * @param {number} properties.frameHeight - Height (in px) of each frame.\n * @param {object} properties.animations - Animations to create from the sprite sheet.\n */\n set: function set(properties) {\n properties = properties || {};\n\n this.animations = {};\n\n if (kontra.isImage(properties.image) || kontra.isCanvas(properties.image)) {\n this.image = properties.image;\n this.frame = {\n width: properties.frameWidth,\n height: properties.frameHeight\n };\n\n this.framesPerRow = properties.image.width / properties.frameWidth | 0;\n }\n else {\n var error = new SyntaxError('Invalid image.');\n kontra.logError(error, 'You must provide an Image for the SpriteSheet.');\n return;\n }\n\n if (properties.animations) {\n this.createAnimations(properties.animations);\n }\n },\n\n /**\n * Create animations from the sprite sheet.\n * @memberof kontra.spriteSheet\n *\n * @param {object} animations - List of named animations to create from the Image.\n * @param {number|string|number[]|string[]} animations.animationName.frames - A single frame or list of frames for this animation.\n * @param {number} animations.animationName.frameSpeed=1 - Number of frames to wait before transitioning the animation to the next frame.\n *\n * @example\n * var sheet = kontra.spriteSheet({image: img, frameWidth: 16, frameHeight: 16});\n * sheet.createAnimations({\n * idle: {\n * frames: 1 // single frame animation\n * },\n * walk: {\n * frames: '2..6', // ascending consecutive frame animation (frames 2-6, inclusive)\n * frameSpeed: 4\n * },\n * moonWalk: {\n * frames: '6..2', // descending consecutive frame animation\n * frameSpeed: 4\n * },\n * jump: {\n * frames: [7, 12, 2], // non-consecutive frame animation\n * frameSpeed: 3\n * },\n * attack: {\n * frames: ['8..10', 13, '10..8'], // you can also mix and match, in this case frames [8,9,10,13,10,9,8]\n * frameSpeed: 2\n * }\n * });\n */\n createAnimations: function createAnimations(animations) {\n var error;\n\n if (!animations || Object.keys(animations).length === 0) {\n error = new ReferenceError('No animations found.');\n kontra.logError(error, 'You must provide at least one named animation to create an Animation.');\n return;\n }\n\n // create each animation by parsing the frames\n var animation, frames, frameSpeed, sequence;\n for (var name in animations) {\n if (!animations.hasOwnProperty(name)) {\n continue;\n }\n\n animation = animations[name];\n frames = animation.frames;\n frameSpeed = animation.frameSpeed;\n\n // array that holds the order of the animation\n sequence = [];\n\n if (frames === undefined) {\n error = new ReferenceError('No animation frames found.');\n kontra.logError(error, 'Animation ' + name + ' must provide a frames property.');\n return;\n }\n\n // single frame\n if (kontra.isNumber(frames)) {\n sequence.push(frames);\n }\n // consecutive frames\n else if (kontra.isString(frames)) {\n sequence = this._parseFrames(frames);\n }\n // non-consecutive frames\n else if (kontra.isArray(frames)) {\n for (var i = 0, frame; frame = frames[i]; i++) {\n\n // consecutive frames\n if (kontra.isString(frame)) {\n\n // add new frames to the end of the array\n sequence.push.apply(sequence, this._parseFrames(frame));\n }\n // single frame\n else {\n sequence.push(frame);\n }\n }\n }\n\n this.animations[name] = kontra.animation({\n spriteSheet: this,\n frames: sequence,\n frameSpeed: frameSpeed\n });\n }\n },\n\n /**\n * Parse a string of consecutive frames.\n * @memberof kontra.spriteSheet\n * @private\n *\n * @param {string} frames - Start and end frame.\n *\n * @returns {number[]} List of frames.\n */\n _parseFrames: function parseFrames(frames) {\n var sequence = [];\n var consecutiveFrames = frames.split('..').map(Number);\n\n // determine which direction to loop\n var direction = (consecutiveFrames[0] < consecutiveFrames[1] ? 1 : -1);\n var i;\n\n // ascending frame order\n if (direction === 1) {\n for (i = consecutiveFrames[0]; i <= consecutiveFrames[1]; i++) {\n sequence.push(i);\n }\n }\n // descending order\n else {\n for (i = consecutiveFrames[0]; i >= consecutiveFrames[1]; i--) {\n sequence.push(i);\n }\n }\n\n return sequence;\n }\n };\n\n return kontra;\n})(kontra || {});","/**\n * localStorage can be a bit of a pain to work with since it stores everything as strings:\n * localStorage.setItem('item', 1); //=> '1'\n * localStorage.setItem('item', false); //=> 'false'\n * localStorage.setItem('item', [1,2,3]); //=> '1,2,3'\n * localStorage.setItem('item', {a:'b'}); //=> '[object Object]'\n * localStorage.setItem('item', undefinedVariable); //=> 'undefined'\n *\n * @fileoverview A simple wrapper for localStorage to make it easier to work with.\n * Based on store.js {@see https://github.com/marcuswestin/store.js}\n */\nvar kontra = (function(kontra, window, localStorage, undefined) {\n 'use strict';\n\n // check if the browser can use localStorage\n kontra.canUse = kontra.canUse || {};\n kontra.canUse.localStorage = 'localStorage' in window && window.localStorage !== null;\n\n if (!kontra.canUse.localStorage) {\n return kontra;\n }\n\n /**\n * Object for using localStorage.\n */\n kontra.store = {};\n\n /**\n * Save an item to localStorage.\n * @memberof kontra.store\n *\n * @param {string} key - Name to store the item as.\n * @param {*} value - Item to store.\n */\n kontra.store.set = function setStoreItem(key, value) {\n if (value === undefined) {\n this.remove(key);\n }\n else {\n localStorage.setItem(key, JSON.stringify(value));\n }\n };\n\n /**\n * Retrieve an item from localStorage and convert it back to it's original type.\n * @memberof kontra.store\n *\n * @param {string} key - Name of the item.\n *\n * @returns {*}\n */\n kontra.store.get = function getStoreItem(key) {\n var value = localStorage.getItem(key);\n\n try {\n value = JSON.parse(value);\n }\n catch(e) {}\n\n return value;\n };\n\n /**\n * Remove an item from localStorage.\n * @memberof kontra.store\n *\n * @param {string} key - Name of the item.\n */\n kontra.store.remove = function removeStoreItem(key) {\n localStorage.removeItem(key);\n };\n\n /**\n * Clear all keys from localStorage.\n * @memberof kontra.store\n */\n kontra.store.clear = function clearStore() {\n localStorage.clear();\n };\n\n return kontra;\n})(kontra || {}, window, window.localStorage);"],"sourceRoot":"/source/"} \ No newline at end of file +{"version":3,"sources":["kontraAssetLoader.js","core.js","gameLoop.js","keyboard.js","pool.js","quadtree.js","sprite.js","spriteSheet.js","store.js"],"names":["qFactory","nextTick","exceptionHandler","forEach","obj","iterator","context","key","isFunction","hasOwnProperty","call","isArray","length","defaultCallback","value","defaultErrback","reason","reject","all","promises","deferred","defer","counter","results","promise","ref","then","resolve","notify","toString","pending","val","callbacks","undefined","callback","i","ii","createInternalRejectedPromise","progress","errback","progressback","result","wrappedCallback","e","wrappedErrback","wrappedProgressback","push","catch","this","finally","makePromise","resolved","handleCallback","isResolved","callbackOutput","error","when","done","window","q","setTimeout","console","stack","kontra","isImage","isAudio","images","audios","data","assetPaths","audio","Audio","canUse","wav","mp3","canPlayType","replace","ogg","aac","m4a","getAssetExtension","url","substr","lastIndexOf","getAssetType","extension","match","getAssetName","loadAssets","type","numLoaded","numAssets","arguments","asset","Array","assetDeferred","loaded","total","loadImage","name","image","Image","onload","onerror","src","loadAudio","source","playableSource","addEventListener","preload","load","loadData","req","XMLHttpRequest","dataUrl","status","responseText","json","JSON","parse","open","send","bundles","createBundle","bundle","assets","loadBundles","apply","loadManifest","manifest","imagePath","audioPath","dataPath","Object","keys","document","init","properties","isString","canvas","getElementById","isCanvas","getElementsByTagName","ReferenceError","logError","getContext","game","width","height","message","noop","isNumber","nodeName","toLowerCase","timestamp","performance","now","Date","getTime","gameLoop","create","prototype","set","update","render","isStopped","_accumulator","_delta","fps","frame","_this","_rAF","requestAnimationFrame","bind","_now","_dt","_last","start","stop","cancelAnimationFrame","normalizeKeyCode","which","keyCode","normalizeKeys","combination","trim","modifier","modifierOrder","indexOf","shiftKeys","join","getKeyCombination","keyMap","keydownEventHandler","split","pressedKeys","preventDefault","keyupEventHandler","aliases","blurEventHandler",8,9,13,16,17,18,20,27,32,33,34,35,36,37,38,39,40,45,46,91,92,93,144,145,106,107,109,110,111,186,187,188,189,190,191,192,219,220,221,222,"String","fromCharCode","~","!","@","#","$","%","^","&","*","(",")","_","+",":","\"","<",">","?","|","plus","leftwindow","select","SyntaxError","unbind","pressed","pool","createProperties","isAlive","objects","size","maxSize","Infinity","lastIndex","inUse","fill","unshift","get","x","getAliveObjects","slice","clear","index","Math","max","j","quadtree","depth","maxDepth","maxObjects","isBranchNode","parentNode","bounds","y","subnodes","object","indices","node","_getIndex","add","_addToSubnode","_split","verticalMidpoint","horizontalMidpoint","position","intersectsTopQuadrants","intersectsBottomQuadrants","subWidth","subHeight","strokeStyle","strokeRect","vector","dt","clamp","xMin","yMin","xMax","yMax","min","sprite","advanceSprite","velocity","acceleration","timeToLive","drawRect","fillStyle","color","fillRect","drawImage","advanceAnimation","currentAnimation","drawAnimation","playAnimation","animations","dx","dy","ddx","ddy","advance","draw","prop","collidesWith","animation","spriteSheet","frames","frameSpeed","currentFrame","row","framesPerRow","col","play","pause","frameWidth","frameHeight","createAnimations","sequence","_parseFrames","consecutiveFrames","map","Number","direction","localStorage","store","remove","setItem","stringify","getItem","removeItem"],"mappings":"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","file":"kontra.min.js","sourcesContent":["/**\n * The MIT License\n *\n * Copyright (c) 2010-2012 Google, Inc. http://angularjs.org\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\nwindow.q = qFactory(function(callback) {\n setTimeout(function() {\n callback();\n }, 0);\n}, function(e) {\n console.error('qLite: ' + e.stack);\n});\n\n/**\n * Constructs a promise manager.\n *\n * @param {function(Function)} nextTick Function for executing functions in the next turn.\n * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for\n * debugging purposes.\n * @returns {object} Promise manager.\n */\nfunction qFactory(nextTick, exceptionHandler) {\n var toString = ({}).toString;\n var isFunction = function isFunction(value){return typeof value == 'function';};\n var isArray = function isArray(value) {return toString.call(value) === '[object Array]';};\n\n function forEach(obj, iterator, context) {\n var key;\n if (obj) {\n if (isFunction(obj)) {\n for (key in obj) {\n // Need to check if hasOwnProperty exists,\n // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function\n if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {\n iterator.call(context, obj[key], key);\n }\n }\n } else if (obj.forEach && obj.forEach !== forEach) {\n obj.forEach(iterator, context);\n } else if (isArray(obj)) {\n for (key = 0; key < obj.length; key++)\n iterator.call(context, obj[key], key);\n } else {\n for (key in obj) {\n if (obj.hasOwnProperty(key)) {\n iterator.call(context, obj[key], key);\n }\n }\n }\n }\n return obj;\n }\n\n /**\n * @ngdoc method\n * @name $q#defer\n * @function\n *\n * @description\n * Creates a `Deferred` object which represents a task which will finish in the future.\n *\n * @returns {Deferred} Returns a new instance of deferred.\n */\n var defer = function() {\n var pending = [],\n value, deferred;\n\n deferred = {\n\n resolve: function(val) {\n if (pending) {\n var callbacks = pending;\n pending = undefined;\n value = ref(val);\n\n if (callbacks.length) {\n nextTick(function() {\n var callback;\n for (var i = 0, ii = callbacks.length; i < ii; i++) {\n callback = callbacks[i];\n value.then(callback[0], callback[1], callback[2]);\n }\n });\n }\n }\n },\n\n\n reject: function(reason) {\n deferred.resolve(createInternalRejectedPromise(reason));\n },\n\n\n notify: function(progress) {\n if (pending) {\n var callbacks = pending;\n\n if (pending.length) {\n nextTick(function() {\n var callback;\n for (var i = 0, ii = callbacks.length; i < ii; i++) {\n callback = callbacks[i];\n callback[2](progress);\n }\n });\n }\n }\n },\n\n\n promise: {\n then: function(callback, errback, progressback) {\n var result = defer();\n\n var wrappedCallback = function(value) {\n try {\n result.resolve((isFunction(callback) ? callback : defaultCallback)(value));\n } catch(e) {\n result.reject(e);\n exceptionHandler(e);\n }\n };\n\n var wrappedErrback = function(reason) {\n try {\n result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));\n } catch(e) {\n result.reject(e);\n exceptionHandler(e);\n }\n };\n\n var wrappedProgressback = function(progress) {\n try {\n result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));\n } catch(e) {\n exceptionHandler(e);\n }\n };\n\n if (pending) {\n pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);\n } else {\n value.then(wrappedCallback, wrappedErrback, wrappedProgressback);\n }\n\n return result.promise;\n },\n\n \"catch\": function(callback) {\n return this.then(null, callback);\n },\n\n \"finally\": function(callback) {\n\n function makePromise(value, resolved) {\n var result = defer();\n if (resolved) {\n result.resolve(value);\n } else {\n result.reject(value);\n }\n return result.promise;\n }\n\n function handleCallback(value, isResolved) {\n var callbackOutput = null;\n try {\n callbackOutput = (callback ||defaultCallback)();\n } catch(e) {\n return makePromise(e, false);\n }\n if (callbackOutput && isFunction(callbackOutput.then)) {\n return callbackOutput.then(function() {\n return makePromise(value, isResolved);\n }, function(error) {\n return makePromise(error, false);\n });\n } else {\n return makePromise(value, isResolved);\n }\n }\n\n return this.then(function(value) {\n return handleCallback(value, true);\n }, function(error) {\n return handleCallback(error, false);\n });\n }\n }\n };\n\n return deferred;\n };\n\n\n var ref = function(value) {\n if (value && isFunction(value.then)) return value;\n return {\n then: function(callback) {\n var result = defer();\n nextTick(function() {\n result.resolve(callback(value));\n });\n return result.promise;\n }\n };\n };\n\n\n /**\n * @ngdoc method\n * @name $q#reject\n * @function\n *\n * @description\n * Creates a promise that is resolved as rejected with the specified `reason`. This api should be\n * used to forward rejection in a chain of promises. If you are dealing with the last promise in\n * a promise chain, you don't need to worry about it.\n *\n * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of\n * `reject` as the `throw` keyword in JavaScript. This also means that if you \"catch\" an error via\n * a promise error callback and you want to forward the error to the promise derived from the\n * current promise, you have to \"rethrow\" the error by returning a rejection constructed via\n * `reject`.\n *\n * ```js\n * promiseB = promiseA.then(function(result) {\n * // success: do something and resolve promiseB\n * // with the old or a new result\n * return result;\n * }, function(reason) {\n * // error: handle the error if possible and\n * // resolve promiseB with newPromiseOrValue,\n * // otherwise forward the rejection to promiseB\n * if (canHandle(reason)) {\n * // handle the error and recover\n * return newPromiseOrValue;\n * }\n * return $q.reject(reason);\n * });\n * ```\n *\n * @param {*} reason Constant, message, exception or an object representing the rejection reason.\n * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.\n */\n var reject = function(reason) {\n var result = defer();\n result.reject(reason);\n return result.promise;\n };\n\n var createInternalRejectedPromise = function(reason) {\n return {\n then: function(callback, errback) {\n var result = defer();\n nextTick(function() {\n try {\n result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));\n } catch(e) {\n result.reject(e);\n exceptionHandler(e);\n }\n });\n return result.promise;\n }\n };\n };\n\n\n /**\n * @ngdoc method\n * @name $q#when\n * @function\n *\n * @description\n * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.\n * This is useful when you are dealing with an object that might or might not be a promise, or if\n * the promise comes from a source that can't be trusted.\n *\n * @param {*} value Value or a promise\n * @returns {Promise} Returns a promise of the passed value or promise\n */\n var when = function(value, callback, errback, progressback) {\n var result = defer(),\n done;\n\n var wrappedCallback = function(value) {\n try {\n return (isFunction(callback) ? callback : defaultCallback)(value);\n } catch (e) {\n exceptionHandler(e);\n return reject(e);\n }\n };\n\n var wrappedErrback = function(reason) {\n try {\n return (isFunction(errback) ? errback : defaultErrback)(reason);\n } catch (e) {\n exceptionHandler(e);\n return reject(e);\n }\n };\n\n var wrappedProgressback = function(progress) {\n try {\n return (isFunction(progressback) ? progressback : defaultCallback)(progress);\n } catch (e) {\n exceptionHandler(e);\n }\n };\n\n nextTick(function() {\n ref(value).then(function(value) {\n if (done) return;\n done = true;\n result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));\n }, function(reason) {\n if (done) return;\n done = true;\n result.resolve(wrappedErrback(reason));\n }, function(progress) {\n if (done) return;\n result.notify(wrappedProgressback(progress));\n });\n });\n\n return result.promise;\n };\n\n\n function defaultCallback(value) {\n return value;\n }\n\n\n function defaultErrback(reason) {\n return reject(reason);\n }\n\n\n /**\n * @ngdoc method\n * @name $q#all\n * @function\n *\n * @description\n * Combines multiple promises into a single promise that is resolved when all of the input\n * promises are resolved.\n *\n * @param {Array.|Object.} promises An array or hash of promises.\n * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,\n * each value corresponding to the promise at the same index/key in the `promises` array/hash.\n * If any of the promises is resolved with a rejection, this resulting promise will be rejected\n * with the same rejection value.\n */\n function all(promises) {\n var deferred = defer(),\n counter = 0,\n results = isArray(promises) ? [] : {};\n\n forEach(promises, function(promise, key) {\n counter++;\n ref(promise).then(function(value) {\n if (results.hasOwnProperty(key)) return;\n results[key] = value;\n if (!(--counter)) deferred.resolve(results);\n }, function(reason) {\n if (results.hasOwnProperty(key)) return;\n deferred.reject(reason);\n }, function(reason) {\n if (results.hasOwnProperty(key)) return;\n deferred.notify(reason);\n });\n });\n\n if (counter === 0) {\n deferred.resolve(results);\n }\n\n return deferred.promise;\n }\n\n return {\n defer: defer,\n reject: reject,\n when: when,\n all: all\n };\n}\nvar kontra = (function(kontra) {\n var isImage = /(jpeg|jpg|gif|png)$/;\n var isAudio = /(wav|mp3|ogg|aac|m4a)$/;\n var folderSeparator = /(\\\\|\\/)/g;\n\n // all assets are stored by name as well as by URL\n kontra.images = {};\n kontra.audios = {};\n kontra.data = {};\n\n // base asset path for determining asset URLs\n kontra.assetPaths = {\n images: '',\n audios: '',\n data: '',\n };\n\n // audio playability\n // @see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/audio.js\n var audio = new Audio();\n kontra.canUse = kontra.canUse || {};\n kontra.canUse.wav = '';\n kontra.canUse.mp3 = audio.canPlayType('audio/mpeg;').replace(/^no$/,'');\n kontra.canUse.ogg = audio.canPlayType('audio/ogg; codecs=\"vorbis\"').replace(/^no$/,'');\n kontra.canUse.aac = audio.canPlayType('audio/aac;').replace(/^no$/,'');\n kontra.canUse.m4a = (audio.canPlayType('audio/x-m4a;') || kontra.canUse.aac).replace(/^no$/,'');\n\n /**\n * Get the extension of an asset.\n * @see http://jsperf.com/extract-file-extension\n * @memberOf kontra\n *\n * @param {string} url - The URL to the asset.\n *\n * @returns {string}\n */\n kontra.getAssetExtension = function getAssetExtension(url) {\n return url.substr((~-url.lastIndexOf(\".\") >>> 0) + 2);\n };\n\n /**\n * Get the type of asset based on its extension.\n * @memberOf kontra\n *\n * @param {string} url - The URL to the asset.\n *\n * @returns {string} Image, Audio, Data.\n */\n kontra.getAssetType = function getAssetType(url) {\n var extension = this.getAssetExtension(url);\n\n if (extension.match(isImage)) {\n return 'Image';\n }\n else if (extension.match(isAudio)) {\n return 'Audio';\n }\n else {\n return 'Data';\n }\n };\n\n /**\n * Get the name of an asset.\n * @memberOf kontra\n *\n * @param {string} url - The URL to the asset.\n *\n * @returns {string}\n */\n kontra.getAssetName = function getAssetName(url) {\n return url.replace(/\\.[^/.]+$/, \"\");\n };\n\n return kontra;\n})(kontra || {});\n/*jshint -W084 */\n\nvar kontra = (function(kontra, q) {\n /**\n * Load an Image, Audio, or data file.\n * @memberOf kontra\n *\n * @param {string|string[]} - Comma separated list of assets to load.\n *\n * @returns {Promise} A deferred promise.\n *\n * @example\n * kontra.loadAsset('car.png');\n * kontra.loadAsset(['explosion.mp3', 'explosion.ogg']);\n * kontra.loadAsset('bio.json');\n * kontra.loadAsset('car.png', ['explosion.mp3', 'explosion.ogg'], 'bio.json');\n */\n kontra.loadAssets = function loadAsset() {\n var deferred = q.defer();\n var promises = [];\n var numLoaded = 0;\n var numAssets = arguments.length;\n var type, name, url;\n\n if (!arguments.length) {\n deferred.resolve();\n }\n\n for (var i = 0, asset; asset = arguments[i]; i++) {\n if (!Array.isArray(asset)) {\n url = asset;\n }\n else {\n url = asset[0];\n }\n\n type = this.getAssetType(url);\n\n // create a closure for event binding\n (function(assetDeferred) {\n promises.push(assetDeferred.promise);\n\n kontra['load' + type](url).then(\n function loadAssetSuccess() {\n assetDeferred.resolve();\n deferred.notify({'loaded': ++numLoaded, 'total': numAssets});\n },\n function loadAssetError(error) {\n assetDeferred.reject(error);\n });\n })(q.defer());\n }\n\n q.all(promises).then(\n function loadAssetsSuccess() {\n deferred.resolve();\n },\n function loadAssetsError(error) {\n deferred.reject(error);\n });\n\n return deferred.promise;\n };\n\n /**\n * Load an Image file. Uses assetPaths.images to resolve URL.\n * @memberOf kontra\n *\n * @param {string} url - The URL to the Image file.\n *\n * @returns {Promise} A deferred promise. Promise resolves with the Image.\n *\n * @example\n * kontra.loadImage('car.png');\n * kontra.loadImage('autobots/truck.png');\n */\n kontra.loadImage = function(url) {\n var deferred = q.defer();\n var name = this.getAssetName(url);\n var image = new Image();\n\n url = this.assetPaths.images + url;\n\n image.onload = function loadImageOnLoad() {\n kontra.images[name] = kontra.images[url] = this;\n deferred.resolve(this);\n };\n\n image.onerror = function loadImageOnError() {\n deferred.reject('Unable to load image ' + url);\n };\n\n image.src = url;\n\n return deferred.promise;\n };\n\n /**\n * Load an Audio file. Supports loading multiple audio formats which will be resolved by\n * the browser in the order listed. Uses assetPaths.audios to resolve URL.\n * @memberOf kontra\n *\n * @param {string|string[]} url - The URL to the Audio file.\n *\n * @returns {Promise} A deferred promise. Promise resolves with the Audio.\n *\n * @example\n * kontra.loadAudio('sound_effects/laser.mp3');\n * kontra.loadAudio(['explosion.mp3', 'explosion.m4a', 'explosion.ogg']);\n *\n * There are two ways to load Audio in the web: HTML5 Audio or the Web Audio API.\n * HTML5 Audio has amazing browser support, including back to IE9\n * (http://caniuse.com/#feat=audio). However, the web Audio API isn't supported in\n * IE nor Android Browsers (http://caniuse.com/#search=Web%20Audio%20API).\n *\n * To support the most browsers we'll use HTML5 Audio. However, doing so means we'll\n * have to work around mobile device limitations as well as Audio implementation\n * limitations.\n *\n * Android browsers require playing Audio through user interaction whereas iOS 6+ can\n * play through normal JavaScript. Moreover, Android can only play one sound source at\n * a time whereas iOS 6+ can handle more than one. See this article for more details\n * (http://pupunzi.open-lab.com/2013/03/13/making-html5-audio-actually-work-on-mobile/)\n *\n * Both iOS and Android will download an Audio through JavaScript, but neither will play\n * it until user interaction. You can get around this issue by having a splash screen\n * that requires user interaction to start the game and using that event to play the audio.\n * (http://jsfiddle.net/straker/5dsm6jgt/)\n */\n kontra.loadAudio = function(url) {\n var deferred = q.defer();\n var source, name, playableSource, audio;\n\n if (!Array.isArray(url)) {\n url = [url];\n }\n\n // determine which audio format the browser can play\n for (var i = 0; source = url[i]; i++) {\n if ( this.canUse[this.getAssetExtension(source)] ) {\n playableSource = source;\n break;\n }\n }\n\n if (!playableSource) {\n deferred.reject('Browser cannot play any of the audio formats provided');\n }\n else {\n name = this.getAssetName(playableSource);\n audio = new Audio();\n\n source = this.assetPaths.audios + playableSource;\n\n audio.addEventListener('canplay', function loadAudioOnLoad() {\n kontra.audios[name] = kontra.audios[source] = this;\n deferred.resolve(this);\n });\n\n audio.onerror = function loadAudioOnError() {\n deferred.reject('Unable to load audio ' + source);\n };\n\n audio.src = source;\n audio.preload = 'auto';\n audio.load();\n }\n\n return deferred.promise;\n };\n\n\n /**\n * Load a data file (be it text or JSON). Uses assetPaths.data to resolve URL.\n * @memberOf kontra\n *\n * @param {string} url - The URL to the data file.\n *\n * @returns {Promise} A deferred promise. Resolves with the data or parsed JSON.\n *\n * @example\n * kontra.loadData('bio.json');\n * kontra.loadData('dialog.txt');\n */\n kontra.loadData = function(url) {\n var deferred = q.defer();\n var req = new XMLHttpRequest();\n var name = this.getAssetName(url);\n var dataUrl = this.assetPaths.data + url;\n\n req.addEventListener('load', function loadDataOnLoad() {\n if (req.status !== 200) {\n deferred.reject(req.responseText);\n return;\n }\n\n try {\n var json = JSON.parse(req.responseText);\n kontra.data[name] = kontra.data[dataUrl] = json;\n\n deferred.resolve(json);\n }\n catch(e) {\n var data = req.responseText;\n kontra.data[name] = kontra.data[dataUrl] = data;\n\n deferred.resolve(data);\n }\n });\n\n req.open('GET', dataUrl, true);\n req.send();\n\n return deferred.promise;\n };\n\n return kontra;\n})(kontra || {}, q);\n/*jshint -W084 */\n\nvar kontra = (function(kontra, q) {\n kontra.bundles = {};\n\n /**\n * Create a group of assets that can be loaded using kontra.loadBundle().\n * @memberOf kontra\n *\n * @param {string} bundle - The name of the bundle.\n * @param {string[]} assets - Assets to add to the bundle.\n *\n * @example\n * kontra.createBundle('myBundle', ['car.png', ['explosion.mp3', 'explosion.ogg']]);\n */\n kontra.createBundle = function createBundle(bundle, assets) {\n if (this.bundles[bundle]) {\n return;\n }\n\n this.bundles[bundle] = assets || [];\n };\n\n /**\n * Load all assets that are part of a bundle.\n * @memberOf kontra\n *\n * @param {string|string[]} - Comma separated list of bundles to load.\n *\n * @returns {Promise} A deferred promise.\n *\n * @example\n * kontra.loadBundles('myBundle');\n * kontra.loadBundles('myBundle', 'myOtherBundle');\n */\n kontra.loadBundles = function loadBundles() {\n var deferred = q.defer();\n var promises = [];\n var numLoaded = 0;\n var numAssets = 0;\n var assets;\n\n for (var i = 0, bundle; bundle = arguments[i]; i++) {\n if (!(assets = this.bundles[bundle])) {\n deferred.reject('Bundle \\'' + bundle + '\\' has not been created.');\n continue;\n }\n\n numAssets += assets.length;\n\n promises.push(this.loadAssets.apply(this, assets));\n }\n\n q.all(promises).then(\n function loadBundlesSuccess() {\n deferred.resolve();\n },\n function loadBundlesError(error) {\n deferred.reject(error);\n },\n function loadBundlesNofity() {\n deferred.notify({'loaded': ++numLoaded, 'total': numAssets});\n });\n\n return deferred.promise;\n };\n\n return kontra;\n})(kontra || {}, q);\n/*jshint -W084 */\n\nvar kontra = (function(kontra, q) {\n /**\n * Load an asset manifest file.\n * @memberOf kontra\n *\n * @param {string} url - The URL to the asset manifest file.\n *\n * @returns {Promise} A deferred promise.\n */\n kontra.loadManifest = function loadManifest(url) {\n var deferred = q.defer();\n var bundles;\n\n kontra.loadData(url).then(\n function loadManifestSuccess(manifest) {\n kontra.assetPaths.images = manifest.imagePath || '';\n kontra.assetPaths.audios = manifest.audioPath || '';\n kontra.assetPaths.data = manifest.dataPath || '';\n\n // create bundles and add assets\n for (var i = 0, bundle; bundle = manifest.bundles[i]; i++) {\n kontra.createBundle(bundle.name, bundle.assets);\n }\n\n if (!manifest.loadBundles) {\n deferred.resolve();\n return;\n }\n\n // load all bundles\n if (manifest.loadBundles === 'all') {\n bundles = Object.keys(kontra.bundles || {});\n }\n // load a single bundle\n else if (!Array.isArray(manifest.loadBundles)) {\n bundles = [manifest.loadBundles];\n }\n // load multiple bundles\n else {\n bundles = manifest.loadBundles;\n }\n\n kontra.loadBundles.apply(kontra, bundles).then(\n function loadBundlesSuccess() {\n deferred.resolve();\n },\n function loadBundlesError(error) {\n deferred.reject(error);\n },\n function loadBundlesNotify(progress) {\n deferred.notify(progress);\n });\n },\n function loadManifestError(error) {\n deferred.reject(error);\n });\n\n return deferred.promise;\n };\n\n return kontra;\n})(kontra || {}, q);","/* global console */\n\nvar kontra = (function(kontra, document) {\n 'use strict';\n\n /**\n * Set up the canvas.\n * @memberof kontra\n *\n * @param {object} properties - Properties for the game.\n * @param {string|Canvas} properties.canvas - Main canvas ID or Element for the game.\n */\n kontra.init = function init(properties) {\n properties = properties || {};\n\n if (kontra.isString(properties.canvas)) {\n this.canvas = document.getElementById(properties.canvas);\n }\n else if (kontra.isCanvas(properties.canvas)) {\n this.canvas = properties.canvas;\n }\n else {\n this.canvas = document.getElementsByTagName('canvas')[0];\n\n if (!this.canvas) {\n var error = new ReferenceError('No canvas element found.');\n kontra.logError(error, 'You must provide a canvas element for the game.');\n return;\n }\n }\n\n this.context = this.canvas.getContext('2d');\n this.game = {\n width: this.canvas.width,\n height: this.canvas.height\n };\n };\n\n /**\n * Throw an error message to the user with readable formating.\n * @memberof kontra\n *\n * @param {Error} error - Error object.\n * @param {string} message - Error message.\n */\n kontra.logError = function logError(error, message) {\n console.error('Kontra: ' + message + '\\n\\t' + error.stack);\n };\n\n /**\n * Noop function.\n * @memberof kontra\n */\n kontra.noop = function noop() {};\n\n /**\n * Determine if a value is an Array.\n * @memberof kontra\n *\n * @param {*} value - Value to test.\n *\n * @returns {boolean}\n */\n kontra.isArray = Array.isArray;\n\n /**\n * Determine if a value is a String.\n * @memberof kontra\n *\n * @param {*} value - Value to test.\n *\n * @returns {boolean}\n */\n kontra.isString = function isString(value) {\n return typeof value === 'string';\n };\n\n /**\n * Determine if a value is a Number.\n * @memberof kontra\n *\n * @param {*} value - Value to test.\n *\n * @returns {boolean}\n */\n kontra.isNumber = function isNumber(value) {\n return typeof value === 'number';\n };\n\n /**\n * Determine if a value is an Image.\n * @memberof kontra\n *\n * @param {*} value - Value to test.\n *\n * @returns {boolean}\n */\n kontra.isImage = function isImage(value) {\n return value && value.nodeName.toLowerCase() === 'img';\n };\n\n /**\n * Determine if a value is a Canvas.\n * @memberof kontra\n *\n * @param {*} value - Value to test.\n *\n * @returns {boolean}\n */\n kontra.isCanvas = function isCanvas(value) {\n return value && value.nodeName.toLowerCase() === 'canvas';\n };\n\n return kontra;\n})(kontra || {}, document);","var kontra = (function(kontra, window) {\n 'use strict';\n\n /**\n * Get the current time. Uses the User Timing API if it's available or defaults to using\n * Date().getTime()\n * @private\n *\n * @returns {number}\n */\n kontra.timestamp = (function() {\n if (window.performance && window.performance.now) {\n return function timestampPerformance() {\n return window.performance.now();\n };\n }\n else {\n return function timestampDate() {\n return new Date().getTime();\n };\n }\n })();\n\n /**\n * Game loop that updates and renders the game every frame.\n * @memberof kontra\n *\n * @see kontra.gameLoop.prototype.set for list of parameters.\n */\n kontra.gameLoop = function(properties) {\n var gameLoop = Object.create(kontra.gameLoop.prototype);\n gameLoop.set(properties);\n\n return gameLoop;\n };\n\n kontra.gameLoop.prototype = {\n /**\n * Set properties on the game loop.\n * @memberof kontra.gameLoop\n *\n * @param {object} properties - Configure the game loop.\n * @param {number} [properties.fps=60] - Desired frame rate.\n * @param {function} properties.update - Function called to update the game.\n * @param {function} properties.render - Function called to render the game.\n */\n set: function set(properties) {\n properties = properties || {};\n\n // check for required functions\n if (typeof properties.update !== 'function' || typeof properties.render !== 'function') {\n var error = new ReferenceError('Required functions not found');\n kontra.logError(error, 'You must provide update() and render() functions to create a game loop.');\n return;\n }\n\n this.isStopped = false;\n\n // animation variables\n this._accumulator = 0;\n this._delta = 1E3 / (properties.fps || 60);\n\n this.update = properties.update;\n this.render = properties.render;\n },\n\n /**\n * Called every frame of the game loop.\n * @memberof kontra.gameLoop\n */\n frame: function frame() {\n var _this = this;\n\n _this._rAF = requestAnimationFrame(_this.frame.bind(_this));\n\n _this._now = kontra.timestamp();\n _this._dt = _this._now - _this._last;\n _this._last = _this._now;\n\n // prevent updating the game with a very large dt if the game were to lose focus\n // and then regain focus later\n if (_this._dt > 1E3) {\n return;\n }\n\n _this._accumulator += _this._dt;\n\n while (_this._accumulator >= _this._delta) {\n _this.update(_this._delta / 1E3);\n\n _this._accumulator -= _this._delta;\n }\n\n _this.render();\n },\n\n /**\n * Start the game loop.\n * @memberof kontra.gameLoop\n */\n start: function start() {\n this._last = kontra.timestamp();\n this.isStopped = false;\n requestAnimationFrame(this.frame.bind(this));\n },\n\n /**\n * Stop the game loop.\n */\n stop: function stop() {\n this.isStopped = true;\n cancelAnimationFrame(this._rAF);\n }\n };\n\n return kontra;\n})(kontra || {}, window);","/*jshint -W084 */\n\nvar kontra = (function(kontra, window) {\n 'use strict';\n\n var callbacks = {};\n var pressedKeys = {};\n\n var keyMap = {\n // named keys\n 8: 'backspace',\n 9: 'tab',\n 13: 'enter',\n 16: 'shift',\n 17: 'ctrl',\n 18: 'alt',\n 20: 'capslock',\n 27: 'esc',\n 32: 'space',\n 33: 'pageup',\n 34: 'pagedown',\n 35: 'end',\n 36: 'home',\n 37: 'left',\n 38: 'up',\n 39: 'right',\n 40: 'down',\n 45: 'insert',\n 46: 'delete',\n 91: 'leftwindow',\n 92: 'rightwindow',\n 93: 'select',\n 144: 'numlock',\n 145: 'scrolllock',\n\n // special characters\n 106: '*',\n 107: '+',\n 109: '-',\n 110: '.',\n 111: '/',\n 186: ';',\n 187: '=',\n 188: ',',\n 189: '-',\n 190: '.',\n 191: '/',\n 192: '`',\n 219: '[',\n 220: '\\\\',\n 221: ']',\n 222: '\\''\n };\n\n // alpha keys\n for (var i = 0; i < 26; i++) {\n keyMap[65+i] = String.fromCharCode(65+i).toLowerCase();\n }\n // numeric keys\n for (i = 0; i < 10; i++) {\n keyMap[48+i] = ''+i;\n }\n // f keys\n for (i = 1; i < 20; i++) {\n keyMap[111+i] = 'f'+i;\n }\n // keypad\n for (i = 0; i < 10; i++) {\n keyMap[96+i] = 'numpad'+i;\n }\n\n // shift keys mapped to their non-shift equivalent\n var shiftKeys = {\n '~': '`',\n '!': '1',\n '@': '2',\n '#': '3',\n '$': '4',\n '%': '5',\n '^': '6',\n '&': '7',\n '*': '8',\n '(': '9',\n ')': '0',\n '_': '-',\n '+': '=',\n ':': ';',\n '\"': '\\'',\n '<': ',',\n '>': '.',\n '?': '/',\n '|': '\\\\',\n 'plus': '='\n };\n\n // aliases modifier keys to their actual key for keyup event\n var aliases = {\n 'leftwindow': 'meta', // mac\n 'select': 'meta' // mac\n };\n\n // modifier order for combinations\n var modifierOrder = ['meta', 'ctrl', 'alt', 'shift'];\n\n window.addEventListener('keydown', keydownEventHandler);\n window.addEventListener('keyup', keyupEventHandler);\n window.addEventListener('blur', blurEventHandler);\n\n /**\n * Object for using the keyboard.\n */\n kontra.keys = {};\n\n /**\n * Register a function to be called on a keyboard keys.\n * Please note that not all keyboard combinations can be executed due to ghosting.\n * @memberof kontra.keys\n *\n * @param {string|string[]} keys - keys combination string(s).\n *\n * @throws {SyntaxError} If callback is not a function.\n */\n kontra.keys.bind = function bindKey(keys, callback) {\n if (typeof callback !== 'function') {\n var error = new SyntaxError('Invalid function.');\n kontra.logError(error, 'You must provide a function as the second parameter.');\n return;\n }\n\n keys = (kontra.isArray(keys) ? keys : [keys]);\n\n for (var i = 0, key; key = keys[i]; i++) {\n var combination = normalizeKeys(key);\n\n callbacks[combination] = callback;\n }\n };\n\n /**\n * Remove the callback function for a key combination.\n * @memberof kontra.keys\n *\n * @param {string|string[]} keys - keys combination string.\n */\n kontra.keys.unbind = function unbindKey(keys) {\n keys = (kontra.isArray(keys) ? keys : [keys]);\n\n for (var i = 0, key; key = keys[i]; i++) {\n var combination = normalizeKeys(key);\n\n callbacks[combination] = undefined;\n }\n };\n\n /**\n * Returns whether a key is pressed.\n * @memberof kontra.keys\n *\n * @param {string} keys - Keys combination string.\n *\n * @returns {boolean}\n */\n kontra.keys.pressed = function keyPressed(keys) {\n var combination = normalizeKeys(keys);\n var pressed = true;\n\n // loop over each key in the combination and verify that it is pressed\n keys = combination.split('+');\n for (var i = 0, key; key = keys[i]; i++) {\n pressed = pressed && !!pressedKeys[key];\n }\n\n return pressed;\n };\n\n /**\n * Normalize the event keycode\n * @private\n *\n * @param {Event} e\n *\n * @returns {number}\n */\n function normalizeKeyCode(e) {\n return (typeof e.which === 'number' ? e.which : e.keyCode);\n }\n\n /**\n * Normalize keys combination order.\n * @private\n *\n * @param {string} keys - keys combination string.\n *\n * @returns {string} Normalized combination.\n *\n * @example\n * normalizeKeys('c+ctrl'); //=> 'ctrl+c'\n * normalizeKeys('shift+++meta+alt'); //=> 'meta+alt+shift+plus'\n */\n function normalizeKeys(keys) {\n var combination = [];\n\n // handle '++' combinations\n keys = keys.trim().replace('++', '+plus');\n\n // put modifiers in the correct order\n for (var i = 0, modifier; modifier = modifierOrder[i]; i++) {\n\n // check for the modifier\n if (keys.indexOf(modifier) !== -1) {\n combination.push(modifier);\n keys = keys.replace(modifier, '');\n }\n }\n\n // remove all '+'s to leave only the last key\n keys = keys.replace(/\\+/g, '').toLowerCase();\n\n // check for shift key\n if (shiftKeys[keys]) {\n combination.push('shift+'+shiftKeys[keys]);\n }\n else if(keys) {\n combination.push(keys);\n }\n\n return combination.join('+');\n }\n\n /**\n * Get the key combination from an event.\n * @private\n *\n * @param {Event} e\n *\n * @return {string} normalized combination.\n */\n function getKeyCombination(e) {\n var combination = [];\n\n // check for modifiers\n for (var i = 0, modifier; modifier = modifierOrder[i]; i++) {\n if (e[modifier+'Key']) {\n combination.push(modifier);\n }\n }\n\n var key = keyMap[normalizeKeyCode(e)];\n\n // prevent duplicate keys from being added to the combination\n // for example 'ctrl+ctrl' since ctrl is both a modifier and\n // a regular key\n if (combination.indexOf(key) === -1) {\n combination.push(key);\n }\n\n return combination.join('+');\n }\n\n /**\n * Execute a function that corresponds to a keyboard combination.\n * @private\n *\n * @param {Event} e\n */\n function keydownEventHandler(e) {\n var combination = getKeyCombination(e);\n\n // set pressed keys\n for (var i = 0, keys = combination.split('+'), key; key = keys[i]; i++) {\n pressedKeys[key] = true;\n }\n\n if (callbacks[combination]) {\n callbacks[combination](e, combination);\n e.preventDefault();\n }\n }\n\n /**\n * Set the released key to not being pressed.\n * @private\n *\n * @param {Event} e\n */\n function keyupEventHandler(e) {\n var key = keyMap[normalizeKeyCode(e)];\n pressedKeys[key] = false;\n\n if (aliases[key]) {\n pressedKeys[ aliases[key] ] = false;\n }\n }\n\n /**\n * Reset pressed keys.\n * @private\n *\n * @param {Event} e\n */\n function blurEventHandler(e) {\n pressedKeys = {};\n }\n\n return kontra;\n})(kontra || {}, window);","/*jshint -W084 */\n\nvar kontra = (function(kontra) {\n 'use strict';\n\n /**\n * Object pool. The pool will grow in size to accommodate as many objects as are needed.\n * Unused items are at the front of the pool and in use items are at the of the pool.\n * @memberof kontra\n *\n * @see kontra.pool.prototype.set for list of parameters.\n */\n kontra.pool = function(properties) {\n var pool = Object.create(kontra.pool.prototype);\n pool.set(properties);\n\n return pool;\n };\n\n kontra.pool.prototype = {\n /**\n * Set properties on the pool.\n *\n * @param {object} properties - Properties of the pool.\n * @param {object} properties.create - Function that returns the object to use in the pool.\n * @param {object} properties.createProperties - Properties that will be passed to the create function.\n * @param {number} properties.maxSize - The maximum size that the pool will grow to.\n * @param {boolean} properties.fill - Fill the pool to max size instead of slowly growing.\n *\n * Objects inside the pool must implement render(), update(),\n * set(), and isAlive() functions.\n */\n set: function set(properties) {\n properties = properties || {};\n\n var error, obj;\n\n if (typeof properties.create !== 'function') {\n error = new SyntaxError('Required function not found.');\n kontra.logError(error, 'Parameter \\'create\\' must be a function that returns an object.');\n return;\n }\n\n // bind the create function to always use the create properties\n this.create = properties.create.bind(this, properties.createProperties || {});\n\n // ensure objects for the pool have required functions\n obj = this.create();\n\n if (!obj || typeof obj.render !== 'function' || typeof obj.update !== 'function' ||\n typeof obj.set !== 'function' || typeof obj.isAlive !== 'function') {\n error = new ReferenceError('Create object required functions not found.');\n kontra.logError(error, 'Objects to be pooled must implement render(), update(), set() and isAlive() functions.');\n return;\n }\n\n // start the pool with an object\n this.objects = [obj];\n this.size = 1;\n this.maxSize = properties.maxSize || Infinity;\n this.lastIndex = 0;\n this.inUse = 0;\n\n // fill the pool\n if (properties.fill) {\n while (this.objects.length < this.maxSize) {\n this.objects.unshift(this.create());\n }\n }\n },\n\n /**\n * Get an object from the pool.\n * @memberof kontra.pool\n *\n * @param {object} properties - Properties to pass to object.set().\n */\n get: function get(properties) {\n properties = properties || {};\n\n var _this = this;\n\n // the pool is out of objects if the first object is in use and it can't grow\n if (_this.objects[0].isAlive()) {\n if (_this.size === _this.maxSize) {\n return;\n }\n // 'double' the size of the array by filling it with twice as many objects\n else {\n for (var x = 0; x < _this.size && _this.objects.length < _this.maxSize; x++) {\n _this.objects.unshift(_this.create());\n }\n\n _this.size = _this.objects.length;\n _this.lastIndex = _this.size - 1;\n }\n }\n\n // save off first object in pool to reassign to last object after unshift\n var obj = _this.objects[0];\n obj.set(properties);\n\n // unshift the array\n for (var i = 1; i < _this.size; i++) {\n _this.objects[i-1] = _this.objects[i];\n }\n\n _this.objects[_this.lastIndex] = obj;\n _this.inUse++;\n },\n\n /**\n * Return all objects that are alive from the pool.\n * @memberof kontra.pool\n *\n * @returns {object[]}\n */\n getAliveObjects: function getAliveObjects() {\n return this.objects.slice(this.objects.length - this.inUse);\n },\n\n /**\n * Clear the object pool.\n * @memberof kontra.pool\n */\n clear: function clear() {\n this.inUse = 0;\n this.size = 1;\n this.lastIndex = 0;\n this.objects.length = 0;\n this.objects.push(this.create({}));\n },\n\n /**\n * Update all alive pool objects.\n * @memberof kontra.pool\n */\n update: function update() {\n var i = this.lastIndex;\n var obj;\n\n // only iterate over the objects that are alive\n //\n // If the user kills an object outside of the update cycle, the pool won't know of\n // the change until the next update and inUse won't be decremented. If the user then\n // gets an object when inUse is the same size as objects.length, inUse will increment\n // and this statement will evaluate to -1.\n //\n // I don't like having to go through the pool to kill an object as it forces you to know\n // which object came from which pool. Instead, we'll just prevent the index from going below\n // 0 and accept the fact that inUse may be out of sync for a frame.\n var index = Math.max(this.objects.length - this.inUse, 0);\n\n while (i >= index) {\n obj = this.objects[i];\n\n obj.update();\n\n // if the object is dead, move it to the front of the pool\n if (!obj.isAlive()) {\n\n // push an object from the middle of the pool to the front of the pool\n // without returning a new array through Array#splice to avoid garbage\n // collection of the old array\n // @see http://jsperf.com/object-pools-array-vs-loop\n for (var j = i; j > 0; j--) {\n this.objects[j] = this.objects[j-1];\n }\n\n this.objects[0] = obj;\n this.inUse--;\n index++;\n }\n else {\n i--;\n }\n }\n },\n\n /**\n * render all alive pool objects.\n * @memberof kontra.pool\n */\n render: function render() {\n var index = Math.max(this.objects.length - this.inUse, 0);\n\n for (var i = this.lastIndex; i >= index; i--) {\n this.objects[i].render();\n }\n }\n };\n\n return kontra;\n})(kontra || {});","/*jshint -W084 */\n\nvar kontra = (function(kontra, undefined) {\n 'use strict';\n\n /**\n * A quadtree for 2D collision checking. The quadtree acts like an object pool in that it\n * will create subnodes as objects are needed but it won't clean up the subnodes when it\n * collapses to avoid garbage collection.\n * @memberof kontra\n *\n * @see kontra.quadtree.prototype.set for list of parameters.\n *L\n * The quadrant indices are numbered as follows (following a z-order curve):\n * |\n * 0 | 1\n * ----+----\n * 2 | 3\n * |\n */\n kontra.quadtree = function(properties) {\n var quadtree = Object.create(kontra.quadtree.prototype);\n quadtree.set(properties);\n\n return quadtree;\n };\n\n kontra.quadtree.prototype = {\n /**\n * Set properties on the quadtree.\n * @memberof kontra.quadtree\n *\n * @param {number} [depth=0] - Current node depth.\n * @param {number} [maxDepth=3] - Maximum node depths the quadtree can have.\n * @param {number} [maxObjects=25] - Maximum number of objects a node can support before splitting.\n * @param {object} [parentNode] - The node that contains this node.\n * @param {object} [bounds] - The 2D space this node occupies.\n */\n set: function set(properties) {\n properties = properties || {};\n\n this.depth = properties.depth || 0;\n this.maxDepth = properties.maxDepth || 3;\n this.maxObjects = properties.maxObjects || 25;\n\n // since we won't clean up any subnodes, we need to keep track of which nodes are\n // currently the leaf node so we know which nodes to add objects to\n this.isBranchNode = false;\n\n this.parentNode = properties.parentNode;\n\n this.bounds = properties.bounds || {\n x: 0,\n y: 0,\n width: kontra.game.width,\n height: kontra.game.height\n };\n\n this.objects = [];\n this.subnodes = [];\n },\n\n /**\n * Clear the quadtree\n * @memberof kontra.quadtree\n */\n clear: function clear() {\n if (this.isBranchNode) {\n for (var i = 0; i < 4; i++) {\n this.subnodes[i].clear();\n }\n }\n\n this.isBranchNode = false;\n this.objects.length = 0;\n },\n\n /**\n * Find the leaf node the object belongs to and get all objects that are part of\n * that node.\n * @memberof kontra.quadtree\n *\n * @param {object} object - Object to use for finding the leaf node.\n *\n * @returns {object[]} A list of objects in the same leaf node as the object.\n */\n get: function get(object) {\n var node = this;\n var objects = [];\n var indices, index;\n\n // traverse the tree until we get to a leaf node\n while (node.subnodes.length && this.isBranchNode) {\n indices = this._getIndex(object);\n\n for (var i = 0, length = indices.length; i < length; i++) {\n index = indices[i];\n\n objects.push.apply(objects, this.subnodes[index].get(object));\n }\n\n return objects;\n }\n\n return node.objects;\n },\n\n /**\n * Add an object to the quadtree. Once the number of objects in the node exceeds\n * the maximum number of objects allowed, it will split and move all objects to their\n * corresponding subnodes.\n * @memberof kontra.quadtree\n */\n add: function add() {\n var _this = this;\n var i, object, obj, indices, index;\n\n for (var j = 0, length = arguments.length; j < length; j++) {\n object = arguments[j];\n\n // add a group of objects separately\n if (kontra.isArray(object)) {\n _this.add.apply(this, object);\n\n continue;\n }\n\n // current node has subnodes, so we need to add this object into a subnode\n if (_this.subnodes.length && _this.isBranchNode) {\n _this._addToSubnode(object);\n\n continue;\n }\n\n // this node is a leaf node so add the object to it\n _this.objects.push(object);\n\n // split the node if there are too many objects\n if (_this.objects.length > _this.maxObjects && _this.depth < _this.maxDepth) {\n _this._split();\n\n // move all objects to their corresponding subnodes\n for (i = 0; obj = _this.objects[i]; i++) {\n _this._addToSubnode(obj);\n }\n\n _this.objects.length = 0;\n }\n }\n },\n\n /**\n * Add an object to a subnode.\n * @memberof kontra.quadtree\n * @private\n *\n * @param {object} object - Object to add into a subnode\n */\n _addToSubnode: function _addToSubnode(object) {\n var indices = this._getIndex(object);\n\n // add the object to all subnodes it intersects\n for (var i = 0, length = indices.length; i < length; i++) {\n this.subnodes[ indices[i] ].add(object);\n }\n },\n\n /**\n * Determine which subnodes the object intersects with.\n * @memberof kontra.quadtree\n * @private\n *\n * @param {object} object - Object to check.\n *\n * @returns {number[]} List of all subnodes object intersects.\n */\n _getIndex: function getIndex(object) {\n var indices = [];\n\n var verticalMidpoint = this.bounds.x + this.bounds.width / 2;\n var horizontalMidpoint = this.bounds.y + this.bounds.height / 2;\n\n // handle non-kontra.sprite objects as well as kontra.sprite objects\n var x = (object.x !== undefined ? object.x : object.position.x);\n var y = (object.y !== undefined ? object.y : object.position.y);\n\n // save off quadrant checks for reuse\n var intersectsTopQuadrants = y < horizontalMidpoint && y + object.height >= this.bounds.y;\n var intersectsBottomQuadrants = y + object.height >= horizontalMidpoint && y < this.bounds.y + this.bounds.height;\n\n // object intersects with the left quadrants\n if (x < verticalMidpoint && x + object.width >= this.bounds.x) {\n if (intersectsTopQuadrants) { // top left\n indices.push(0);\n }\n\n if (intersectsBottomQuadrants) { // bottom left\n indices.push(2);\n }\n }\n\n // object intersects with the right quadrants\n if (x + object.width >= verticalMidpoint && x < this.bounds.x + this.bounds.width) { // top right\n if (intersectsTopQuadrants) {\n indices.push(1);\n }\n\n if (intersectsBottomQuadrants) { // bottom right\n indices.push(3);\n }\n }\n\n return indices;\n },\n\n /**\n * Split the node into four subnodes.\n * @memberof kontra.quadtree\n * @private\n */\n _split: function split() {\n this.isBranchNode = true;\n\n // only split if we haven't split before\n if (this.subnodes.length) {\n return;\n }\n\n var subWidth = this.bounds.width / 2 | 0;\n var subHeight = this.bounds.height / 2 | 0;\n var x = this.bounds.x;\n var y = this.bounds.y;\n\n for (var i = 0; i < 4; i++) {\n this.subnodes[i] = kontra.quadtree({\n bounds: {\n x: x + (i % 2 === 1 ? subWidth : 0), // nodes 1 and 3\n y: y + (i >= 2 ? subHeight : 0), // nodes 2 and 3\n width: subWidth,\n height: subHeight\n },\n depth: this.depth+1,\n maxDepth: this.maxDepth,\n maxObjects: this.maxObjects,\n parentNode: this\n });\n }\n },\n\n /**\n * Draw the quadtree. Useful for visual debugging.\n * @memberof kontra.quadtree\n */\n render: function() {\n // don't draw empty leaf nodes, always draw branch nodes and the first node\n if (this.objects.length || this.depth === 0 ||\n (this.parentNode && this.parentNode.isBranchNode)) {\n\n kontra.context.strokeStyle = 'red';\n kontra.context.strokeRect(this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height);\n\n if (this.subnodes.length) {\n for (var i = 0; i < 4; i++) {\n this.subnodes[i].render();\n }\n }\n }\n }\n };\n\n return kontra;\n})(kontra || {});","var kontra = (function(kontra, Math, undefined) {\n 'use strict';\n\n /**\n * A vector for 2D space.\n * @memberof kontra\n *\n * @see kontra.vector.prototype.set for list of parameters.\n */\n kontra.vector = function(x, y) {\n var vector = Object.create(kontra.vector.prototype);\n vector.set(x, y);\n\n return vector;\n };\n\n kontra.vector.prototype = {\n /**\n * Set the vector's x and y position.\n * @memberof kontra.vector\n *\n * @param {number} x=0 - Center x coordinate.\n * @param {number} y=0 - Center y coordinate.\n *\n * @returns {vector}\n */\n set: function set(x, y) {\n this.x = x || 0;\n this.y = y || 0;\n\n return this;\n },\n\n /**\n * Add a vector to this vector.\n * @memberof kontra.vector\n *\n * @param {vector} vector - Vector to add.\n * @param {number} dt=1 - Time since last update.\n */\n add: function add(vector, dt) {\n this.x += (vector.x || 0) * (dt || 1);\n this.y += (vector.y || 0) * (dt || 1);\n },\n\n /**\n * Clamp the vector between two points that form a rectangle.\n * Please note that clamping will only work if the add function is called.\n * @memberof kontra.vector\n *\n * @param {number} xMin - Min x value.\n * @param {number} yMin - Min y value.\n * @param {number} xMax - Max x value.\n * @param {number} yMax - Max y value.\n */\n clamp: function clamp(xMin, yMin, xMax, yMax) {\n\n // overwrite add function to clamp the final values.\n this.add = function clampAdd(vector, dt) {\n var x = this.x + (vector.x || 0) * (dt || 1);\n var y = this.y + (vector.y || 0) * (dt || 1);\n\n this.x = Math.min( Math.max(x, xMin), xMax );\n this.y = Math.min( Math.max(y, yMin), yMax );\n };\n }\n };\n\n\n\n\n\n /**\n * A sprite with a position, velocity, and acceleration.\n * @memberof kontra\n * @requires kontra.vector\n *\n * @see kontra.sprite._prot.set for list of parameters.\n */\n kontra.sprite = function(properties) {\n var sprite = Object.create(kontra.sprite.prototype);\n sprite.set(properties);\n\n return sprite;\n };\n\n kontra.sprite.prototype = {\n /**\n * Move the sprite by its velocity.\n * @memberof kontra.sprite\n *\n * @param {number} dt - Time since last update.\n */\n advanceSprite: function advanceSprite(dt) {\n this.velocity.add(this.acceleration, dt);\n this.position.add(this.velocity, dt);\n\n this.timeToLive--;\n },\n\n /**\n * Draw a simple rectangle. Useful for prototyping.\n * @memberof kontra.sprite\n */\n drawRect: function drawRect() {\n this.context.fillStyle = this.color;\n this.context.fillRect(this.position.x, this.position.y, this.width, this.height);\n },\n\n /**\n * Draw the sprite.\n * @memberof kontra.sprite\n */\n drawImage: function drawImage() {\n this.context.drawImage(this.image, this.position.x, this.position.y);\n },\n\n /**\n * Update the currently playing animation. Used when animations are passed to the sprite.\n * @memberof kontra.sprite\n *\n * @param {number} dt - Time since last update.\n */\n advanceAnimation: function advanceAnimation(dt) {\n this.advanceSprite(dt);\n\n this.currentAnimation.update(dt);\n },\n\n /**\n * Draw the currently playing animation. Used when animations are passed to the sprite.\n * @memberof kontra.sprite\n */\n drawAnimation: function drawAnimation() {\n this.currentAnimation.render({\n context: this.context,\n x: this.position.x,\n y: this.position.y\n });\n },\n\n /**\n * Play an animation.\n * @memberof kontra.sprite\n *\n * @param {string} name - Name of the animation to play.\n */\n playAnimation: function playAnimation(name) {\n this.currentAnimation = this.animations[name];\n },\n\n /**\n * Determine if the sprite is alive.\n * @memberof kontra.sprite\n *\n * @returns {boolean}\n */\n isAlive: function isAlive() {\n return this.timeToLive > 0;\n },\n\n /**\n * Set properties on the sprite.\n * @memberof kontra.sprite\n *\n * @param {object} properties - Properties to set on the sprite.\n * @param {number} properties.x - X coordinate of the sprite.\n * @param {number} properties.y - Y coordinate of the sprite.\n * @param {number} [properties.dx] - Change in X position.\n * @param {number} [properties.dy] - Change in Y position.\n * @param {number} [properties.ddx] - Change in X velocity.\n * @param {number} [properties.ddy] - Change in Y velocity.\n *\n * @param {object} [properties.properties] - Additional properties to set on the sprite.\n * @param {number} [properties.timeToLive=0] - How may frames the sprite should be alive.\n * @param {Context} [properties.context=kontra.context] - Provide a context for the sprite to draw on.\n *\n * @param {Image|Canvas} [properties.image] - Image for the sprite.\n *\n * @param {object} [properties.animations] - Animations for the sprite instead of an image.\n *\n * @param {string} [properties.color] - If no image or animation is provided, use color to draw a rectangle for the sprite.\n * @param {number} [properties.width] - Width of the sprite for drawing a rectangle.\n * @param {number} [properties.height] - Height of the sprite for drawing a rectangle.\n *\n * @param {function} [properties.update] - Function to use to update the sprite.\n * @param {function} [properties.render] - Function to use to render the sprite.\n *\n * If you need the sprite to live forever, or just need it to stay on screen until you\n * decide when to kill it, you can set timeToLive to Infinity.\n * Just be sure to set timeToLive to 0 when you want the sprite to die.\n */\n set: function set(properties) {\n properties = properties || {};\n\n var _this = this;\n\n _this.position = (_this.position || kontra.vector()).set(properties.x, properties.y);\n _this.velocity = (_this.velocity || kontra.vector()).set(properties.dx, properties.dy);\n _this.acceleration = (_this.acceleration || kontra.vector()).set(properties.ddx, properties.ddy);\n\n _this.timeToLive = properties.timeToLive || 0;\n _this.context = properties.context || kontra.context;\n\n // image sprite\n if (kontra.isImage(properties.image) || kontra.isCanvas(properties.image)) {\n _this.image = properties.image;\n _this.width = properties.image.width;\n _this.height = properties.image.height;\n\n // change the advance and draw functions to work with images\n _this.advance = _this.advanceSprite;\n _this.draw = _this.drawImage;\n }\n // animation sprite\n else if (properties.animations) {\n _this.animations = properties.animations;\n\n // default the current animation to the first one in the list\n _this.currentAnimation = properties.animations[ Object.keys(properties.animations)[0] ];\n _this.width = _this.currentAnimation.width;\n _this.height = _this.currentAnimation.height;\n\n // change the advance and draw functions to work with animations\n _this.advance = _this.advanceAnimation;\n _this.draw = _this.drawAnimation;\n }\n // rectangle sprite\n else {\n _this.color = properties.color;\n _this.width = properties.width;\n _this.height = properties.height;\n\n // change the advance and draw functions to work with rectangles\n _this.advance = _this.advanceSprite;\n _this.draw = _this.drawRect;\n }\n\n if (properties.update) {\n _this.update = properties.update;\n }\n\n if (properties.render) {\n _this.render = properties.render;\n }\n\n // loop through all additional properties and add them to the sprite\n for (var prop in properties.properties) {\n if (properties.properties.hasOwnProperty(prop)) {\n _this[prop] = properties.properties[prop];\n }\n }\n },\n\n /**\n * Simple bounding box collision test.\n * @memberof kontra.sprite\n *\n * @param {object} object - Object to check collision against.\n *\n * @returns {boolean} True if the objects collide, false otherwise.\n */\n collidesWith: function collidesWith(object) {\n // handle non-kontra.sprite objects as well as kontra.sprite objects\n var x = (object.x !== undefined ? object.x : object.position.x);\n var y = (object.y !== undefined ? object.y : object.position.y);\n\n if (this.position.x < x + object.width &&\n this.position.x + this.width > x &&\n this.position.y < y + object.height &&\n this.position.y + this.height > y) {\n return true;\n }\n\n return false;\n },\n\n /**\n * Update the sprites velocity and position.\n * @memberof kontra.sprite\n * @abstract\n *\n * @param {number} dt - Time since last update.\n *\n * This function can be overridden on a per sprite basis if more functionality\n * is needed in the update step. Just call this.advance() when you need\n * the sprite to update its position.\n *\n * @example\n * sprite = kontra.sprite({\n * update: function update(dt) {\n * // do some logic\n *\n * this.advance(dt);\n * }\n * });\n */\n update: function update(dt) {\n this.advance(dt);\n },\n\n /**\n * Render the sprite.\n * @memberof kontra.sprite.\n * @abstract\n *\n * This function can be overridden on a per sprite basis if more functionality\n * is needed in the render step. Just call this.draw() when you need the\n * sprite to draw its image.\n *\n * @example\n * sprite = kontra.sprite({\n * render: function render() {\n * // do some logic\n *\n * this.draw();\n * }\n * });\n */\n render: function render() {\n this.draw();\n }\n };\n\n return kontra;\n})(kontra || {}, Math);","/*jshint -W084 */\n\nvar kontra = (function(kontra, undefined) {\n 'use strict';\n\n /**\n * Single animation from a sprite sheet.\n * @memberof kontra\n *\n * @see kontra.pool.prototype.set for list of parameters.\n */\n kontra.animation = function(properties) {\n var animation = Object.create(kontra.animation.prototype);\n animation.set(properties);\n\n return animation;\n };\n\n kontra.animation.prototype = {\n /**\n * Set properties on the animation.\n * @memberof kontra.animation\n *\n * @param {object} properties - Properties of the animation.\n * @param {spriteSheet} properties.spriteSheet - Sprite sheet for the animation.\n * @param {number[]} properties.frames - List of frames of the animation.\n * @param {number} properties.frameSpeed - Time to wait before transitioning the animation to the next frame.\n */\n set: function set(properties) {\n properties = properties || {};\n\n this.spriteSheet = properties.spriteSheet;\n this.frames = properties.frames;\n this.frameSpeed = properties.frameSpeed;\n\n this.width = properties.spriteSheet.frame.width;\n this.height = properties.spriteSheet.frame.height;\n\n this.currentFrame = 0;\n this._accumulator = 0;\n this.update = this.advance;\n this.render = this.draw;\n },\n\n /**\n * Update the animation. Used when the animation is not paused or stopped.\n * @memberof kontra.animation\n * @private\n *\n * @param {number} dt=1 - Time since last update.\n */\n advance: function advance(dt) {\n // normalize dt to work with milliseconds as a decimal or an integer\n dt = (dt < 1 ? dt * 1E3 : dt) || 1;\n\n this._accumulator += dt;\n\n // update to the next frame if it's time\n while (this._accumulator >= this.frameSpeed) {\n this.currentFrame = ++this.currentFrame % this.frames.length;\n\n this._accumulator -= this.frameSpeed;\n }\n },\n\n /**\n * Draw the current frame. Used when the animation is not stopped.\n * @memberof kontra.animation\n * @private\n *\n * @param {object} properties - How to draw the animation.\n * @param {integer} properties.x - X position to draw\n * @param {integer} properties.y - Y position to draw\n * @param {Context} [properties.context=kontra.context] - Provide a context for the sprite to draw on.\n */\n draw: function draw(properties) {\n properties = properties || {};\n\n var context = properties.context || kontra.context;\n\n // get the row and col of the frame\n var row = this.frames[this.currentFrame] / this.spriteSheet.framesPerRow | 0;\n var col = this.frames[this.currentFrame] % this.spriteSheet.framesPerRow | 0;\n\n context.drawImage(\n this.spriteSheet.image,\n col * this.spriteSheet.frame.width, row * this.spriteSheet.frame.height,\n this.spriteSheet.frame.width, this.spriteSheet.frame.height,\n properties.x, properties.y,\n this.spriteSheet.frame.width, this.spriteSheet.frame.height\n );\n },\n\n /**\n * Play the animation.\n * @memberof kontra.animation\n */\n play: function play() {\n // restore references to update and render functions only if overridden\n this.update = this.advance;\n this.render = this.draw;\n },\n\n /**\n * Stop the animation and prevent update and render.\n * @memberof kontra.animation\n */\n stop: function stop() {\n\n // instead of putting an if statement in both render/update functions that checks\n // a variable to determine whether to render or update, we can just reassign the\n // functions to noop and save processing time in the game loop.\n // @see http://jsperf.com/boolean-check-vs-noop\n this.update = kontra.noop;\n this.render = kontra.noop;\n },\n\n /**\n * Pause the animation and prevent update.\n * @memberof kontra.animation\n */\n pause: function pause() {\n this.update = kontra.noop;\n }\n };\n\n\n\n\n\n\n /**\n * Create a sprite sheet from an image.\n * @memberof kontra\n *\n * @see kontra.spriteSheet.prototype.set for list of parameters.\n */\n kontra.spriteSheet = function(properties) {\n var spriteSheet = Object.create(kontra.spriteSheet.prototype);\n spriteSheet.set(properties);\n\n return spriteSheet;\n };\n\n kontra.spriteSheet.prototype = {\n /**\n * Set properties on the spriteSheet.\n * @memberof kontra\n * @constructor\n *\n * @param {object} properties - Configure the sprite sheet.\n * @param {Image|Canvas} properties.image - Image for the sprite sheet.\n * @param {number} properties.frameWidth - Width (in px) of each frame.\n * @param {number} properties.frameHeight - Height (in px) of each frame.\n * @param {object} properties.animations - Animations to create from the sprite sheet.\n */\n set: function set(properties) {\n properties = properties || {};\n\n this.animations = {};\n\n if (kontra.isImage(properties.image) || kontra.isCanvas(properties.image)) {\n this.image = properties.image;\n this.frame = {\n width: properties.frameWidth,\n height: properties.frameHeight\n };\n\n this.framesPerRow = properties.image.width / properties.frameWidth | 0;\n }\n else {\n var error = new SyntaxError('Invalid image.');\n kontra.logError(error, 'You must provide an Image for the SpriteSheet.');\n return;\n }\n\n if (properties.animations) {\n this.createAnimations(properties.animations);\n }\n },\n\n /**\n * Create animations from the sprite sheet.\n * @memberof kontra.spriteSheet\n *\n * @param {object} animations - List of named animations to create from the Image.\n * @param {number|string|number[]|string[]} animations.animationName.frames - A single frame or list of frames for this animation.\n * @param {number} animations.animationName.frameSpeed=1 - Number of frames to wait before transitioning the animation to the next frame.\n *\n * @example\n * var sheet = kontra.spriteSheet({image: img, frameWidth: 16, frameHeight: 16});\n * sheet.createAnimations({\n * idle: {\n * frames: 1 // single frame animation\n * },\n * walk: {\n * frames: '2..6', // ascending consecutive frame animation (frames 2-6, inclusive)\n * frameSpeed: 4\n * },\n * moonWalk: {\n * frames: '6..2', // descending consecutive frame animation\n * frameSpeed: 4\n * },\n * jump: {\n * frames: [7, 12, 2], // non-consecutive frame animation\n * frameSpeed: 3\n * },\n * attack: {\n * frames: ['8..10', 13, '10..8'], // you can also mix and match, in this case frames [8,9,10,13,10,9,8]\n * frameSpeed: 2\n * }\n * });\n */\n createAnimations: function createAnimations(animations) {\n var error;\n\n if (!animations || Object.keys(animations).length === 0) {\n error = new ReferenceError('No animations found.');\n kontra.logError(error, 'You must provide at least one named animation to create an Animation.');\n return;\n }\n\n // create each animation by parsing the frames\n var animation, frames, frameSpeed, sequence;\n for (var name in animations) {\n if (!animations.hasOwnProperty(name)) {\n continue;\n }\n\n animation = animations[name];\n frames = animation.frames;\n frameSpeed = animation.frameSpeed;\n\n // array that holds the order of the animation\n sequence = [];\n\n if (frames === undefined) {\n error = new ReferenceError('No animation frames found.');\n kontra.logError(error, 'Animation ' + name + ' must provide a frames property.');\n return;\n }\n\n // single frame\n if (kontra.isNumber(frames)) {\n sequence.push(frames);\n }\n // consecutive frames\n else if (kontra.isString(frames)) {\n sequence = this._parseFrames(frames);\n }\n // non-consecutive frames\n else if (kontra.isArray(frames)) {\n for (var i = 0, frame; frame = frames[i]; i++) {\n\n // consecutive frames\n if (kontra.isString(frame)) {\n\n // add new frames to the end of the array\n sequence.push.apply(sequence, this._parseFrames(frame));\n }\n // single frame\n else {\n sequence.push(frame);\n }\n }\n }\n\n this.animations[name] = kontra.animation({\n spriteSheet: this,\n frames: sequence,\n frameSpeed: frameSpeed\n });\n }\n },\n\n /**\n * Parse a string of consecutive frames.\n * @memberof kontra.spriteSheet\n * @private\n *\n * @param {string} frames - Start and end frame.\n *\n * @returns {number[]} List of frames.\n */\n _parseFrames: function parseFrames(frames) {\n var sequence = [];\n var consecutiveFrames = frames.split('..').map(Number);\n\n // determine which direction to loop\n var direction = (consecutiveFrames[0] < consecutiveFrames[1] ? 1 : -1);\n var i;\n\n // ascending frame order\n if (direction === 1) {\n for (i = consecutiveFrames[0]; i <= consecutiveFrames[1]; i++) {\n sequence.push(i);\n }\n }\n // descending order\n else {\n for (i = consecutiveFrames[0]; i >= consecutiveFrames[1]; i--) {\n sequence.push(i);\n }\n }\n\n return sequence;\n }\n };\n\n return kontra;\n})(kontra || {});","/**\n * localStorage can be a bit of a pain to work with since it stores everything as strings:\n * localStorage.setItem('item', 1); //=> '1'\n * localStorage.setItem('item', false); //=> 'false'\n * localStorage.setItem('item', [1,2,3]); //=> '1,2,3'\n * localStorage.setItem('item', {a:'b'}); //=> '[object Object]'\n * localStorage.setItem('item', undefinedVariable); //=> 'undefined'\n *\n * @fileoverview A simple wrapper for localStorage to make it easier to work with.\n * Based on store.js {@see https://github.com/marcuswestin/store.js}\n */\nvar kontra = (function(kontra, window, localStorage, undefined) {\n 'use strict';\n\n // check if the browser can use localStorage\n kontra.canUse = kontra.canUse || {};\n kontra.canUse.localStorage = 'localStorage' in window && window.localStorage !== null;\n\n if (!kontra.canUse.localStorage) {\n return kontra;\n }\n\n /**\n * Object for using localStorage.\n */\n kontra.store = {};\n\n /**\n * Save an item to localStorage.\n * @memberof kontra.store\n *\n * @param {string} key - Name to store the item as.\n * @param {*} value - Item to store.\n */\n kontra.store.set = function setStoreItem(key, value) {\n if (value === undefined) {\n this.remove(key);\n }\n else {\n localStorage.setItem(key, JSON.stringify(value));\n }\n };\n\n /**\n * Retrieve an item from localStorage and convert it back to it's original type.\n * @memberof kontra.store\n *\n * @param {string} key - Name of the item.\n *\n * @returns {*}\n */\n kontra.store.get = function getStoreItem(key) {\n var value = localStorage.getItem(key);\n\n try {\n value = JSON.parse(value);\n }\n catch(e) {}\n\n return value;\n };\n\n /**\n * Remove an item from localStorage.\n * @memberof kontra.store\n *\n * @param {string} key - Name of the item.\n */\n kontra.store.remove = function removeStoreItem(key) {\n localStorage.removeItem(key);\n };\n\n /**\n * Clear all keys from localStorage.\n * @memberof kontra.store\n */\n kontra.store.clear = function clearStore() {\n localStorage.clear();\n };\n\n return kontra;\n})(kontra || {}, window, window.localStorage);"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/src/gameLoop.js b/src/gameLoop.js index 0043baaf..03a05d05 100644 --- a/src/gameLoop.js +++ b/src/gameLoop.js @@ -25,16 +25,16 @@ var kontra = (function(kontra, window) { * Game loop that updates and renders the game every frame. * @memberof kontra * - * @see kontra.gameLoop._proto.set for list of parameters. + * @see kontra.gameLoop.prototype.set for list of parameters. */ kontra.gameLoop = function(properties) { - var gameLoop = Object.create(kontra.gameLoop._proto); + var gameLoop = Object.create(kontra.gameLoop.prototype); gameLoop.set(properties); return gameLoop; }; - kontra.gameLoop._proto = { + kontra.gameLoop.prototype = { /** * Set properties on the game loop. * @memberof kontra.gameLoop diff --git a/src/pool.js b/src/pool.js index 8248a2f1..756dd374 100644 --- a/src/pool.js +++ b/src/pool.js @@ -8,16 +8,16 @@ var kontra = (function(kontra) { * Unused items are at the front of the pool and in use items are at the of the pool. * @memberof kontra * - * @see kontra.pool._proto.set for list of parameters. + * @see kontra.pool.prototype.set for list of parameters. */ kontra.pool = function(properties) { - var pool = Object.create(kontra.pool._proto); + var pool = Object.create(kontra.pool.prototype); pool.set(properties); return pool; }; - kontra.pool._proto = { + kontra.pool.prototype = { /** * Set properties on the pool. * diff --git a/src/quadtree.js b/src/quadtree.js index 4e96a098..a1941201 100644 --- a/src/quadtree.js +++ b/src/quadtree.js @@ -9,7 +9,7 @@ var kontra = (function(kontra, undefined) { * collapses to avoid garbage collection. * @memberof kontra * - * @see kontra.quadtree._proto.set for list of parameters. + * @see kontra.quadtree.prototype.set for list of parameters. *L * The quadrant indices are numbered as follows (following a z-order curve): * | @@ -19,13 +19,13 @@ var kontra = (function(kontra, undefined) { * | */ kontra.quadtree = function(properties) { - var quadtree = Object.create(kontra.quadtree._proto); + var quadtree = Object.create(kontra.quadtree.prototype); quadtree.set(properties); return quadtree; }; - kontra.quadtree._proto = { + kontra.quadtree.prototype = { /** * Set properties on the quadtree. * @memberof kontra.quadtree diff --git a/src/sprite.js b/src/sprite.js index a6832d26..41ba7b17 100644 --- a/src/sprite.js +++ b/src/sprite.js @@ -5,26 +5,30 @@ var kontra = (function(kontra, Math, undefined) { * A vector for 2D space. * @memberof kontra * - * @see kontra.vector._proto.set for list of parameters. + * @see kontra.vector.prototype.set for list of parameters. */ kontra.vector = function(x, y) { - var vector = Object.create(kontra.vector._proto); + var vector = Object.create(kontra.vector.prototype); vector.set(x, y); return vector; }; - kontra.vector._proto = { + kontra.vector.prototype = { /** * Set the vector's x and y position. * @memberof kontra.vector * * @param {number} x=0 - Center x coordinate. * @param {number} y=0 - Center y coordinate. + * + * @returns {vector} */ set: function set(x, y) { this.x = x || 0; this.y = y || 0; + + return this; }, /** @@ -74,16 +78,13 @@ var kontra = (function(kontra, Math, undefined) { * @see kontra.sprite._prot.set for list of parameters. */ kontra.sprite = function(properties) { - var sprite = Object.create(kontra.sprite._proto); - sprite.position = kontra.vector(); - sprite.velocity = kontra.vector(); - sprite.acceleration = kontra.vector(); + var sprite = Object.create(kontra.sprite.prototype); sprite.set(properties); return sprite; }; - kontra.sprite._proto = { + kontra.sprite.prototype = { /** * Move the sprite by its velocity. * @memberof kontra.sprite @@ -194,11 +195,11 @@ var kontra = (function(kontra, Math, undefined) { var _this = this; - _this.position.set(properties.x, properties.y); - _this.velocity.set(properties.dx, properties.dy); - _this.acceleration.set(properties.ddx, properties.ddy); - _this.timeToLive = properties.timeToLive || 0; + _this.position = (_this.position || kontra.vector()).set(properties.x, properties.y); + _this.velocity = (_this.velocity || kontra.vector()).set(properties.dx, properties.dy); + _this.acceleration = (_this.acceleration || kontra.vector()).set(properties.ddx, properties.ddy); + _this.timeToLive = properties.timeToLive || 0; _this.context = properties.context || kontra.context; // image sprite diff --git a/src/spriteSheet.js b/src/spriteSheet.js index 37de4013..cfd3f72c 100644 --- a/src/spriteSheet.js +++ b/src/spriteSheet.js @@ -7,16 +7,16 @@ var kontra = (function(kontra, undefined) { * Single animation from a sprite sheet. * @memberof kontra * - * @see kontra.pool._proto.set for list of parameters. + * @see kontra.pool.prototype.set for list of parameters. */ kontra.animation = function(properties) { - var animation = Object.create(kontra.animation._proto); + var animation = Object.create(kontra.animation.prototype); animation.set(properties); return animation; }; - kontra.animation._proto = { + kontra.animation.prototype = { /** * Set properties on the animation. * @memberof kontra.animation @@ -133,16 +133,16 @@ var kontra = (function(kontra, undefined) { * Create a sprite sheet from an image. * @memberof kontra * - * @see kontra.spriteSheet._proto.set for list of parameters. + * @see kontra.spriteSheet.prototype.set for list of parameters. */ kontra.spriteSheet = function(properties) { - var spriteSheet = Object.create(kontra.spriteSheet._proto); + var spriteSheet = Object.create(kontra.spriteSheet.prototype); spriteSheet.set(properties); return spriteSheet; }; - kontra.spriteSheet._proto = { + kontra.spriteSheet.prototype = { /** * Set properties on the spriteSheet. * @memberof kontra