diff --git a/src/engine/audio.js b/src/engine/audio.js index 5f3943c7..2a46d38b 100644 --- a/src/engine/audio.js +++ b/src/engine/audio.js @@ -277,6 +277,7 @@ game.createClass('Audio', { request.open('GET', realPath, true); request.responseType = 'arraybuffer'; request.onload = this._decode.bind(this, request, path, callback); + request.onerror = this._error.bind(this, path, callback); request.send(); } }, diff --git a/src/engine/core.js b/src/engine/core.js index d05a6a1f..6c1502a1 100644 --- a/src/engine/core.js +++ b/src/engine/core.js @@ -99,7 +99,7 @@ var game = { Engine version. @property {String} version **/ - version: '2.12.0', + version: '2.13.0', /** @property {Boolean} _booted @private @@ -199,12 +199,14 @@ var game = { @method addAsset @param {String} filename @param {String} [id] + @param {Boolean} [noCache] Force to not load file from cache **/ - addAsset: function(filename, id) { + addAsset: function(filename, id, noCache) { if (!filename) throw 'addAsset: filename undefined'; if (id && this.paths[id]) return; if (this.paths[filename]) return; var realPath = this._getFilePath(filename); + if (id && noCache) realPath += '?' + Date.now(); if (id) this.paths[id] = realPath; this.paths[filename] = realPath; if (this.mediaQueue.indexOf(realPath) === -1) this.mediaQueue.push(realPath); @@ -398,7 +400,7 @@ var game = { var ext = from[key]; if ( typeof ext !== 'object' || - ext instanceof HTMLElement || + (typeof document !== 'undefined' && ext instanceof HTMLElement) || ext instanceof this.Class || ext instanceof this.Container ) { @@ -799,6 +801,9 @@ var game = { this.device.facebook = /FB/i.test(navigator.userAgent); this.device.panda2 = /Panda2/i.test(navigator.userAgent); this.device.electron = (!this.device.panda2 && /Electron/i.test(navigator.userAgent)); + this.device.chrome = /Chrome/i.test(navigator.userAgent); + var chromeVer = navigator.userAgent.match(/Chrome\/([\d.]+)/); + this.device.chromeVer = chromeVer ? parseInt(chromeVer[1]) : 0; this.device.mobile = this.device.iOS || this.device.android || this.device.wp || this.device.wt; if (this.device.androidTV) this.device.mobile = false; @@ -1037,7 +1042,10 @@ var game = { } } - if (typeof document === 'undefined') return; + if (typeof document === 'undefined') { + this.onReady(); + return; + } this._logoSource = document.createElement('img'); this._logoSource.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAA8BAMAAABfg2ObAAAALVBMVEUAAAD4uABHR0f4uABHR0f4uAD4uABHR0dHR0dHR0f4uABHR0f4uABHR0f4uADOcJEWAAAADXRSTlMAqqpV6UQkUMmUdBvjKrIhowAAAH1JREFUSMdjKLmLB7gz4Ae++DRfIaD5Ll4wqnlU8xDQzCqIDKRI05z3DgUsIEmzHapmgVHNo5qpovkGInkS1uykhApmo2cMGTyaFRgIAMZRzaOaRzUPJs2sEM0BZGlmSDYGAjMG0jUjwKjmUc2jmontlE0gUXMJckNgA2l6ASc7KJOPBNRIAAAAAElFTkSuQmCC'; this._logoSource.onload = this._readyLogo.bind(this); diff --git a/src/engine/input.js b/src/engine/input.js index 1c5e17ba..b0208688 100644 --- a/src/engine/input.js +++ b/src/engine/input.js @@ -168,7 +168,7 @@ game.createClass('Input', { window.focus(); game.renderer.canvas.focus(); } - if (!game.scene) return; + if (!game.scene || game.system.paused) return; this._preventDefault(input.event); this._calculateXY(input); @@ -186,7 +186,7 @@ game.createClass('Input', { @private **/ _inputmove: function(input) { - if (!game.scene) return; + if (!game.scene || game.system.paused) return; this._preventDefault(input.event); this._calculateXY(input); @@ -213,7 +213,7 @@ game.createClass('Input', { @private **/ _inputup: function(input) { - if (!game.scene) return; + if (!game.scene || game.system.paused) return; this._preventDefault(input.event); this._calculateXY(input); @@ -267,7 +267,7 @@ game.createClass('Input', { @private **/ _mouseout: function(event) { - if (!game.scene) return; + if (!game.scene || game.system.paused) return; var input = this._mouseInput; input.event = event; diff --git a/src/engine/physics.js b/src/engine/physics.js index ce64e855..4a942bd4 100644 --- a/src/engine/physics.js +++ b/src/engine/physics.js @@ -87,14 +87,18 @@ game.createClass('Body', { @private **/ _collisionGroup: 0, - - init: function(properties) { + + staticInit: function() { this.force = new game.Vector(); this.position = new game.Vector(); this.velocity = new game.Vector(); this.velocityLimit = new game.Vector(980, 980); this.last = new game.Vector(); + }, + + init: function(properties) { game.merge(this, properties); + return true; }, /** @@ -172,21 +176,25 @@ game.createClass('Body', { }, /** - @method _update - @private + Update body position and velocity. + @method update + @param {Number} [delta] **/ - _update: function() { + update: function(delta) { + delta = delta || game.delta; this.last.copy(this.position); if (this.static) return; - - this.velocity.x += this.world.gravity.x * this.mass * game.delta; - this.velocity.y += this.world.gravity.y * this.mass * game.delta; - this.velocity.x += this.force.x * game.delta; - this.velocity.y += this.force.y * game.delta; + + if (this.world) { + this.velocity.x += this.world.gravity.x * this.mass * delta; + this.velocity.y += this.world.gravity.y * this.mass * delta; + } + this.velocity.x += this.force.x * delta; + this.velocity.y += this.force.y * delta; if (this.damping > 0 && this.damping < 1) { - var damping = Math.pow(1 - this.damping, game.delta); + var damping = Math.pow(1 - this.damping, delta); this.velocity.x *= damping; this.velocity.y *= damping; } @@ -200,8 +208,8 @@ game.createClass('Body', { if (this.velocity.y < -this.velocityLimit.y) this.velocity.y = -this.velocityLimit.y; } - this.position.x += this.velocity.x * game.delta; - this.position.y += this.velocity.y * game.delta; + this.position.x += this.velocity.x * delta; + this.position.y += this.velocity.y * delta; } }); @@ -232,6 +240,7 @@ game.defineProperties('Body', { @constructor @param {Number} [x] Gravity x @param {Number} [y] Gravity y + @param {Boolean} [manualUpdate] Don't update physics automatically **/ game.createClass('Physics', { /** @@ -251,11 +260,11 @@ game.createClass('Physics', { **/ _collisionGroups: {}, - staticInit: function(x, y) { + staticInit: function(x, y, manualUpdate) { x = typeof x === 'number' ? x : 0; y = typeof y === 'number' ? y : 980; this.gravity = new game.Vector(x, y); - if (game.scene) game.scene.physics.push(this); + if (game.scene && !manualUpdate) game.scene.physics.push(this); }, /** @@ -270,6 +279,37 @@ game.createClass('Physics', { this._addBodyCollision(body); }, + /** + Perform collision for body. + @method collide + @param {Body} body + **/ + collide: function(body) { + var g, i, b, group; + + for (g = 0; g < body.collideAgainst.length; g++) { + body._collides.length = 0; + group = this._collisionGroups[body.collideAgainst[g]]; + + if (!group) continue; + + for (i = group.length - 1; i >= 0; i--) { + if (!group) break; + b = group[i]; + if (body !== b) { + if (this.hitTest(body, b)) { + body._collides.push(b); + } + } + } + for (i = body._collides.length - 1; i >= 0; i--) { + if (this.hitResponse(body, body._collides[i])) { + body.afterCollide(body._collides[i]); + } + } + } + }, + /** Hit response a versus b. @method hitResponse @@ -379,37 +419,6 @@ game.createClass('Physics', { this._collisionGroups[body.collisionGroup].push(body); }, - /** - @method _collide - @param {Body} body - @private - **/ - _collide: function(body) { - var g, i, b, group; - - for (g = 0; g < body.collideAgainst.length; g++) { - body._collides.length = 0; - group = this._collisionGroups[body.collideAgainst[g]]; - - if (!group) continue; - - for (i = group.length - 1; i >= 0; i--) { - if (!group) break; - b = group[i]; - if (body !== b) { - if (this.hitTest(body, b)) { - body._collides.push(b); - } - } - } - for (i = body._collides.length - 1; i >= 0; i--) { - if (this.hitResponse(body, body._collides[i])) { - body.afterCollide(body._collides[i]); - } - } - } - }, - /** @method _removeBodyCollision @param {Body} body @@ -434,7 +443,7 @@ game.createClass('Physics', { this.bodies.splice(i, 1); } else { - this.bodies[i]._update(); + this.bodies[i].update(); } } }, diff --git a/src/engine/renderer/animation.js b/src/engine/renderer/animation.js index 42189d0f..c045cca4 100644 --- a/src/engine/renderer/animation.js +++ b/src/engine/renderer/animation.js @@ -107,7 +107,7 @@ game.createClass('Animation', 'Sprite', { Add new animation. @method addAnim @param {String} name Name of animation. - @param {Array|Number|String} frames List of invidual frame indexes or start frame index or name that each frame starts with. + @param {Array|Number|String} frames List of invidual frame indexes | List of frame names | Start frame index | Name that each frame starts with. @param {Number|Object} [frameCount] Number of frames or animation properties. @param {Object} [props] Animation properties. @chainable @@ -127,7 +127,11 @@ game.createClass('Animation', 'Sprite', { } else if (frames.length) { for (var i = 0; i < frames.length; i++) { - textures[i] = this.textures[frames[i]]; + if (typeof frames[i] === 'number') textures[i] = this.textures[frames[i]]; + else if (typeof frames[i] === 'string') { + var index = this.textures.indexOf(frames[i]); + if (index !== -1) textures[i] = this.textures[index]; + } } } else if (typeof frames === 'number' && typeof frameCount === 'number') { diff --git a/src/engine/renderer/container.js b/src/engine/renderer/container.js index 58057522..f5bfc74d 100644 --- a/src/engine/renderer/container.js +++ b/src/engine/renderer/container.js @@ -585,6 +585,8 @@ game.createClass('Container', { var context = game.Container._context; var bounds = this._getBounds(); + if (bounds.width === 0 || bounds.height === 0) return; + canvas.width = (bounds.width / this.scale.x) * game.scale; canvas.height = (bounds.height / this.scale.y) * game.scale; @@ -593,8 +595,10 @@ game.createClass('Container', { this._renderCanvas(context); this._renderChildren(context); - - var texture = game.Texture.fromCanvas(canvas); + + var texture = game.Texture.fromImage(canvas.toDataURL()); + texture.width = canvas.width; + texture.height = canvas.height; var sprite = new game.Sprite(texture); sprite._parent = this; @@ -791,8 +795,10 @@ game.addAttributes('Container', { _context: null }); -game.Container._canvas = document.createElement('canvas'); -game.Container._context = game.Container._canvas.getContext('2d'); +if (typeof document !== 'undefined') { + game.Container._canvas = document.createElement('canvas'); + game.Container._context = game.Container._canvas.getContext('2d'); +} game.defineProperties('Container', { /** diff --git a/src/engine/renderer/sprite.js b/src/engine/renderer/sprite.js index aee0905b..994c995a 100644 --- a/src/engine/renderer/sprite.js +++ b/src/engine/renderer/sprite.js @@ -306,7 +306,9 @@ game.addAttributes('Sprite', { } }); -game.Sprite._canvas = document.createElement('canvas'); -game.Sprite._context = game.Sprite._canvas.getContext('2d'); +if (typeof document !== 'undefined') { + game.Sprite._canvas = document.createElement('canvas'); + game.Sprite._context = game.Sprite._canvas.getContext('2d'); +} }); diff --git a/src/engine/renderer/tilingsprite.js b/src/engine/renderer/tilingsprite.js index 5d20086d..14ed3cdf 100644 --- a/src/engine/renderer/tilingsprite.js +++ b/src/engine/renderer/tilingsprite.js @@ -101,7 +101,9 @@ game.createClass('TilingSprite', 'Container', { } } - var texture = game.Texture.fromCanvas(canvas); + var texture = game.Texture.fromImage(canvas.toDataURL()); + texture.width = canvas.width; + texture.height = canvas.height; this.tw = texture.width; this.th = texture.height; game.TilingSprite.cache[this.texture.baseTexture._id] = texture; @@ -175,8 +177,8 @@ game.createClass('TilingSprite', 'Container', { var scaleX = this._worldTransform.a / this._cosCache; var scaleY = this._worldTransform.d / this._cosCache; - var tw = this.tw * game.scale; - var th = this.th * game.scale; + var tw = this.tw; + var th = this.th; var width = this.width / scaleX * game.scale; var height = this.height / scaleY * game.scale; var tileX = this.tilePosition.x * game.scale; @@ -273,8 +275,10 @@ game.addAttributes('TilingSprite', { } }); -game.TilingSprite._canvas = document.createElement('canvas'); -game.TilingSprite._context = game.TilingSprite._canvas.getContext('2d'); +if (typeof document !== 'undefined') { + game.TilingSprite._canvas = document.createElement('canvas'); + game.TilingSprite._context = game.TilingSprite._canvas.getContext('2d'); +} game.defineProperties('TilingSprite', { width: { diff --git a/src/engine/timer.js b/src/engine/timer.js index c1e91d4e..12b2d772 100644 --- a/src/engine/timer.js +++ b/src/engine/timer.js @@ -17,6 +17,11 @@ game.createClass('Timer', { @property {Function} callback **/ callback: null, + /** + Is timer paused. + @property {Boolean} paused + **/ + paused: false, /** Should timer repeat. @property {Boolean} repeat @@ -38,10 +43,10 @@ game.createClass('Timer', { **/ _last: 0, /** - @property {Number} _pause + @property {Number} _pauseTime @private **/ - _pause: 0, + _pauseTime: 0, init: function(time) { this._last = game.Timer.time; @@ -66,7 +71,7 @@ game.createClass('Timer', { delta: function() { var delta = game.Timer.time - this._last; this._last = game.Timer.time; - return this._pause ? 0 : delta; + return this.paused ? 0 : delta; }, /** @@ -74,7 +79,9 @@ game.createClass('Timer', { @method pause **/ pause: function() { - if (!this._pause) this._pause = game.Timer.time; + if (this.paused) return; + this._pauseTime = game.Timer.time; + this.paused = true; }, /** @@ -83,7 +90,8 @@ game.createClass('Timer', { **/ reset: function() { this._base = game.Timer.time; - this._pause = 0; + this._pauseTime = 0; + this.paused = false; }, /** @@ -91,10 +99,10 @@ game.createClass('Timer', { @method resume **/ resume: function() { - if (this._pause) { - this._base += game.Timer.time - this._pause; - this._pause = 0; - } + if (!this.paused) return; + this._base += game.Timer.time - this._pauseTime; + this._pauseTime = 0; + this.paused = false; }, /** @@ -114,7 +122,7 @@ game.createClass('Timer', { @return {Number} time **/ time: function() { - var time = this._base + this.target - (this._pause || game.Timer.time); + var time = this._base + this.target - (this._pauseTime || game.Timer.time); return time < 0 ? 0 : time; } });