diff --git a/README.md b/README.md index ecb3646a14..1cbf30b873 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,7 @@ New features: * Group.moveDown(child) will move a child down the display list, swapping with the child below it. * Device.windowsPhone is now tested for. * The Debug panel now works in WebGL mode. Pay attention to the warning at the top of the Debug docs (feature request #499) +* You can now create blank Tilemaps and then populate them with data later. Updates: @@ -203,6 +204,7 @@ Bug Fixes: * Device no longer things a Windows Phone or Windows Tablet are desktop devices (thanks wombatbuddy, fixes #506) * Sound.onMarkerComplete event is now dispatched when a marker stops. See Sound.onLoop for a looping marker event (thanks registered99, fixes #500) * Events.onInputUp would be dispatched twice if the Sprite had drag enabled, now only dispatched once (thanks Overbryd, fixes #502) +* You can now load in CSV Tilemaps again and they get created properly (fixes #391) TO DO: diff --git a/examples/wip/tilemap blank.js b/examples/wip/tilemap blank.js index 8e853d59c5..7df91df5f0 100644 --- a/examples/wip/tilemap blank.js +++ b/examples/wip/tilemap blank.js @@ -35,7 +35,7 @@ function create() { layer.resizeWorld(); // Create our tile selector at the top of the screen - this.createTileSelector(); + createTileSelector(); game.input.setMoveCallback(updateMarker, this); diff --git a/examples/wip/tilemap csv.js b/examples/wip/tilemap csv.js new file mode 100644 index 0000000000..e3fd675b8f --- /dev/null +++ b/examples/wip/tilemap csv.js @@ -0,0 +1,59 @@ + +var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render }); +// var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.tilemap('map', 'assets/tilemaps/csv/catastrophi_level2.csv', null, Phaser.Tilemap.CSV); + game.load.image('tiles', 'assets/tilemaps/tiles/catastrophi_tiles_16.png'); + +} + +var map; +var layer; +var cursors; + +function create() { + + // Because we're loading CSV map data we have to specify the tile size here or we can't render it + map = game.add.tilemap('map', 16, 16); + + // Now add in the tileset + map.addTilesetImage('tiles'); + + // Create our layer + layer = map.createLayer(0); + + // Resize the world + layer.resizeWorld(); + + // Allow cursors to scroll around the map + cursors = game.input.keyboard.createCursorKeys(); + +} + +function update() { + + if (cursors.left.isDown) + { + game.camera.x -= 4; + } + else if (cursors.right.isDown) + { + game.camera.x += 4; + } + + if (cursors.up.isDown) + { + game.camera.y -= 4; + } + else if (cursors.down.isDown) + { + game.camera.y += 4; + } + +} + +function render() { + +} diff --git a/src/core/Game.js b/src/core/Game.js index 6c0798a5c6..9a88793f76 100644 --- a/src/core/Game.js +++ b/src/core/Game.js @@ -197,7 +197,7 @@ Phaser.Game = function (width, height, renderer, parent, state, transparent, ant this.canvas = null; /** - * @property {Context} context - A handy reference to renderer.context (only set for CANVAS games, not WebGL) + * @property {CanvasRenderingContext2D} context - A handy reference to renderer.context (only set for CANVAS games, not WebGL) */ this.context = null; diff --git a/src/gameobjects/GameObjectCreator.js b/src/gameobjects/GameObjectCreator.js index c1d4ec6177..6ccf67fc4b 100644 --- a/src/gameobjects/GameObjectCreator.js +++ b/src/gameobjects/GameObjectCreator.js @@ -270,15 +270,22 @@ Phaser.GameObjectCreator.prototype = { }, /** - * Creates a new Tilemap object. + * Creates a new Phaser.Tilemap object. The map can either be populated with data from a Tiled JSON file or from a CSV file. + * To do this pass the Cache key as the first parameter. When using Tiled data you need only provide the key. + * When using CSV data you must provide the key and the tileWidth and tileHeight parameters. + * If creating a blank tilemap to be populated later, you can either specify no parameters at all and then use `Tilemap.create` or pass the map and tile dimensions here. + * Note that all Tilemaps use a base tile size to calculate dimensions from, but that a TilemapLayer may have its own unique tile size that overrides it. * * @method Phaser.GameObjectCreator#tilemap - * @param {string} [key] - The key of the tilemap data as stored in the Cache. If you're creating a blank map don't pass anything for this parameter. - * @return {Phaser.Tilemap} The newly created tilemap object. + * @param {string} [key] - The key of the tilemap data as stored in the Cache. If you're creating a blank map either leave this parameter out or pass `null`. + * @param {number} [tileWidth=32] - The pixel width of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data. + * @param {number} [tileHeight=32] - The pixel height of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data. + * @param {number} [width=10] - The width of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this. + * @param {number} [height=10] - The height of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this. */ - tilemap: function (key) { + tilemap: function (key, tileWidth, tileHeight, width, height) { - return new Phaser.Tilemap(this.game, key); + return new Phaser.Tilemap(this.game, key, tileWidth, tileHeight, width, height); }, diff --git a/src/gameobjects/GameObjectFactory.js b/src/gameobjects/GameObjectFactory.js index f4c6aab858..a29fb6d7de 100644 --- a/src/gameobjects/GameObjectFactory.js +++ b/src/gameobjects/GameObjectFactory.js @@ -301,15 +301,23 @@ Phaser.GameObjectFactory.prototype = { }, /** - * Creates a new Tilemap object. + * Creates a new Phaser.Tilemap object. The map can either be populated with data from a Tiled JSON file or from a CSV file. + * To do this pass the Cache key as the first parameter. When using Tiled data you need only provide the key. + * When using CSV data you must provide the key and the tileWidth and tileHeight parameters. + * If creating a blank tilemap to be populated later, you can either specify no parameters at all and then use `Tilemap.create` or pass the map and tile dimensions here. + * Note that all Tilemaps use a base tile size to calculate dimensions from, but that a TilemapLayer may have its own unique tile size that overrides it. * * @method Phaser.GameObjectFactory#tilemap - * @param {string} [key] - The key of the tilemap data as stored in the Cache. If you're creating a blank map don't pass anything for this parameter. + * @param {string} [key] - The key of the tilemap data as stored in the Cache. If you're creating a blank map either leave this parameter out or pass `null`. + * @param {number} [tileWidth=32] - The pixel width of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data. + * @param {number} [tileHeight=32] - The pixel height of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data. + * @param {number} [width=10] - The width of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this. + * @param {number} [height=10] - The height of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this. * @return {Phaser.Tilemap} The newly created tilemap object. */ - tilemap: function (key) { + tilemap: function (key, tileWidth, tileHeight, width, height) { - return new Phaser.Tilemap(this.game, key); + return new Phaser.Tilemap(this.game, key, tileWidth, tileHeight, width, height); }, diff --git a/src/tilemap/Tilemap.js b/src/tilemap/Tilemap.js index a46a9c1d09..c54cc3640f 100644 --- a/src/tilemap/Tilemap.js +++ b/src/tilemap/Tilemap.js @@ -5,15 +5,24 @@ */ /** -* A Tile Map object. A Tile map consists of a set of tile data and tile sets. It is rendered to the display using a TilemapLayer. +* Creates a new Phaser.Tilemap object. The map can either be populated with data from a Tiled JSON file or from a CSV file. +* To do this pass the Cache key as the first parameter. When using Tiled data you need only provide the key. +* When using CSV data you must provide the key and the tileWidth and tileHeight parameters. +* If creating a blank tilemap to be populated later, you can either specify no parameters at all and then use `Tilemap.create` or pass the map and tile dimensions here. +* Note that all Tilemaps use a base tile size to calculate dimensions from, but that a TilemapLayer may have its own unique tile size that overrides it. +* A Tile map is rendered to the display using a TilemapLayer. It is not added to the display list directly itself. * A map may have multiple layers. You can perform operations on the map data such as copying, pasting, filling and shuffling the tiles around. * * @class Phaser.Tilemap * @constructor * @param {Phaser.Game} game - Game reference to the currently running game. -* @param {string} [key] - The key of the tilemap data as stored in the Cache. If you're creating a blank map don't pass anything for this parameter. +* @param {string} [key] - The key of the tilemap data as stored in the Cache. If you're creating a blank map either leave this parameter out or pass `null`. +* @param {number} [tileWidth=32] - The pixel width of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data. +* @param {number} [tileHeight=32] - The pixel height of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data. +* @param {number} [width=10] - The width of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this. +* @param {number} [height=10] - The height of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this. */ -Phaser.Tilemap = function (game, key) { +Phaser.Tilemap = function (game, key, tileWidth, tileHeight, width, height) { /** * @property {Phaser.Game} game - A reference to the currently running Game. @@ -25,7 +34,7 @@ Phaser.Tilemap = function (game, key) { */ this.key = key; - var data = Phaser.TilemapParser.parse(this.game, key); + var data = Phaser.TilemapParser.parse(this.game, key, tileWidth, tileHeight, width, height); if (data === null) { @@ -165,10 +174,8 @@ Phaser.Tilemap.prototype = { this.width = width; this.height = height; - this.tileWidth = tileWidth; - this.tileHeight = tileHeight; - this.widthInPixels = width * tileWidth; - this.heightInPixels = height * tileHeight; + + this.setTileSize(tileWidth, tileHeight); var row; var output = []; @@ -208,6 +215,22 @@ Phaser.Tilemap.prototype = { }, + /** + * Sets the base tile size for the map. + * + * @method Phaser.Tilemap#setTileSize + * @param {number} tileWidth - The width of the tiles the map uses for calculations. + * @param {number} tileHeight - The height of the tiles the map uses for calculations. + */ + setTileSize: function (tileWidth, tileHeight) { + + this.tileWidth = tileWidth; + this.tileHeight = tileHeight; + this.widthInPixels = this.width * tileWidth; + this.heightInPixels = this.height * tileHeight; + + }, + /** * Adds an image to the map to be used as a tileset. A single map may use multiple tilesets. * Note that the tileset name can be found in the JSON file exported from Tiled, or in the Tiled editor. diff --git a/src/tilemap/TilemapParser.js b/src/tilemap/TilemapParser.js index 8ff6470ee5..e854816116 100644 --- a/src/tilemap/TilemapParser.js +++ b/src/tilemap/TilemapParser.js @@ -67,25 +67,40 @@ Phaser.TilemapParser = { /** * Parse tilemap data from the cache and creates a Tilemap object. + * * @method Phaser.TilemapParser.parse * @param {Phaser.Game} game - Game reference to the currently running game. * @param {string} key - The key of the tilemap in the Cache. + * @param {number} [tileWidth=32] - The pixel width of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data. + * @param {number} [tileHeight=32] - The pixel height of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data. + * @param {number} [width=10] - The width of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this. + * @param {number} [height=10] - The height of the map in tiles. If this map is created from Tiled or CSV data you don't need to specify this. * @return {object} The parsed map object. */ - parse: function (game, key) { + parse: function (game, key, tileWidth, tileHeight, width, height) { + + if (typeof tileWidth === 'undefined') { tileWidth = 32; } + if (typeof tileHeight === 'undefined') { tileHeight = 32; } + if (typeof width === 'undefined') { width = 10; } + if (typeof height === 'undefined') { height = 10; } if (typeof key === 'undefined') { return this.getEmptyData(); } + if (key === null) + { + return this.getEmptyData(tileWidth, tileHeight, width, height); + } + var map = game.cache.getTilemapData(key); if (map) { if (map.format === Phaser.Tilemap.CSV) { - return this.parseCSV(map.data); + return this.parseCSV(key, map.data, tileWidth, tileHeight); } else if (map.format === Phaser.Tilemap.TILED_JSON) { @@ -101,11 +116,16 @@ Phaser.TilemapParser = { /** * Parses a CSV file into valid map data. + * * @method Phaser.TilemapParser.parseCSV * @param {string} data - The CSV file data. + * @param {number} [tileWidth=32] - The pixel width of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data. + * @param {number} [tileHeight=32] - The pixel height of a single map tile. If using CSV data you must specify this. Not required if using Tiled map data. * @return {object} Generated map data. */ - parseCSV: function (data) { + parseCSV: function (key, data, tileWidth, tileHeight) { + + var map = this.getEmptyData(); // Trim any rogue whitespace from the data data = data.trim(); @@ -115,15 +135,15 @@ Phaser.TilemapParser = { var height = rows.length; var width = 0; - for (var i = 0; i < rows.length; i++) + for (var y = 0; y < rows.length; y++) { - output[i] = []; + output[y] = []; - var column = rows[i].split(","); + var column = rows[y].split(","); - for (var c = 0; c < column.length; c++) + for (var x = 0; x < column.length; x++) { - output[i][c] = parseInt(column[c], 10); + output[y][x] = new Phaser.Tile(0, parseInt(column[x], 10), x, y, tileWidth, tileHeight); } if (width === 0) @@ -132,9 +152,21 @@ Phaser.TilemapParser = { } } - // Build collision map + map.name = key; + map.width = width; + map.height = height; + map.tileWidth = tileWidth; + map.tileHeight = tileHeight; + map.widthInPixels = width * tileWidth; + map.heightInPixels = height * tileHeight; - return [{ name: 'csv', width: width, height: height, alpha: 1, visible: true, indexes: [], tileMargin: 0, tileSpacing: 0, data: output }]; + map.layers[0].width = width; + map.layers[0].height = height; + map.layers[0].widthInPixels = map.widthInPixels; + map.layers[0].heightInPixels = map.heightInPixels; + map.layers[0].data = output; + + return map; }, @@ -143,7 +175,7 @@ Phaser.TilemapParser = { * @method Phaser.TilemapParser.getEmptyData * @return {object} Generated map data. */ - getEmptyData: function () { + getEmptyData: function (tileWidth, tileHeight, width, height) { var map = {}; @@ -151,6 +183,12 @@ Phaser.TilemapParser = { map.height = 0; map.tileWidth = 0; map.tileHeight = 0; + + if (typeof tileWidth !== 'undefined' && tileWidth !== null) { map.tileWidth = tileWidth; } + if (typeof tileHeight !== 'undefined' && tileHeight !== null) { map.tileHeight = tileHeight; } + if (typeof width !== 'undefined' && width !== null) { map.width = width; } + if (typeof height !== 'undefined' && height !== null) { map.height = height; } + map.orientation = 'orthogonal'; map.version = '1'; map.properties = {}; @@ -177,6 +215,8 @@ Phaser.TilemapParser = { }; + // fill with nulls? + layers.push(layer); map.layers = layers; @@ -256,7 +296,7 @@ Phaser.TilemapParser = { // Loop through the data field in the JSON. - // This is an array containing the tile indexes, one after the other. 0 = no tile, everything else = the tile index (starting at 1) + // This is an array containing the tile indexes, one after the other. null = no tile, everything else = the tile index (starting at 1 for Tiled, 0 for CSV) // If the map contains multiple tilesets then the indexes are relative to that which the set starts from. // Need to set which tileset in the cache = which tileset in the JSON, if you do this manually it means you can use the same map data but a new tileset.