From e5a4620b87414531f30a06b51d1213af67c0eda6 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Fri, 14 Feb 2014 23:51:49 +0000 Subject: [PATCH] Loader.physics now lets you load Lime + Corona JSON Physics data, which can be used with Body.loadPolygon and Body.loadData. Cache.addPhysicsData and Cache.getPhysicsData allow you to store parsed JSON physics data in the cache, for sharing between Bodies. --- README.md | 3 + examples/wip/p27.js | 12 +- src/loader/Cache.js | 337 +++++++++++++++++++++++++++++++++++-------- src/loader/Loader.js | 55 +++++++ src/physics/Body.js | 58 ++------ src/physics/World.js | 5 + 6 files changed, 365 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index b49220ad..0a87f962 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ Significant API changes: * BitmapData has had all of the EaselJS functions removed. It was just taking up space and you can do it all via BitmapData.context directly. * BitmapText has had a bit of an overhaul - the signature for adding a BitmapText has changed to: x, y, font, text, size. See the docs and examples for details. * World preUpdate, update and postUpdate have all been moved to Stage. So all children are updated regardless where on the display list they live. +* Cache.getImageKeys and similar has been removed, please use Cache.getKeys(Phaser.Cache.IMAGE) instead, this now supports all 10 Cache data types. New features: @@ -112,6 +113,8 @@ New features: * Loader.bitmapFont now has 2 extra parameters: xSpacing and ySpacing. These allow you to add extra spacing to each letter or line of the font. * Added the new BitmapFont class. This is for rendering retro style fixed-width bitmap fonts into an Image object. It's a texture you can apply to a Sprite/Image. * Added Cache.updateFrameData which is really useful for swapping FrameData blocks in the cache. +* Loader.physics now lets you load Lime + Corona JSON Physics data, which can be used with Body.loadPolygon and Body.loadData. +* Cache.addPhysicsData and Cache.getPhysicsData allow you to store parsed JSON physics data in the cache, for sharing between Bodies. Updates: diff --git a/examples/wip/p27.js b/examples/wip/p27.js index 7c3e6c82..3a810eb2 100644 --- a/examples/wip/p27.js +++ b/examples/wip/p27.js @@ -3,8 +3,8 @@ var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: function preload() { - // game.load.image('box', 'assets/sprites/block.png'); game.load.image('box', 'assets/sprites/diamond.png'); + game.load.physics('physobjects', 'assets/physics/diamond.json'); } @@ -24,8 +24,14 @@ function create() { box.physicsEnabled = true; + box.body.clearShapes(); + + box.body.loadPolygon('physobjects', 'diamond'); + box.body.rotateLeft(20); + // console.log(game.cache.getPhysicsData('physobjects', 'diamond')); + // 95x95 // box.body.setRectangle(64, 64); @@ -41,7 +47,9 @@ function create() { // Works // box.body.addPolygon({}, -100, 100, -100, 0, 100, 0, 100, 100, 50, 50); - box.body.addPolygon({}, 32, 13 , 17, 28 , 15, 28 , 0, 13 , 0, 7 , 7, 0 , 25, 0 , 32, 7 ); + // box.body.addPolygon({}, -100, 100, -100, 0, 100, 0, 100, 100, 50, 50 ); + + // box.body.addPolygon({}, 32, 13 , 17, 28 , 15, 28 , 0, 13 , 0, 7 , 7, 0 , 25, 0 , 32, 7 ); // Works // box.body.setPolygon({}, -1, 1, -1, 0, 1, 0, 1, 1, 0.5, 0.5); diff --git a/src/loader/Cache.js b/src/loader/Cache.js index 739621be..3945e693 100644 --- a/src/loader/Cache.js +++ b/src/loader/Cache.js @@ -49,6 +49,12 @@ Phaser.Cache = function (game) { */ this._text = {}; + /** + * @property {object} _physics - Physics data key-value container. + * @private + */ + this._physics = {}; + /** * @property {object} _tilemaps - Tilemap key-value container. * @private @@ -83,10 +89,71 @@ Phaser.Cache = function (game) { }; +/** +* @constant +* @type {number} +*/ +Phaser.Cache.CANVAS = 1; + +/** +* @constant +* @type {number} +*/ +Phaser.Cache.IMAGE = 2; + +/** +* @constant +* @type {number} +*/ +Phaser.Cache.TEXTURE = 3; + +/** +* @constant +* @type {number} +*/ +Phaser.Cache.SOUND = 4; + +/** +* @constant +* @type {number} +*/ +Phaser.Cache.TEXT = 5; + +/** +* @constant +* @type {number} +*/ +Phaser.Cache.PHYSICS = 6; + +/** +* @constant +* @type {number} +*/ +Phaser.Cache.TILEMAP = 7; + +/** +* @constant +* @type {number} +*/ +Phaser.Cache.BINARY = 8; + +/** +* @constant +* @type {number} +*/ +Phaser.Cache.BITMAPDATA = 9; + +/** +* @constant +* @type {number} +*/ +Phaser.Cache.BITMAPFONT = 10; + Phaser.Cache.prototype = { /** * Add a new canvas object in to the cache. + * * @method Phaser.Cache#addCanvas * @param {string} key - Asset key for this canvas. * @param {HTMLCanvasElement} canvas - Canvas DOM element. @@ -100,6 +167,7 @@ Phaser.Cache.prototype = { /** * Add a binary object in to the cache. + * * @method Phaser.Cache#addBinary * @param {string} key - Asset key for this binary data. * @param {object} binaryData - The binary object to be addded to the cache. @@ -112,6 +180,7 @@ Phaser.Cache.prototype = { /** * Add a BitmapData object in to the cache. + * * @method Phaser.Cache#addBitmapData * @param {string} key - Asset key for this BitmapData. * @param {Phaser.BitmapData} bitmapData - The BitmapData object to be addded to the cache. @@ -178,7 +247,7 @@ Phaser.Cache.prototype = { }, /** - * Add a new tilemap. + * Add a new tilemap to the Cache. * * @method Phaser.Cache#addTilemap * @param {string} key - The unique key by which you will reference this object. @@ -193,7 +262,7 @@ Phaser.Cache.prototype = { }, /** - * Add a new texture atlas. + * Add a new texture atlas to the Cache. * * @method Phaser.Cache#addTextureAtlas * @param {string} key - The unique key by which you will reference this object. @@ -225,7 +294,7 @@ Phaser.Cache.prototype = { }, /** - * Add a new Bitmap Font. + * Add a new Bitmap Font to the Cache. * * @method Phaser.Cache#addBitmapFont * @param {string} key - The unique key by which you will reference this object. @@ -246,10 +315,26 @@ Phaser.Cache.prototype = { }, + /** + * Add a new physics data object to the Cache. + * + * @method Phaser.Cache#addTilemap + * @param {string} key - The unique key by which you will reference this object. + * @param {string} url - URL of the physics json data. + * @param {object} JSONData - The physics data object (a JSON file). + * @param {number} format - The format of the physics data. + */ + addPhysicsData: function (key, url, JSONData, format) { + + this._physics[key] = { url: url, data: JSONData, format: format }; + + }, + /** * Adds a default image to be used in special cases such as WebGL Filters. Is mapped to the key __default. * * @method Phaser.Cache#addDefaultImage + * @protected */ addDefaultImage: function () { @@ -268,6 +353,7 @@ Phaser.Cache.prototype = { * Adds an image to be used when a key is wrong / missing. Is mapped to the key __missing. * * @method Phaser.Cache#addMissingImage + * @protected */ addMissingImage: function () { @@ -292,10 +378,7 @@ Phaser.Cache.prototype = { */ addText: function (key, url, data) { - this._text[key] = { - url: url, - data: data - }; + this._text[key] = { url: url, data: data }; }, @@ -318,23 +401,6 @@ Phaser.Cache.prototype = { }, - /** - * Replaces a set of frameData with a new Phaser.FrameData object. - * - * @method Phaser.Cache#updateFrameData - * @param {string} key - The unique key by which you will reference this object. - * @param {number} frameData - The new FrameData. - */ - updateFrameData: function (key, frameData) { - - if (this._images[key]) - { - this._images[key].spriteSheet = true; - this._images[key].frameData = frameData; - } - - }, - /** * Add a new sound. * @@ -489,6 +555,44 @@ Phaser.Cache.prototype = { }, + /** + * Get a physics data object from the cache by its key. You can get either the entire data set or just a single object from it. + * + * @method Phaser.Cache#getPhysicsData + * @param {string} key - Asset key of the physics data object to retrieve from the Cache. + * @param {string} [object=null] - If specified it will return just the physics object that is part of the given key, if null it will return them all. + * @return {object} The requested physics object data if found. + */ + getPhysicsData: function (key, object) { + + if (typeof object === 'undefined' || object === null) + { + // Get 'em all + if (this._physics[key]) + { + return this._physics[key].data; + } + else + { + console.warn('Phaser.Cache.getPhysicsData: Invalid key: "' + key + '"'); + } + } + else + { + if (this._physics[key] && this._physics[key].data[object]) + { + return this._physics[key].data[object][0]; + } + else + { + console.warn('Phaser.Cache.getPhysicsData: Invalid key/object: "' + key + ' / ' + object + '"'); + } + } + + return null; + + }, + /** * Checks if an image key exists. * @@ -564,6 +668,23 @@ Phaser.Cache.prototype = { return null; }, + /** + * Replaces a set of frameData with a new Phaser.FrameData object. + * + * @method Phaser.Cache#updateFrameData + * @param {string} key - The unique key by which you will reference this object. + * @param {number} frameData - The new FrameData. + */ + updateFrameData: function (key, frameData) { + + if (this._images[key]) + { + this._images[key].spriteSheet = true; + this._images[key].frameData = frameData; + } + + }, + /** * Get a single frame out of a frameData set by key. * @@ -780,14 +901,63 @@ Phaser.Cache.prototype = { }, /** - * Get the cache keys from a given array of objects. - * Normally you don't call this directly but instead use getImageKeys, getSoundKeys, etc. + * Gets all keys used by the Cache for the given data type. * * @method Phaser.Cache#getKeys - * @param {Array} array - An array of items to return the keys for. + * @param {number} [type=Phaser.Cache.IMAGE] - The type of Cache keys you wish to get. Can be Cache.CANVAS, Cache.IMAGE, Cache.SOUND, etc. * @return {Array} The array of item keys. */ - getKeys: function (array) { + getKeys: function (type) { + + var array = null; + + switch (type) + { + case Phaser.Cache.CANVAS: + array = this._canvases; + break; + + case Phaser.Cache.IMAGE: + array = this._images; + break; + + case Phaser.Cache.TEXTURE: + array = this._textures; + break; + + case Phaser.Cache.SOUND: + array = this._sounds; + break; + + case Phaser.Cache.TEXT: + array = this._text; + break; + + case Phaser.Cache.PHYSICS: + array = this._physics; + break; + + case Phaser.Cache.TILEMAP: + array = this._tilemaps; + break; + + case Phaser.Cache.BINARY: + array = this._binary; + break; + + case Phaser.Cache.BITMAPDATA: + array = this._bitmapDatas; + break; + + case Phaser.Cache.BITMAPFONT: + array = this._bitmapFont; + break; + } + + if (!array) + { + return; + } var output = []; @@ -803,36 +973,6 @@ Phaser.Cache.prototype = { }, - /** - * Returns an array containing all of the keys of Images in the Cache. - * - * @method Phaser.Cache#getImageKeys - * @return {Array} The string based keys in the Cache. - */ - getImageKeys: function () { - return this.getKeys(this._images); - }, - - /** - * Returns an array containing all of the keys of Sounds in the Cache. - * - * @method Phaser.Cache#getSoundKeys - * @return {Array} The string based keys in the Cache. - */ - getSoundKeys: function () { - return this.getKeys(this._sounds); - }, - - /** - * Returns an array containing all of the keys of Text Files in the Cache. - * - * @method Phaser.Cache#getTextKeys - * @return {Array} The string based keys in the Cache. - */ - getTextKeys: function () { - return this.getKeys(this._text); - }, - /** * Removes a canvas from the cache. * @@ -873,6 +1013,56 @@ Phaser.Cache.prototype = { delete this._text[key]; }, + /** + * Removes a physics data file from the cache. + * + * @method Phaser.Cache#removePhysics + * @param {string} key - Key of the asset you want to remove. + */ + removePhysics: function (key) { + delete this._text[key]; + }, + + /** + * Removes a tilemap from the cache. + * + * @method Phaser.Cache#removeTilemap + * @param {string} key - Key of the asset you want to remove. + */ + removeTilemap: function (key) { + delete this._text[key]; + }, + + /** + * Removes a binary file from the cache. + * + * @method Phaser.Cache#removeBinary + * @param {string} key - Key of the asset you want to remove. + */ + removeBinary: function (key) { + delete this._text[key]; + }, + + /** + * Removes a bitmap data from the cache. + * + * @method Phaser.Cache#removeBitmapData + * @param {string} key - Key of the asset you want to remove. + */ + removeBitmapData: function (key) { + delete this._text[key]; + }, + + /** + * Removes a bitmap font from the cache. + * + * @method Phaser.Cache#removeBitmapFont + * @param {string} key - Key of the asset you want to remove. + */ + removeBitmapFont: function (key) { + delete this._text[key]; + }, + /** * Clears the cache. Removes every local cache object reference. * @@ -899,6 +1089,37 @@ Phaser.Cache.prototype = { { delete this._text[item['key']]; } + + for (var item in this._textures) + { + delete this._textures[item['key']]; + } + + for (var item in this._physics) + { + delete this._physics[item['key']]; + } + + for (var item in this._tilemaps) + { + delete this._tilemaps[item['key']]; + } + + for (var item in this._binary) + { + delete this._binary[item['key']]; + } + + for (var item in this._bitmapDatas) + { + delete this._bitmapDatas[item['key']]; + } + + for (var item in this._bitmapFont) + { + delete this._bitmapFont[item['key']]; + } + } }; diff --git a/src/loader/Loader.js b/src/loader/Loader.js index f8489a20..f6ee485f 100644 --- a/src/loader/Loader.js +++ b/src/loader/Loader.js @@ -133,6 +133,12 @@ Phaser.Loader.TEXTURE_ATLAS_JSON_HASH = 1; */ Phaser.Loader.TEXTURE_ATLAS_XML_STARLING = 2; +/** +* @constant +* @type {number} +*/ +Phaser.Loader.PHYSICS_LIME_CORONA = 3; + Phaser.Loader.prototype = { /** @@ -489,6 +495,49 @@ Phaser.Loader.prototype = { }, + /** + * Add a new physics data object loading request. + * The data must be in Lime + Corona JSON format. Physics Editor by code'n'web exports in this format natively. + * + * @method Phaser.Loader#physics + * @param {string} key - Unique asset key of the physics json data. + * @param {string} [dataURL] - The url of the map data file (csv/json) + * @param {object} [jsonData] - An optional JSON data object. If given then the dataURL is ignored and this JSON object is used for physics data instead. + * @param {string} [format=Phaser.Physics.LIME_CORONA_JSON] - The format of the physics data. + * @return {Phaser.Loader} This Loader instance. + */ + physics: function (key, dataURL, jsonData, format) { + + if (typeof dataURL === "undefined") { dataURL = null; } + if (typeof jsonData === "undefined") { jsonData = null; } + if (typeof format === "undefined") { format = Phaser.Physics.LIME_CORONA_JSON; } + + if (dataURL == null && jsonData == null) + { + console.warn('Phaser.Loader.physics - Both dataURL and jsonData are null. One must be set.'); + + return this; + } + + // A map data object has been given + if (jsonData) + { + if (typeof jsonData === 'string') + { + jsonData = JSON.parse(jsonData); + } + + this.game.cache.addPhysicsData(key, null, jsonData, format); + } + else + { + this.addToFileList('physics', key, dataURL, { format: format }); + } + + return this; + + }, + /** * Add a new bitmap font loading request. * @@ -863,6 +912,7 @@ Phaser.Loader.prototype = { case 'text': case 'script': + case 'physics': this._xhr.open("GET", this.baseURL + file.url, true); this._xhr.responseType = "text"; this._xhr.onload = function () { @@ -1065,6 +1115,11 @@ Phaser.Loader.prototype = { this.game.cache.addText(file.key, file.url, file.data); break; + case 'physics': + var data = JSON.parse(this._xhr.responseText); + this.game.cache.addPhysicsData(file.key, file.url, data, file.format); + break; + case 'script': file.data = document.createElement('script'); file.data.language = 'javascript'; diff --git a/src/physics/Body.js b/src/physics/Body.js index ee98ef8c..c0937d88 100644 --- a/src/physics/Body.js +++ b/src/physics/Body.js @@ -534,7 +534,7 @@ Phaser.Physics.Body.prototype = { var path; // Did they pass in a single array of points? - if (points.length === 1) + if (points.length === 1 && Array.isArray(points[0])) { path = points[0]; } @@ -643,69 +643,37 @@ Phaser.Physics.Body.prototype = { }, /** - * Reads a polygon shape path, and assembles convex shapes from that and puts them at proper offset points. The shape must be simple and without holes. - * This function expects the x.y values to be given in pixels. If you want to provide them at p2 world scales then call Body.data.fromPolygon directly. + * Reads the shape data from a physics data file stored in the Game.Cache and adds it as a polygon to this Body. * - * @method Phaser.Physics.Body#setPolygon + * @method Phaser.Physics.Body#loadPolygon + * @param {string} key - The key of the Physics Data file as stored in Game.Cache. + * @param {string} object - The key of the object within the Physics data file that you wish to load the shape data from. * @param {object} options - An object containing the build options: * @param {boolean} [options.optimalDecomp=false] - Set to true if you need optimal decomposition. Warning: very slow for polygons with more than 10 vertices. * @param {boolean} [options.skipSimpleCheck=false] - Set to true if you already know that the path is not intersecting itself. * @param {boolean|number} [options.removeCollinearPoints=false] - Set to a number (angle threshold value) to remove collinear points, or false to keep all points. - * @param {(number[]|...number)} points - An array of 2d vectors that form the convex or concave polygon. - * Either [[0,0], [0,1],...] or a flat array of numbers that will be interpreted as [x,y, x,y, ...], - * or the arguments passed can be flat x,y values e.g. `setPolygon(options, x,y, x,y, x,y, ...)` where `x` and `y` are numbers. * @return {boolean} True on success, else false. - setPolygon: function (options, points) { + */ + loadPolygon: function (key, object, options) { - options = options || {}; + var data = game.cache.getPhysicsData(key, object); - points = Array.prototype.slice.call(arguments, 1); - - var path; - - // Did they pass in a single array of points? - if (points.length === 1) + if (data && data.shape) { - // console.log('part 1', points.length); - path = points[0]; - } - else if (Array.isArray(points[0])) - { - // console.log('part 2', points.length); - path = points; - } - else if (typeof points[0] === 'number') - { - // A list of numbers? - // console.log('part 3'); - var temp = []; // We've a list of numbers - for (var i = 0, len = points.length; i < len; i += 2) + for (var i = 0, len = data.shape.length; i < len; i += 2) { - temp.push([points[i], points[i + 1]]); + temp.push([data.shape[i], data.shape[i + 1]]); } - path = temp; + return this.addPolygon(options, temp); } - // Now process them into p2 values - for (var p = 0; p < path.length; p++) - { - path[p][0] = this.px2p(path[p][0]); - path[p][1] = this.px2p(path[p][1]); - } - - // console.log('points'); - // console.table(points); - // console.log('PATH'); - // console.log(path); - - return this.data.fromPolygon(path, options); + return false; }, - */ /** * Convert p2 physics value to pixel scale. diff --git a/src/physics/World.js b/src/physics/World.js index 3b567a70..56e3f170 100644 --- a/src/physics/World.js +++ b/src/physics/World.js @@ -9,6 +9,11 @@ */ Phaser.Physics = {}; +/** +* @const +*/ +Phaser.Physics.LIME_CORONA_JSON = 0; + // Add an extra property to p2.Body p2.Body.prototype.parent = null;