From 94add2ea6e7e6fe32c1cd4a16171d684636a1bbb Mon Sep 17 00:00:00 2001 From: Richard Davey Date: Thu, 23 May 2013 15:45:04 +0100 Subject: [PATCH] Updated Loader so it no longer checks if the animation data is valid, passes that control to the AnimationLoader. Also fixed camera bounds check in Sprite. --- Phaser/Loader.ts | 62 ++--- Phaser/gameobjects/Sprite.ts | 36 +-- Phaser/system/animation/AnimationLoader.ts | 12 + README.md | 5 +- Tests/phaser.js | 135 ++++------ Tests/physics/temp2.js | 229 ++++++++++++++-- Tests/physics/temp2.ts | 287 +++++++++++++++++++-- build/phaser.d.ts | 2 +- build/phaser.js | 135 ++++------ 9 files changed, 637 insertions(+), 266 deletions(-) diff --git a/Phaser/Loader.ts b/Phaser/Loader.ts index a698178c..5b58f4bb 100644 --- a/Phaser/Loader.ts +++ b/Phaser/Loader.ts @@ -166,32 +166,23 @@ module Phaser { atlasData = JSON.parse(atlasData); } - // Malformed? - if (atlasData['frames']) - { - this._queueSize++; - this._fileList[key] = { type: 'textureatlas', key: key, url: textureURL, data: null, atlasURL: null, atlasData: atlasData['frames'], format: format, error: false, loaded: false }; - this._keys.push(key); - } - else - { - throw new Error("Phaser.Loader. Invalid Texture Atlas JSON given, missing frames block"); - } + this._queueSize++; + this._fileList[key] = { type: 'textureatlas', key: key, url: textureURL, data: null, atlasURL: null, atlasData: atlasData['frames'], format: format, error: false, loaded: false }; + this._keys.push(key); } else if (format == Loader.TEXTURE_ATLAS_XML_STARLING) { // An xml string or object has been given if (typeof atlasData === 'string') { - var tmp; var xml; try { if (window['DOMParser']) { - tmp = new DOMParser(); - xml = tmp.parseFromString(atlasData, "text/xml"); + var domparser = new DOMParser(); + xml = domparser.parseFromString(atlasData, "text/xml"); } else { @@ -215,17 +206,9 @@ module Phaser { } } - // Malformed? - if (atlasData.getElementsByTagName('TextureAtlas')) - { - this._queueSize++; - this._fileList[key] = { type: 'textureatlas', key: key, url: textureURL, data: null, atlasURL: null, atlasData: atlasData, format: format, error: false, loaded: false }; - this._keys.push(key); - } - else - { - throw new Error("Phaser.Loader. Invalid Texture Atlas XML given, missing tag"); - } + this._queueSize++; + this._fileList[key] = { type: 'textureatlas', key: key, url: textureURL, data: null, atlasURL: null, atlasData: atlasData, format: format, error: false, loaded: false }; + this._keys.push(key); } } @@ -449,13 +432,9 @@ module Phaser { private jsonLoadComplete(key: string) { var data = JSON.parse(this._xhr.response); + var file = this._fileList[key]; - // Malformed? - if (data['frames']) - { - var file = this._fileList[key]; - this._game.cache.addTextureAtlas(file.key, file.url, file.data, data['frames'], file.format); - } + this._game.cache.addTextureAtlas(file.key, file.url, file.data, data['frames'], file.format); this.nextFile(key, true); @@ -468,23 +447,24 @@ module Phaser { private dataLoadError(key: string) { var file = this._fileList[key]; + file.error = true; + this.nextFile(key, true); } private xmlLoadComplete(key: string) { - var atlasData = this._xhr.response; // xml? - var tmp; + var atlasData = this._xhr.response; var xml; try { if (window['DOMParser']) { - tmp = new DOMParser(); - xml = tmp.parseFromString(atlasData, "text/xml"); + var domparser = new DOMParser(); + xml = domparser.parseFromString(atlasData, "text/xml"); } else { @@ -503,16 +483,8 @@ module Phaser { throw new Error("Phaser.Loader. Invalid Texture Atlas XML given"); } - // Malformed? - if (xml.getElementsByTagName('TextureAtlas')) - { - var file = this._fileList[key]; - this._game.cache.addTextureAtlas(file.key, file.url, file.data, xml, file.format); - } - else - { - throw new Error("Phaser.Loader. Invalid Texture Atlas XML given, missing tag"); - } + var file = this._fileList[key]; + this._game.cache.addTextureAtlas(file.key, file.url, file.data, xml, file.format); this.nextFile(key, true); diff --git a/Phaser/gameobjects/Sprite.ts b/Phaser/gameobjects/Sprite.ts index c4a4eff7..e58917cf 100644 --- a/Phaser/gameobjects/Sprite.ts +++ b/Phaser/gameobjects/Sprite.ts @@ -185,7 +185,7 @@ module Phaser { * @param camera {Rectangle} The rectangle you want to check. * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. */ - public inCamera(camera: Rectangle): bool { + public inCamera(camera: Rectangle, cameraOffsetX: number, cameraOffsetY: number): bool { // Object fixed in place regardless of the camera scrolling? Then it's always visible if (this.scrollFactor.x == 0 && this.scrollFactor.y == 0) @@ -193,21 +193,12 @@ module Phaser { return true; } - // Otherwise, if it's scrolling perfectly in sync with the camera (1 to 1) then it's a simple bounds check on world coordinates - if (this.scrollFactor.x == 1 && this.scrollFactor.y == 1) - { - return camera.intersects(this.frameBounds, this.frameBounds.length); - } - else - { - // Else apply the offsets - this._dx = (this.frameBounds.x - camera.x) * this.scrollFactor.x; - this._dy = (this.frameBounds.y - camera.y) * this.scrollFactor.y; - this._dw = this.frameBounds.width * this.scale.x; - this._dh = this.frameBounds.height * this.scale.y; + this._dx = (this.frameBounds.x - camera.x); + this._dy = (this.frameBounds.y - camera.y); + this._dw = this.frameBounds.width * this.scale.x; + this._dh = this.frameBounds.height * this.scale.y; - return (camera.right > this._dx) && (camera.x < this._dx + this._dw) && (camera.bottom > this._dy) && (camera.y < this._dy + this._dh); - } + return (camera.right > this._dx) && (camera.x < this._dx + this._dw) && (camera.bottom > this._dy) && (camera.y < this._dy + this._dh); } @@ -248,7 +239,7 @@ module Phaser { public render(camera: Camera, cameraOffsetX: number, cameraOffsetY: number): bool { // Render checks - if (this.visible == false || this.scale.x == 0 || this.scale.y == 0 || this.alpha < 0.1 || this.cameraBlacklist.indexOf(camera.ID) !== -1 || this.inCamera(camera.worldView) == false) + if (this.visible == false || this.scale.x == 0 || this.scale.y == 0 || this.alpha < 0.1 || this.cameraBlacklist.indexOf(camera.ID) !== -1 || this.inCamera(camera.worldView, cameraOffsetX, cameraOffsetY) == false) { return false; } @@ -400,8 +391,8 @@ module Phaser { if (this.renderDebug) { - //this.renderBounds(camera, cameraOffsetX, cameraOffsetY); - this.collisionMask.render(camera, cameraOffsetX, cameraOffsetY); + this.renderBounds(camera, cameraOffsetX, cameraOffsetY); + //this.collisionMask.render(camera, cameraOffsetX, cameraOffsetY); } if (globalAlpha > -1) @@ -421,14 +412,11 @@ module Phaser { */ private renderBounds(camera:Camera, cameraOffsetX:number, cameraOffsetY:number) { - //this._dx = cameraOffsetX + (this.frameBounds.topLeft.x - camera.worldView.x); - //this._dy = cameraOffsetY + (this.frameBounds.topLeft.y - camera.worldView.y); - - this._dx = cameraOffsetX + (this.collisionMask.x - camera.worldView.x); - this._dy = cameraOffsetY + (this.collisionMask.y - camera.worldView.y); + this._dx = cameraOffsetX + (this.frameBounds.topLeft.x - camera.worldView.x); + this._dy = cameraOffsetY + (this.frameBounds.topLeft.y - camera.worldView.y); this.context.fillStyle = this.renderDebugColor; - this.context.fillRect(this._dx, this._dy, this.collisionMask.width, this.collisionMask.height); + this.context.fillRect(this._dx, this._dy, this.frameBounds.width, this.frameBounds.height); //this.context.fillStyle = this.renderDebugPointColor; diff --git a/Phaser/system/animation/AnimationLoader.ts b/Phaser/system/animation/AnimationLoader.ts index 51bb3c7f..711face3 100644 --- a/Phaser/system/animation/AnimationLoader.ts +++ b/Phaser/system/animation/AnimationLoader.ts @@ -78,6 +78,12 @@ module Phaser { */ public static parseJSONData(game: Game, json): FrameData { + // Malformed? + if (!json['frames']) + { + throw new Error("Phaser.AnimationLoader.parseJSONData: Invalid Texture Atlas JSON given, missing 'frames' array"); + } + // Let's create some frames then var data: FrameData = new FrameData(); @@ -98,6 +104,12 @@ module Phaser { public static parseXMLData(game: Game, xml, format: number): FrameData { + // Malformed? + if (!xml.getElementsByTagName('TextureAtlas')) + { + throw new Error("Phaser.AnimationLoader.parseXMLData: Invalid Texture Atlas XML given, missing tag"); + } + // Let's create some frames then var data: FrameData = new FrameData(); diff --git a/README.md b/README.md index 6bbaa15b..926fa3a1 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ V0.9.6 * Added Loader.crossOrigin property which is applied to loaded Images * Added AnimationManager.destroy() to clear out all local references and objects * Added the clearAnimations parameter to Sprite.loadGraphic(). Allows you to change animation textures but retain the frame data. -* Added the GameObjectFactory to Game. You now make Sprites like this: game.add.sprite(). Much better separation of game object creation methods now. But you'll have to update ALL code, sorry! +* Added the GameObjectFactory to Game. You now make Sprites like this: game.add.sprite(). Much better separation of game object creation methods now. But you'll have to update ALL code, sorry! (blame JesseFreeman for breaking your code and coming up with the idea :) * Added GameObjectFactory methods to add existing objects to the game world, such as existingSprite(), existingTween(), etc. * Added the GameObjectFactory to Phaser.State * Added new format parameter to Loader.addTextureAtlas defining the format. Currently supported: JSON Array and Starling/Sparrow XML. @@ -112,11 +112,10 @@ V0.9.6 * TODO: Game.Time should monitor pause duration * TODO: Investigate bug re: tilemap collision and animation frames * TODO: Update tests that use arrow keys and include touch/mouse support (FlxControlHandler style) -* TODO: GameObject.clipRect +* TODO: GameObject.clipRect - won't work with rotation :( have to use context.clip which is crazy expensive, damnit * TODO: Polygon geom primitive * TODO: Move GameObject transforms to a single matrix * TODO: this.target.view.style.cursor = "pointer"; ("default") -* TODO: Fix bug in scrollFactor inCamera check where the scrollFactor > 0 and < 1 * TODO: If the Camera is larger than the Stage size then the rotation offset isn't correct * TODO: Texture Repeat doesn't scroll, because it's part of the camera not the world, need to think about this more diff --git a/Tests/phaser.js b/Tests/phaser.js index 82bbd8e6..37c35bb8 100644 --- a/Tests/phaser.js +++ b/Tests/phaser.js @@ -1959,22 +1959,16 @@ var Phaser; * @param camera {Rectangle} The rectangle you want to check. * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. */ - function (camera) { + function (camera, cameraOffsetX, cameraOffsetY) { // Object fixed in place regardless of the camera scrolling? Then it's always visible if(this.scrollFactor.x == 0 && this.scrollFactor.y == 0) { return true; } - // Otherwise, if it's scrolling perfectly in sync with the camera (1 to 1) then it's a simple bounds check on world coordinates - if(this.scrollFactor.x == 1 && this.scrollFactor.y == 1) { - return camera.intersects(this.frameBounds, this.frameBounds.length); - } else { - // Else apply the offsets - this._dx = (this.frameBounds.x - camera.x) * this.scrollFactor.x; - this._dy = (this.frameBounds.y - camera.y) * this.scrollFactor.y; - this._dw = this.frameBounds.width * this.scale.x; - this._dh = this.frameBounds.height * this.scale.y; - return (camera.right > this._dx) && (camera.x < this._dx + this._dw) && (camera.bottom > this._dy) && (camera.y < this._dy + this._dh); - } + this._dx = (this.frameBounds.x - camera.x); + this._dy = (this.frameBounds.y - camera.y); + this._dw = this.frameBounds.width * this.scale.x; + this._dh = this.frameBounds.height * this.scale.y; + return (camera.right > this._dx) && (camera.x < this._dx + this._dw) && (camera.bottom > this._dy) && (camera.y < this._dy + this._dh); }; Sprite.prototype.postUpdate = /** * Automatically called after update() by the game loop, this function just updates animations. @@ -2012,7 +2006,7 @@ var Phaser; */ function (camera, cameraOffsetX, cameraOffsetY) { // Render checks - if(this.visible == false || this.scale.x == 0 || this.scale.y == 0 || this.alpha < 0.1 || this.cameraBlacklist.indexOf(camera.ID) !== -1 || this.inCamera(camera.worldView) == false) { + if(this.visible == false || this.scale.x == 0 || this.scale.y == 0 || this.alpha < 0.1 || this.cameraBlacklist.indexOf(camera.ID) !== -1 || this.inCamera(camera.worldView, cameraOffsetX, cameraOffsetY) == false) { return false; } // Alpha @@ -2116,9 +2110,9 @@ var Phaser; this.context.restore(); } if(this.renderDebug) { - //this.renderBounds(camera, cameraOffsetX, cameraOffsetY); - this.collisionMask.render(camera, cameraOffsetX, cameraOffsetY); - } + this.renderBounds(camera, cameraOffsetX, cameraOffsetY); + //this.collisionMask.render(camera, cameraOffsetX, cameraOffsetY); + } if(globalAlpha > -1) { this.context.globalAlpha = globalAlpha; } @@ -2131,12 +2125,10 @@ var Phaser; * @param cameraOffsetY {number} Y offset of bound to the camera. */ function (camera, cameraOffsetX, cameraOffsetY) { - //this._dx = cameraOffsetX + (this.frameBounds.topLeft.x - camera.worldView.x); - //this._dy = cameraOffsetY + (this.frameBounds.topLeft.y - camera.worldView.y); - this._dx = cameraOffsetX + (this.collisionMask.x - camera.worldView.x); - this._dy = cameraOffsetY + (this.collisionMask.y - camera.worldView.y); + this._dx = cameraOffsetX + (this.frameBounds.topLeft.x - camera.worldView.x); + this._dy = cameraOffsetY + (this.frameBounds.topLeft.y - camera.worldView.y); this.context.fillStyle = this.renderDebugColor; - this.context.fillRect(this._dx, this._dy, this.collisionMask.width, this.collisionMask.height); + this.context.fillRect(this._dx, this._dy, this.frameBounds.width, this.frameBounds.height); //this.context.fillStyle = this.renderDebugPointColor; //var hw = this.frameBounds.halfWidth * this.scale.x; //var hh = this.frameBounds.halfHeight * this.scale.y; @@ -2368,6 +2360,10 @@ var Phaser; * @return {FrameData} Generated FrameData object. */ function parseJSONData(game, json) { + // Malformed? + if(!json['frames']) { + throw new Error("Phaser.AnimationLoader.parseJSONData: Invalid Texture Atlas JSON given, missing 'frames' array"); + } // Let's create some frames then var data = new Phaser.FrameData(); // By this stage frames is a fully parsed array @@ -2380,6 +2376,10 @@ var Phaser; return data; }; AnimationLoader.parseXMLData = function parseXMLData(game, xml, format) { + // Malformed? + if(!xml.getElementsByTagName('TextureAtlas')) { + throw new Error("Phaser.AnimationLoader.parseXMLData: Invalid Texture Atlas XML given, missing tag"); + } // Let's create some frames then var data = new Phaser.FrameData(); var frames = xml.getElementsByTagName('SubTexture'); @@ -2455,7 +2455,6 @@ var Phaser; * @param destHeight {number} Destiny draw height. */ function (trimmed, actualWidth, actualHeight, destX, destY, destWidth, destHeight) { - console.log('setTrim', actualWidth, actualHeight, destX, destY, destWidth, destHeight); this.trimmed = trimmed; this.sourceSizeW = actualWidth; this.sourceSizeH = actualHeight; @@ -9132,7 +9131,6 @@ var Phaser; if (typeof atlasURL === "undefined") { atlasURL = null; } if (typeof atlasData === "undefined") { atlasData = null; } if (typeof format === "undefined") { format = Loader.TEXTURE_ATLAS_JSON_ARRAY; } - console.log('addTextureAtlas', key, textureURL, atlasURL, atlasData, format); if(this.checkKeyExists(key) === false) { if(atlasURL !== null) { // A URL to a json/xml file has been given @@ -9154,33 +9152,27 @@ var Phaser; if(typeof atlasData === 'string') { atlasData = JSON.parse(atlasData); } - // Malformed? - if(atlasData['frames']) { - this._queueSize++; - this._fileList[key] = { - type: 'textureatlas', - key: key, - url: textureURL, - data: null, - atlasURL: null, - atlasData: atlasData['frames'], - format: format, - error: false, - loaded: false - }; - this._keys.push(key); - } else { - throw new Error("Phaser.Loader. Invalid Texture Atlas JSON given, missing frames block"); - } + this._queueSize++; + this._fileList[key] = { + type: 'textureatlas', + key: key, + url: textureURL, + data: null, + atlasURL: null, + atlasData: atlasData['frames'], + format: format, + error: false, + loaded: false + }; + this._keys.push(key); } else if(format == Loader.TEXTURE_ATLAS_XML_STARLING) { // An xml string or object has been given if(typeof atlasData === 'string') { - var tmp; var xml; try { if(window['DOMParser']) { - tmp = new DOMParser(); - xml = tmp.parseFromString(atlasData, "text/xml"); + var domparser = new DOMParser(); + xml = domparser.parseFromString(atlasData, "text/xml"); } else { xml = new ActiveXObject("Microsoft.XMLDOM"); xml.async = 'false'; @@ -9195,24 +9187,19 @@ var Phaser; atlasData = xml; } } - // Malformed? - if(atlasData.getElementsByTagName('TextureAtlas')) { - this._queueSize++; - this._fileList[key] = { - type: 'textureatlas', - key: key, - url: textureURL, - data: null, - atlasURL: null, - atlasData: atlasData, - format: format, - error: false, - loaded: false - }; - this._keys.push(key); - } else { - throw new Error("Phaser.Loader. Invalid Texture Atlas XML given, missing tag"); - } + this._queueSize++; + this._fileList[key] = { + type: 'textureatlas', + key: key, + url: textureURL, + data: null, + atlasURL: null, + atlasData: atlasData, + format: format, + error: false, + loaded: false + }; + this._keys.push(key); } } } @@ -9410,11 +9397,8 @@ var Phaser; */ function (key) { var data = JSON.parse(this._xhr.response); - // Malformed? - if(data['frames']) { - var file = this._fileList[key]; - this._game.cache.addTextureAtlas(file.key, file.url, file.data, data['frames'], file.format); - } + var file = this._fileList[key]; + this._game.cache.addTextureAtlas(file.key, file.url, file.data, data['frames'], file.format); this.nextFile(key, true); }; Loader.prototype.dataLoadError = /** @@ -9427,14 +9411,12 @@ var Phaser; this.nextFile(key, true); }; Loader.prototype.xmlLoadComplete = function (key) { - var atlasData = this._xhr.response;// xml? - - var tmp; + var atlasData = this._xhr.response; var xml; try { if(window['DOMParser']) { - tmp = new DOMParser(); - xml = tmp.parseFromString(atlasData, "text/xml"); + var domparser = new DOMParser(); + xml = domparser.parseFromString(atlasData, "text/xml"); } else { xml = new ActiveXObject("Microsoft.XMLDOM"); xml.async = 'false'; @@ -9446,13 +9428,8 @@ var Phaser; if(!xml || !xml.documentElement || xml.getElementsByTagName("parsererror").length) { throw new Error("Phaser.Loader. Invalid Texture Atlas XML given"); } - // Malformed? - if(xml.getElementsByTagName('TextureAtlas')) { - var file = this._fileList[key]; - this._game.cache.addTextureAtlas(file.key, file.url, file.data, xml, file.format); - } else { - throw new Error("Phaser.Loader. Invalid Texture Atlas XML given, missing tag"); - } + var file = this._fileList[key]; + this._game.cache.addTextureAtlas(file.key, file.url, file.data, xml, file.format); this.nextFile(key, true); }; Loader.prototype.nextFile = /** diff --git a/Tests/physics/temp2.js b/Tests/physics/temp2.js index 6eaf2b5e..ca7d6f1a 100644 --- a/Tests/physics/temp2.js +++ b/Tests/physics/temp2.js @@ -27,13 +27,176 @@ var NPhysics = (function () { return NPhysics; })(); var AABB = (function () { - function AABB(pos, xw, yw) { + function AABB(x, y, xw, yw) { this.type = 0; - this.pos = pos.clone(); - this.oldpos = pos.clone(); + this.pos = new Phaser.Vector2(x, y); + this.oldpos = this.pos.clone(); this.xw = Math.abs(xw); this.yw = Math.abs(yw); + this.aabbTileProjections = { + }//hash object to hold tile-specific collision functions + ; + this.aabbTileProjections[TileMapCell.CTYPE_FULL] = this.ProjAABB_Full; } + AABB.COL_NONE = 0; + AABB.COL_AXIS = 1; + AABB.COL_OTHER = 2; + AABB.prototype.IntegrateVerlet = function () { + //var d = DRAG; + //var g = GRAV; + var d = 1; + var g = 0.2; + var p = this.pos; + var o = this.oldpos; + var px, py; + var ox = o.x;//we can't swap buffers since mcs/sticks point directly to vector2s.. + + var oy = o.y; + o.x = px = p.x//get vector values + ; + o.y = py = p.y//p = position + ; + //o = oldposition + //integrate + p.x += (d * px) - (d * ox); + p.y += (d * py) - (d * oy) + g; + }; + AABB.prototype.ReportCollisionVsWorld = function (px, py, dx, dy, obj) { + var p = this.pos; + var o = this.oldpos; + //calc velocity + var vx = p.x - o.x; + var vy = p.y - o.y; + //find component of velocity parallel to collision normal + var dp = (vx * dx + vy * dy); + var nx = dp * dx;//project velocity onto collision normal + + var ny = dp * dy;//nx,ny is normal velocity + + var tx = vx - nx;//px,py is tangent velocity + + var ty = vy - ny; + //we only want to apply collision response forces if the object is travelling into, and not out of, the collision + var b, bx, by, f, fx, fy; + if(dp < 0) { + //f = FRICTION; + f = 0.05; + fx = tx * f; + fy = ty * f; + //b = 1 + BOUNCE;//this bounce constant should be elsewhere, i.e inside the object/tile/etc.. + b = 1 + 0.3//this bounce constant should be elsewhere, i.e inside the object/tile/etc.. + ; + bx = (nx * b); + by = (ny * b); + } else { + //moving out of collision, do not apply forces + bx = by = fx = fy = 0; + } + p.x += px//project object out of collision + ; + p.y += py; + o.x += px + bx + fx//apply bounce+friction impulses which alter velocity + ; + o.y += py + by + fy; + }; + AABB.prototype.CollideAABBVsWorldBounds = function () { + var p = this.pos; + var xw = this.xw; + var yw = this.yw; + var XMIN = 0; + var XMAX = 800; + var YMIN = 0; + var YMAX = 600; + //collide vs. x-bounds + //test XMIN + var dx = XMIN - (p.x - xw); + if(0 < dx) { + //object is colliding with XMIN + this.ReportCollisionVsWorld(dx, 0, 1, 0, null); + } else { + //test XMAX + dx = (p.x + xw) - XMAX; + if(0 < dx) { + //object is colliding with XMAX + this.ReportCollisionVsWorld(-dx, 0, -1, 0, null); + } + } + //collide vs. y-bounds + //test YMIN + var dy = YMIN - (p.y - yw); + if(0 < dy) { + //object is colliding with YMIN + this.ReportCollisionVsWorld(0, dy, 0, 1, null); + } else { + //test YMAX + dy = (p.y + yw) - YMAX; + if(0 < dy) { + //object is colliding with YMAX + this.ReportCollisionVsWorld(0, -dy, 0, -1, null); + } + } + }; + AABB.prototype.render = function (context) { + context.beginPath(); + context.strokeStyle = 'rgb(0,255,0)'; + context.strokeRect(this.pos.x - this.xw, this.pos.y - this.yw, this.xw * 2, this.yw * 2); + context.stroke(); + context.closePath(); + context.fillStyle = 'rgb(0,255,0)'; + context.fillRect(this.pos.x, this.pos.y, 2, 2); + /* + if (this.oH == 1) + { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius); + context.lineTo(this.pos.x - this.radius, this.pos.y + this.radius); + context.stroke(); + context.closePath(); + } + else if (this.oH == -1) + { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.pos.x + this.radius, this.pos.y - this.radius); + context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius); + context.stroke(); + context.closePath(); + } + + if (this.oV == 1) + { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius); + context.lineTo(this.pos.x + this.radius, this.pos.y - this.radius); + context.stroke(); + context.closePath(); + } + else if (this.oV == -1) + { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.pos.x - this.radius, this.pos.y + this.radius); + context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius); + context.stroke(); + context.closePath(); + } + */ + }; + AABB.prototype.ResolveBoxTile = function (x, y, box, t) { + if(0 < t.ID) { + return this.aabbTileProjections[t.CTYPE](x, y, box, t); + } else { + //trace("ResolveBoxTile() was called with an empty (or unknown) tile!: ID=" + t.ID + " ("+ t.i + "," + t.j + ")"); + return false; + } + }; + AABB.prototype.ProjAABB_Full = function (x, y, obj, t) { + var l = Math.sqrt(x * x + y * y); + obj.ReportCollisionVsWorld(x, y, x / l, y / l, t); + return AABB.COL_AXIS; + }; return AABB; })(); var TileMapCell = (function () { @@ -111,6 +274,7 @@ var TileMapCell = (function () { this.UpdateType(); //this.Draw(); } + return this; }; TileMapCell.prototype.Clear = function () { //tile was on, turn it off @@ -408,6 +572,9 @@ var Circle = (function () { //Proj_CircleTile[CTYPE_67DEGb] = ProjCircle_67DegB; //Proj_CircleTile[CTYPE_HALF] = ProjCircle_Half; } + Circle.COL_NONE = 0; + Circle.COL_AXIS = 1; + Circle.COL_OTHER = 2; Circle.prototype.IntegrateVerlet = function () { //var d = DRAG; //var g = GRAV; @@ -587,9 +754,6 @@ var Circle = (function () { return false; } }; - Circle.COL_NONE = 0; - Circle.COL_AXIS = 1; - Circle.COL_OTHER = 2; Circle.prototype.ProjCircle_Full = function (x, y, oH, oV, obj, t) { //if we're colliding vs. the current cell, we need to project along the //smallest penetration vector. @@ -1170,22 +1334,35 @@ var Circle = (function () { myGame.loader.addImageFile('atari1', 'assets/sprites/atari130xe.png'); myGame.loader.load(); } - physics: -NPhysics - c: -Circle - t: -TileMapCell + var cells; + var physics; + var b; + var c; + var t; function create() { this.physics = new NPhysics(); this.c = new Circle(200, 100, 25); + this.b = new AABB(200, 200, 50, 50); // pos is center, not upper-left - this.t = new TileMapCell(200, 500, 100, 100); + this.cells = []; + var tid; + for(var i = 0; i < 10; i++) { + if(i % 2 == 0) { + console.log('pn'); + tid = TileMapCell.TID_CONCAVEpn; + } else { + console.log('nn'); + tid = TileMapCell.TID_CONCAVEnn; + } + //this.cells.push(new TileMapCell(100 + (i * 100), 500, 50, 50).SetState(tid)); + this.cells.push(new TileMapCell(100 + (i * 100), 500, 50, 50).SetState(TileMapCell.TID_FULL)); + } + //this.t = new TileMapCell(200, 500, 100, 100); //this.t.SetState(TileMapCell.TID_FULL); //this.t.SetState(TileMapCell.TID_45DEGpn); //this.t.SetState(TileMapCell.TID_CONCAVEpn); - this.t.SetState(TileMapCell.TID_CONVEXpn); - } + //this.t.SetState(TileMapCell.TID_CONVEXpn); + } function update() { var fx = 0; var fy = 0; @@ -1199,6 +1376,7 @@ TileMapCell } else if(myGame.input.keyboard.isDown(Phaser.Keyboard.DOWN)) { fy += 0.2; } + // update circle var p = this.c.pos; var o = this.c.oldpos; var vx = p.x - o.x; @@ -1208,11 +1386,28 @@ TileMapCell p.x = o.x + newx; p.y = o.y + newy; this.c.IntegrateVerlet(); - this.c.CollideCircleVsTile(this.t); + // update box + var p = this.b.pos; + var o = this.b.oldpos; + var vx = p.x - o.x; + var vy = p.y - o.y; + var newx = Math.min(20, Math.max(-20, vx + fx)); + var newy = Math.min(20, Math.max(-20, vy + fy)); + p.x = o.x + newx; + p.y = o.y + newy; + this.b.IntegrateVerlet(); + for(var i = 0; i < this.cells.length; i++) { + this.c.CollideCircleVsTile(this.cells[i]); + //this.cells[i].render(myGame.stage.context); + } this.c.CollideCircleVsWorldBounds(); + this.b.CollideAABBVsWorldBounds(); } function render() { this.c.render(myGame.stage.context); - this.t.render(myGame.stage.context); + this.b.render(myGame.stage.context); + for(var i = 0; i < this.cells.length; i++) { + this.cells[i].render(myGame.stage.context); + } } })(); diff --git a/Tests/physics/temp2.ts b/Tests/physics/temp2.ts index 459680c5..8fdc1da2 100644 --- a/Tests/physics/temp2.ts +++ b/Tests/physics/temp2.ts @@ -35,11 +35,14 @@ class NPhysics { class AABB { - constructor(pos: Phaser.Vector2, xw, yw) { - this.pos = pos.clone(); - this.oldpos = pos.clone(); + constructor(x: number, y: number, xw, yw) { + + this.pos = new Phaser.Vector2(x, y); + this.oldpos = this.pos.clone(); this.xw = Math.abs(xw); this.yw = Math.abs(yw); + this.aabbTileProjections = {};//hash object to hold tile-specific collision functions + this.aabbTileProjections[TileMapCell.CTYPE_FULL] = this.ProjAABB_Full; } type:number = 0; @@ -47,6 +50,206 @@ class AABB { oldpos: Phaser.Vector2; xw: number; yw: number; + aabbTileProjections; + public oH: number; + public oV: number; + static COL_NONE = 0; + static COL_AXIS = 1; + static COL_OTHER = 2; + + public IntegrateVerlet() { + + //var d = DRAG; + //var g = GRAV; + var d = 1; + var g = 0.2; + + var p = this.pos; + var o = this.oldpos; + var px, py; + + var ox = o.x; //we can't swap buffers since mcs/sticks point directly to vector2s.. + var oy = o.y; + o.x = px = p.x; //get vector values + o.y = py = p.y; //p = position + //o = oldposition + + //integrate + p.x += (d * px) - (d * ox); + p.y += (d * py) - (d * oy) + g; + + } + + public ReportCollisionVsWorld(px, py, dx, dy, obj: TileMapCell) { + + var p = this.pos; + var o = this.oldpos; + + //calc velocity + var vx = p.x - o.x; + var vy = p.y - o.y; + + //find component of velocity parallel to collision normal + var dp = (vx * dx + vy * dy); + var nx = dp * dx;//project velocity onto collision normal + + var ny = dp * dy;//nx,ny is normal velocity + + var tx = vx - nx;//px,py is tangent velocity + var ty = vy - ny; + + //we only want to apply collision response forces if the object is travelling into, and not out of, the collision + var b, bx, by, f, fx, fy; + + if (dp < 0) + { + //f = FRICTION; + f = 0.05; + fx = tx * f; + fy = ty * f; + + //b = 1 + BOUNCE;//this bounce constant should be elsewhere, i.e inside the object/tile/etc.. + b = 1 + 0.3;//this bounce constant should be elsewhere, i.e inside the object/tile/etc.. + + bx = (nx * b); + by = (ny * b); + + } + else + { + //moving out of collision, do not apply forces + bx = by = fx = fy = 0; + } + + p.x += px;//project object out of collision + p.y += py; + + o.x += px + bx + fx;//apply bounce+friction impulses which alter velocity + o.y += py + by + fy; + + } + + public CollideAABBVsWorldBounds() { + var p = this.pos; + var xw = this.xw; + var yw = this.yw; + var XMIN = 0; + var XMAX = 800; + var YMIN = 0; + var YMAX = 600; + + //collide vs. x-bounds + //test XMIN + var dx = XMIN - (p.x - xw); + if (0 < dx) + { + //object is colliding with XMIN + this.ReportCollisionVsWorld(dx, 0, 1, 0, null); + } + else + { + //test XMAX + dx = (p.x + xw) - XMAX; + if (0 < dx) + { + //object is colliding with XMAX + this.ReportCollisionVsWorld(-dx, 0, -1, 0, null); + } + } + + //collide vs. y-bounds + //test YMIN + var dy = YMIN - (p.y - yw); + if (0 < dy) + { + //object is colliding with YMIN + this.ReportCollisionVsWorld(0, dy, 0, 1, null); + } + else + { + //test YMAX + dy = (p.y + yw) - YMAX; + if (0 < dy) + { + //object is colliding with YMAX + this.ReportCollisionVsWorld(0, -dy, 0, -1, null); + } + } + } + + public render(context:CanvasRenderingContext2D) { + + context.beginPath(); + context.strokeStyle = 'rgb(0,255,0)'; + context.strokeRect(this.pos.x - this.xw, this.pos.y - this.yw, this.xw * 2, this.yw * 2); + context.stroke(); + context.closePath(); + + context.fillStyle = 'rgb(0,255,0)'; + context.fillRect(this.pos.x, this.pos.y, 2, 2); + + /* + if (this.oH == 1) + { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius); + context.lineTo(this.pos.x - this.radius, this.pos.y + this.radius); + context.stroke(); + context.closePath(); + } + else if (this.oH == -1) + { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.pos.x + this.radius, this.pos.y - this.radius); + context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius); + context.stroke(); + context.closePath(); + } + + if (this.oV == 1) + { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.pos.x - this.radius, this.pos.y - this.radius); + context.lineTo(this.pos.x + this.radius, this.pos.y - this.radius); + context.stroke(); + context.closePath(); + } + else if (this.oV == -1) + { + context.beginPath(); + context.strokeStyle = 'rgb(255,0,0)'; + context.moveTo(this.pos.x - this.radius, this.pos.y + this.radius); + context.lineTo(this.pos.x + this.radius, this.pos.y + this.radius); + context.stroke(); + context.closePath(); + } + */ + + } + + public ResolveBoxTile(x, y, box, t) { + if (0 < t.ID) + { + return this.aabbTileProjections[t.CTYPE](x, y, box, t); + } + else + { + //trace("ResolveBoxTile() was called with an empty (or unknown) tile!: ID=" + t.ID + " ("+ t.i + "," + t.j + ")"); + return false; + } + } + + public ProjAABB_Full(x, y, obj, t) { + var l = Math.sqrt(x * x + y * y); + obj.ReportCollisionVsWorld(x, y, x / l, y / l, t); + + return AABB.COL_AXIS; + } + + } @@ -149,6 +352,7 @@ class TileMapCell { this.UpdateType(); //this.Draw(); } + return this; } Clear() { @@ -555,6 +759,11 @@ class Circle { oldpos: Phaser.Vector2; radius: number; circleTileProjections; + public oH: number; + public oV: number; + static COL_NONE = 0; + static COL_AXIS = 1; + static COL_OTHER = 2; public IntegrateVerlet() { @@ -723,9 +932,6 @@ class Circle { } - public oH: number; - public oV: number; - public CollideCircleVsTile(tile) { var pos = this.pos; var r = this.radius; @@ -792,10 +998,6 @@ class Circle { } } - static COL_NONE = 0; - static COL_AXIS = 1; - static COL_OTHER = 2; - public ProjCircle_Full(x, y, oH, oV, obj:Circle, t:TileMapCell) { //if we're colliding vs. the current cell, we need to project along the @@ -1618,20 +1820,45 @@ class Circle { } - physics: NPhysics; - c: Circle; - t: TileMapCell; + var cells; + var physics: NPhysics; + var b: Circle; + var c: Circle; + var t: TileMapCell; function create() { this.physics = new NPhysics(); this.c = new Circle(200, 100, 25); + this.b = new AABB(200, 200, 50, 50); + // pos is center, not upper-left - this.t = new TileMapCell(200, 500, 100, 100); + this.cells = []; + + var tid; + + for (var i = 0; i < 10; i++) + { + if (i % 2 == 0) + { + console.log('pn'); + tid = TileMapCell.TID_CONCAVEpn; + } + else + { + console.log('nn'); + tid = TileMapCell.TID_CONCAVEnn; + } + + //this.cells.push(new TileMapCell(100 + (i * 100), 500, 50, 50).SetState(tid)); + this.cells.push(new TileMapCell(100 + (i * 100), 500, 50, 50).SetState(TileMapCell.TID_FULL)); + } + + //this.t = new TileMapCell(200, 500, 100, 100); //this.t.SetState(TileMapCell.TID_FULL); //this.t.SetState(TileMapCell.TID_45DEGpn); //this.t.SetState(TileMapCell.TID_CONCAVEpn); - this.t.SetState(TileMapCell.TID_CONVEXpn); + //this.t.SetState(TileMapCell.TID_CONVEXpn); } @@ -1658,6 +1885,7 @@ class Circle { fy += 0.2; } + // update circle var p = this.c.pos; var o = this.c.oldpos; var vx = p.x - o.x; @@ -1666,17 +1894,40 @@ class Circle { var newy = Math.min(20, Math.max(-20, vy+fy)); p.x = o.x + newx; p.y = o.y + newy; - this.c.IntegrateVerlet(); - this.c.CollideCircleVsTile(this.t); + + // update box + var p = this.b.pos; + var o = this.b.oldpos; + var vx = p.x - o.x; + var vy = p.y - o.y; + var newx = Math.min(20, Math.max(-20, vx+fx)); + var newy = Math.min(20, Math.max(-20, vy+fy)); + p.x = o.x + newx; + p.y = o.y + newy; + this.b.IntegrateVerlet(); + + + for (var i = 0; i < this.cells.length; i++) + { + this.c.CollideCircleVsTile(this.cells[i]); + //this.cells[i].render(myGame.stage.context); + } + this.c.CollideCircleVsWorldBounds(); + this.b.CollideAABBVsWorldBounds(); } function render() { this.c.render(myGame.stage.context); - this.t.render(myGame.stage.context); + this.b.render(myGame.stage.context); + + for (var i = 0; i < this.cells.length; i++) + { + this.cells[i].render(myGame.stage.context); + } } diff --git a/build/phaser.d.ts b/build/phaser.d.ts index 97e04558..189b88b0 100644 --- a/build/phaser.d.ts +++ b/build/phaser.d.ts @@ -1261,7 +1261,7 @@ module Phaser { * @param camera {Rectangle} The rectangle you want to check. * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. */ - public inCamera(camera: Rectangle): bool; + public inCamera(camera: Rectangle, cameraOffsetX: number, cameraOffsetY: number): bool; /** * Automatically called after update() by the game loop, this function just updates animations. */ diff --git a/build/phaser.js b/build/phaser.js index 82bbd8e6..37c35bb8 100644 --- a/build/phaser.js +++ b/build/phaser.js @@ -1959,22 +1959,16 @@ var Phaser; * @param camera {Rectangle} The rectangle you want to check. * @return {boolean} Return true if bounds of this sprite intersects the given rectangle, otherwise return false. */ - function (camera) { + function (camera, cameraOffsetX, cameraOffsetY) { // Object fixed in place regardless of the camera scrolling? Then it's always visible if(this.scrollFactor.x == 0 && this.scrollFactor.y == 0) { return true; } - // Otherwise, if it's scrolling perfectly in sync with the camera (1 to 1) then it's a simple bounds check on world coordinates - if(this.scrollFactor.x == 1 && this.scrollFactor.y == 1) { - return camera.intersects(this.frameBounds, this.frameBounds.length); - } else { - // Else apply the offsets - this._dx = (this.frameBounds.x - camera.x) * this.scrollFactor.x; - this._dy = (this.frameBounds.y - camera.y) * this.scrollFactor.y; - this._dw = this.frameBounds.width * this.scale.x; - this._dh = this.frameBounds.height * this.scale.y; - return (camera.right > this._dx) && (camera.x < this._dx + this._dw) && (camera.bottom > this._dy) && (camera.y < this._dy + this._dh); - } + this._dx = (this.frameBounds.x - camera.x); + this._dy = (this.frameBounds.y - camera.y); + this._dw = this.frameBounds.width * this.scale.x; + this._dh = this.frameBounds.height * this.scale.y; + return (camera.right > this._dx) && (camera.x < this._dx + this._dw) && (camera.bottom > this._dy) && (camera.y < this._dy + this._dh); }; Sprite.prototype.postUpdate = /** * Automatically called after update() by the game loop, this function just updates animations. @@ -2012,7 +2006,7 @@ var Phaser; */ function (camera, cameraOffsetX, cameraOffsetY) { // Render checks - if(this.visible == false || this.scale.x == 0 || this.scale.y == 0 || this.alpha < 0.1 || this.cameraBlacklist.indexOf(camera.ID) !== -1 || this.inCamera(camera.worldView) == false) { + if(this.visible == false || this.scale.x == 0 || this.scale.y == 0 || this.alpha < 0.1 || this.cameraBlacklist.indexOf(camera.ID) !== -1 || this.inCamera(camera.worldView, cameraOffsetX, cameraOffsetY) == false) { return false; } // Alpha @@ -2116,9 +2110,9 @@ var Phaser; this.context.restore(); } if(this.renderDebug) { - //this.renderBounds(camera, cameraOffsetX, cameraOffsetY); - this.collisionMask.render(camera, cameraOffsetX, cameraOffsetY); - } + this.renderBounds(camera, cameraOffsetX, cameraOffsetY); + //this.collisionMask.render(camera, cameraOffsetX, cameraOffsetY); + } if(globalAlpha > -1) { this.context.globalAlpha = globalAlpha; } @@ -2131,12 +2125,10 @@ var Phaser; * @param cameraOffsetY {number} Y offset of bound to the camera. */ function (camera, cameraOffsetX, cameraOffsetY) { - //this._dx = cameraOffsetX + (this.frameBounds.topLeft.x - camera.worldView.x); - //this._dy = cameraOffsetY + (this.frameBounds.topLeft.y - camera.worldView.y); - this._dx = cameraOffsetX + (this.collisionMask.x - camera.worldView.x); - this._dy = cameraOffsetY + (this.collisionMask.y - camera.worldView.y); + this._dx = cameraOffsetX + (this.frameBounds.topLeft.x - camera.worldView.x); + this._dy = cameraOffsetY + (this.frameBounds.topLeft.y - camera.worldView.y); this.context.fillStyle = this.renderDebugColor; - this.context.fillRect(this._dx, this._dy, this.collisionMask.width, this.collisionMask.height); + this.context.fillRect(this._dx, this._dy, this.frameBounds.width, this.frameBounds.height); //this.context.fillStyle = this.renderDebugPointColor; //var hw = this.frameBounds.halfWidth * this.scale.x; //var hh = this.frameBounds.halfHeight * this.scale.y; @@ -2368,6 +2360,10 @@ var Phaser; * @return {FrameData} Generated FrameData object. */ function parseJSONData(game, json) { + // Malformed? + if(!json['frames']) { + throw new Error("Phaser.AnimationLoader.parseJSONData: Invalid Texture Atlas JSON given, missing 'frames' array"); + } // Let's create some frames then var data = new Phaser.FrameData(); // By this stage frames is a fully parsed array @@ -2380,6 +2376,10 @@ var Phaser; return data; }; AnimationLoader.parseXMLData = function parseXMLData(game, xml, format) { + // Malformed? + if(!xml.getElementsByTagName('TextureAtlas')) { + throw new Error("Phaser.AnimationLoader.parseXMLData: Invalid Texture Atlas XML given, missing tag"); + } // Let's create some frames then var data = new Phaser.FrameData(); var frames = xml.getElementsByTagName('SubTexture'); @@ -2455,7 +2455,6 @@ var Phaser; * @param destHeight {number} Destiny draw height. */ function (trimmed, actualWidth, actualHeight, destX, destY, destWidth, destHeight) { - console.log('setTrim', actualWidth, actualHeight, destX, destY, destWidth, destHeight); this.trimmed = trimmed; this.sourceSizeW = actualWidth; this.sourceSizeH = actualHeight; @@ -9132,7 +9131,6 @@ var Phaser; if (typeof atlasURL === "undefined") { atlasURL = null; } if (typeof atlasData === "undefined") { atlasData = null; } if (typeof format === "undefined") { format = Loader.TEXTURE_ATLAS_JSON_ARRAY; } - console.log('addTextureAtlas', key, textureURL, atlasURL, atlasData, format); if(this.checkKeyExists(key) === false) { if(atlasURL !== null) { // A URL to a json/xml file has been given @@ -9154,33 +9152,27 @@ var Phaser; if(typeof atlasData === 'string') { atlasData = JSON.parse(atlasData); } - // Malformed? - if(atlasData['frames']) { - this._queueSize++; - this._fileList[key] = { - type: 'textureatlas', - key: key, - url: textureURL, - data: null, - atlasURL: null, - atlasData: atlasData['frames'], - format: format, - error: false, - loaded: false - }; - this._keys.push(key); - } else { - throw new Error("Phaser.Loader. Invalid Texture Atlas JSON given, missing frames block"); - } + this._queueSize++; + this._fileList[key] = { + type: 'textureatlas', + key: key, + url: textureURL, + data: null, + atlasURL: null, + atlasData: atlasData['frames'], + format: format, + error: false, + loaded: false + }; + this._keys.push(key); } else if(format == Loader.TEXTURE_ATLAS_XML_STARLING) { // An xml string or object has been given if(typeof atlasData === 'string') { - var tmp; var xml; try { if(window['DOMParser']) { - tmp = new DOMParser(); - xml = tmp.parseFromString(atlasData, "text/xml"); + var domparser = new DOMParser(); + xml = domparser.parseFromString(atlasData, "text/xml"); } else { xml = new ActiveXObject("Microsoft.XMLDOM"); xml.async = 'false'; @@ -9195,24 +9187,19 @@ var Phaser; atlasData = xml; } } - // Malformed? - if(atlasData.getElementsByTagName('TextureAtlas')) { - this._queueSize++; - this._fileList[key] = { - type: 'textureatlas', - key: key, - url: textureURL, - data: null, - atlasURL: null, - atlasData: atlasData, - format: format, - error: false, - loaded: false - }; - this._keys.push(key); - } else { - throw new Error("Phaser.Loader. Invalid Texture Atlas XML given, missing tag"); - } + this._queueSize++; + this._fileList[key] = { + type: 'textureatlas', + key: key, + url: textureURL, + data: null, + atlasURL: null, + atlasData: atlasData, + format: format, + error: false, + loaded: false + }; + this._keys.push(key); } } } @@ -9410,11 +9397,8 @@ var Phaser; */ function (key) { var data = JSON.parse(this._xhr.response); - // Malformed? - if(data['frames']) { - var file = this._fileList[key]; - this._game.cache.addTextureAtlas(file.key, file.url, file.data, data['frames'], file.format); - } + var file = this._fileList[key]; + this._game.cache.addTextureAtlas(file.key, file.url, file.data, data['frames'], file.format); this.nextFile(key, true); }; Loader.prototype.dataLoadError = /** @@ -9427,14 +9411,12 @@ var Phaser; this.nextFile(key, true); }; Loader.prototype.xmlLoadComplete = function (key) { - var atlasData = this._xhr.response;// xml? - - var tmp; + var atlasData = this._xhr.response; var xml; try { if(window['DOMParser']) { - tmp = new DOMParser(); - xml = tmp.parseFromString(atlasData, "text/xml"); + var domparser = new DOMParser(); + xml = domparser.parseFromString(atlasData, "text/xml"); } else { xml = new ActiveXObject("Microsoft.XMLDOM"); xml.async = 'false'; @@ -9446,13 +9428,8 @@ var Phaser; if(!xml || !xml.documentElement || xml.getElementsByTagName("parsererror").length) { throw new Error("Phaser.Loader. Invalid Texture Atlas XML given"); } - // Malformed? - if(xml.getElementsByTagName('TextureAtlas')) { - var file = this._fileList[key]; - this._game.cache.addTextureAtlas(file.key, file.url, file.data, xml, file.format); - } else { - throw new Error("Phaser.Loader. Invalid Texture Atlas XML given, missing tag"); - } + var file = this._fileList[key]; + this._game.cache.addTextureAtlas(file.key, file.url, file.data, xml, file.format); this.nextFile(key, true); }; Loader.prototype.nextFile = /**