diff --git a/Docs/Screen Shots/phaser_tilemap_debug.png b/Docs/Screen Shots/phaser_tilemap_debug.png new file mode 100644 index 00000000..392022ce Binary files /dev/null and b/Docs/Screen Shots/phaser_tilemap_debug.png differ diff --git a/examples/assets/maps/cybernoid.png.png b/examples/assets/maps/cybernoid.png similarity index 100% rename from examples/assets/maps/cybernoid.png.png rename to examples/assets/maps/cybernoid.png diff --git a/examples/tilemaps/wip1.php b/examples/tilemaps/wip1.php index 731ba5c9..25cb8c10 100644 --- a/examples/tilemaps/wip1.php +++ b/examples/tilemaps/wip1.php @@ -10,54 +10,73 @@ function preload() { - game.load.tilemap('cybernoidLevel3', 'assets/maps/cybernoid.json', null, Phaser.Tilemap.JSON); - game.load.tileset('cybernoidTiles', 'assets/maps/cybernoid.png', 16, 16); + game.load.tilemap('level3', 'assets/maps/cybernoid.json', null, Phaser.Tilemap.TILED_JSON); + game.load.tileset('tiles', 'assets/maps/cybernoid.png', 16, 16); } var layer; + var cursors; function create() { game.stage.backgroundColor = '#3d3d3d'; + var map = new Phaser.Tilemap(game, 'level3'); + + // This is a bit nuts, ought to find a way to automate it, but it looks cool :) + map.debugMap = [ '#000000', + '#e40058', '#e40058', '#e40058', '#80d010', '#bcbcbc', '#e40058', '#000000', '#0070ec', '#bcbcbc', '#bcbcbc', '#bcbcbc', + '#bcbcbc', '#bcbcbc', '#e40058', '#e40058', '#0070ec', '#0070ec', '#80d010', '#80d010', '#80d010', '#bcbcbc', '#bcbcbc', + '#bcbcbc', '#80d010', '#80d010', '#80d010', '#0070ec', '#0070ec', '#80d010', '#80d010', '#80d010', '#80d010', '#0070ec', + '#0070ec', '#24188c', '#24188c', '#80d010', '#80d010', '#80d010', '#bcbcbc', '#80d010', '#80d010', '#80d010', '#e40058', + '#e40058', '#bcbcbc', '#e40058', '#bcbcbc', '#e40058', '#bcbcbc', '#80d010', '#bcbcbc', '#80d010', '#000000', '#80d010', + '#80d010', '#80d010', '#bcbcbc', '#e40058', '#80d010', '#80d010', '#e40058', '#e40058', '#bcbcbc', '#bcbcbc', '#bcbcbc', + '#0070ec', '#0070ec', '#bcbcbc', '#bcbcbc', '#0070ec', '#0070ec', '#bcbcbc', '#bcbcbc', '#bcbcbc', '#bcbcbc', '#bcbcbc', + '#bcbcbc', '#bcbcbc' + ]; + + map.dump(); + + layer = new Phaser.TilemapLayer(game, 200, 200, 320, 200); + layer.updateTileset('tiles'); + layer.updateMapData(map, 0); + + layer.sprite.anchor.setTo(0.5, 0.5); + + game.world.add(layer.sprite); - // layer = new Phaser.TilemapLayer(game, 0, 0, 500, 500, [], 'snes'); - - // layer = new Phaser.TilemapLayer(game, 0, 0, 500, 500); - - - // layer.load(mapData, tileset); - // layer.create(mapWidth, mapHeight, [tileset]); - - // layer.updateTileset('cybernoidTiles'); // can change on the fly - - - // layer.context.fillStyle = 'rgb(255,0,0)'; - // layer.context.fillRect(0, 0, 200, 300); - - /* - game.world._container.addChild(layer.sprite); - - layer.create(10, 10); - - layer.putTile(0, 0, 3); - layer.putTile(0, 1, 4); - - layer.render(); - - layer.dump(); - */ + cursors = game.input.keyboard.createCursorKeys(); } function update() { + // layer.sprite.angle += 0.5; + + if (cursors.up.isDown) + { + layer.y -= 4; + } + else if (cursors.down.isDown) + { + layer.y += 4; + } + + if (cursors.left.isDown) + { + layer.x -= 4; + } + else if (cursors.right.isDown) + { + layer.x += 4; + } } function render() { + layer.render(); } diff --git a/src/gameobjects/Sprite.js b/src/gameobjects/Sprite.js index 4d0607f6..58872c37 100644 --- a/src/gameobjects/Sprite.js +++ b/src/gameobjects/Sprite.js @@ -97,6 +97,12 @@ Phaser.Sprite = function (game, x, y, key, frame) { this.currentFrame = this.game.cache.getTextureFrame(key.name); } + else if (key instanceof PIXI.Texture) + { + PIXI.Sprite.call(this, key); + + this.currentFrame = frame; + } else { if (key == null || this.game.cache.checkImageKey(key) == false) diff --git a/src/loader/Cache.js b/src/loader/Cache.js index ebcda117..a644a4ec 100644 --- a/src/loader/Cache.js +++ b/src/loader/Cache.js @@ -156,9 +156,9 @@ Phaser.Cache.prototype = { */ addTilemap: function (key, url, mapData, format) { - this._tilemaps[key] = { url: url, mapData: mapData, format: format }; + this._tilemaps[key] = { url: url, data: mapData, format: format }; - this._tilemaps[key].mapData = Phaser.TilemapParser.parse(this.game, mapData, format); + this._tilemaps[key].layers = Phaser.TilemapParser.parse(this.game, mapData, format); }, @@ -453,9 +453,9 @@ Phaser.Cache.prototype = { * * @method Phaser.Cache#getTilemap * @param {string} key - Asset key of the tilemap you want. - * @return {Phaser.Tilemap} The tilemap data. The tileset image is in the data property, the map data in mapData. + * @return {Object} The tilemap data. The tileset image is in the data property, the map data in mapData. */ - getTilemap: function (key) { + getTilemapData: function (key) { if (this._tilemaps[key]) { diff --git a/src/loader/Loader.js b/src/loader/Loader.js index 1c496073..42c60a30 100644 --- a/src/loader/Loader.js +++ b/src/loader/Loader.js @@ -371,7 +371,7 @@ Phaser.Loader.prototype = { break; // An xml string or object has been given - case Phaser.Tilemap.JSON: + case Phaser.Tilemap.TILED_JSON: if (typeof mapData === 'string') { @@ -710,7 +710,7 @@ Phaser.Loader.prototype = { this._xhr.open("GET", this.baseURL + file.url, true); this._xhr.responseType = "text"; - if (file.format == Phaser.Tilemap.JSON) + if (file.format == Phaser.Tilemap.TILED_JSON) { this._xhr.onload = function () { return _this.jsonLoadComplete(file.key); diff --git a/src/tilemap/Tilemap.js b/src/tilemap/Tilemap.js index 5d2506d1..3f8b9e72 100644 --- a/src/tilemap/Tilemap.js +++ b/src/tilemap/Tilemap.js @@ -1,11 +1,134 @@ -Phaser.Tilemap = function (game, key, x, y, resizeWorld, tileWidth, tileHeight) { +Phaser.Tilemap = function (game, key) { + + /** + * @property {Phaser.Game} game - Description. + */ + this.game = game; + + /** + * @property {array} layers - Description. + */ + this.layers; + + if (typeof key === 'string') + { + this.key = key; + + this.layers = game.cache.getTilemapData(key).layers; + } + else + { + this.layers = []; + } + + this.currentLayer = 0; + + this.debugMap = []; }; -// Needed to keep the PIXI.Sprite constructor in the prototype chain (as the core pixi renderer uses an instanceof check sadly) -Phaser.Tilemap.prototype = Object.create(PIXI.DisplayObjectContainer.prototype); -Phaser.Tilemap.prototype.constructor = Phaser.Tilemap; - Phaser.Tilemap.CSV = 0; -Phaser.Tilemap.JSON = 1; +Phaser.Tilemap.TILED_JSON = 1; +Phaser.Tilemap.prototype = { + + create: function (name, width, height) { + + var data = []; + + for (var y = 0; y < height; y++) + { + data[y] = []; + + for (var x = 0; x < width; x++) + { + data[y][x] = 0; + } + } + + this.currentLayer = this.layers.push({ + + name: name, + width: width, + height: height, + alpha: 1, + visible: true, + tileMargin: 0, + tileSpacing: 0, + format: Phaser.Tilemap.CSV, + data: data + + }); + + }, + + setLayer: function (layer) { + + if (this.layers[layer]) + { + this.currentLayer = layer; + } + + }, + + createLayerSprite: function (tilset) { + + // Creates a TilemapLayer which you can add to the display list + // Hooked to a specific layer within the map data + + + }, + + /** + * Set a specific tile with its x and y in tiles. + * @method putTile + * @param {number} x - X position of this tile. + * @param {number} y - Y position of this tile. + * @param {number} index - The index of this tile type in the core map data. + */ + putTile: function (x, y, index) { + + if (x >= 0 && x < this.layers[this.currentLayer].width && y >= 0 && y < this.layers[this.currentLayer].height) + { + this.layers[this.currentLayer].data[y][x] = index; + } + + }, + + dump: function () { + + var txt = ''; + var args = ['']; + + for (var y = 0; y < this.layers[this.currentLayer].height; y++) + { + for (var x = 0; x < this.layers[this.currentLayer].width; x++) + { + txt += "%c "; + + if (this.layers[this.currentLayer].data[y][x] > 1) + { + if (this.debugMap[this.layers[this.currentLayer].data[y][x]]) + { + args.push("background: " + this.debugMap[this.layers[this.currentLayer].data[y][x]]); + } + else + { + args.push("background: #ffffff"); + } + } + else + { + args.push("background: rgb(0, 0, 0)"); + } + } + + txt += "\n"; + } + + args[0] = txt; + console.log.apply(console, args); + + } + +}; diff --git a/src/tilemap/TilemapLayer.js b/src/tilemap/TilemapLayer.js index 6eae2601..dbf9918b 100644 --- a/src/tilemap/TilemapLayer.js +++ b/src/tilemap/TilemapLayer.js @@ -30,16 +30,14 @@ Phaser.TilemapLayer = function (game, x, y, renderWidth, renderHeight, mapData, */ this.texture = new PIXI.Texture(this.baseTexture); + // index, x, y, width, height, name, uuid + this.frame = new Phaser.Frame(0, 0, 0, renderWidth, renderHeight, 'tilemaplayer', game.rnd.uuid()); + /** * @property {Description} sprite - Description. * @default */ - this.sprite = new PIXI.Sprite(this.texture); - - /** - * @property {array} mapData - Description. - */ - this.mapData = []; + this.sprite = new Phaser.Sprite(this.game, x, y, this.texture, this.frame); /** * @property {Description} tileset - Description. @@ -127,46 +125,32 @@ Phaser.TilemapLayer = function (game, x, y, renderWidth, renderHeight, mapData, */ this._startY = 0; + this.tilemap; + this.layer; + + this._x = 0; + this._y = 0; + this._prevX = 0; + this._prevY = 0; + this.dirty = true; + }; Phaser.TilemapLayer.prototype = { - create: function (width, height) { + updateMapData: function (tilemap, layerID) { - this.mapData = []; + this.tilemap = tilemap; + this.layer = this.tilemap.layers[layerID]; - var data; - - for (var y = 0; y < height; y++) + if (this._maxX > this.layer.width) { - this.mapData[y] = []; - - for (var x = 0; x < width; x++) - { - this.mapData[y][x] = 0; - } + this._maxX = this.layer.width; } - this.widthInTiles = width; - this.heightInTiles = height; - - }, - - /** - * Set a specific tile with its x and y in tiles. - * @method putTile - * @param {number} x - X position of this tile. - * @param {number} y - Y position of this tile. - * @param {number} index - The index of this tile type in the core map data. - */ - putTile: function (x, y, index) { - - if (y >= 0 && y < this.mapData.length) + if (this._maxY > this.layer.height) { - if (x >= 0 && x < this.mapData[y].length) - { - this.mapData[y][x] = index; - } + this._maxY = this.layer.height; } }, @@ -177,22 +161,26 @@ Phaser.TilemapLayer.prototype = { this.tileWidth = this.tileset.tileWidth; this.tileHeight = this.tileset.tileHeight; + // This don't need to be calculated every frame! + this._maxX = this.game.math.ceil(this.canvas.width / this.tileWidth) + 1; + this._maxY = this.game.math.ceil(this.canvas.height / this.tileHeight) + 1; + }, render: function () { - if (this.visible == false) + if (this.visible == false || this.dirty == false) { return; } // Work out how many tiles we can fit into our canvas and round it up for the edges - this._maxX = this.game.math.ceil(this.canvas.width / this.tileWidth) + 1; - this._maxY = this.game.math.ceil(this.canvas.height / this.tileHeight) + 1; + // this._maxX = this.game.math.ceil(this.canvas.width / this.tileWidth) + 1; + // this._maxY = this.game.math.ceil(this.canvas.height / this.tileHeight) + 1; // And now work out where in the tilemap the camera actually is - this._startX = this.game.math.floor(this.game.camera.x / this.tileWidth); - this._startY = this.game.math.floor(this.game.camera.y / this.tileHeight); + this._startX = this.game.math.floor(this._x / this.tileWidth); + this._startY = this.game.math.floor(this._y / this.tileHeight); // Tilemap bounds check if (this._startX < 0) @@ -205,47 +193,40 @@ Phaser.TilemapLayer.prototype = { this._startY = 0; } - if (this._maxX > this.widthInTiles) + if (this._startX + this._maxX > this.layer.width) { - this._maxX = this.widthInTiles; + this._startX = this.layer.width - this._maxX; } - if (this._maxY > this.heightInTiles) + if (this._startY + this._maxY > this.layer.height) { - this._maxY = this.heightInTiles; - } - - if (this._startX + this._maxX > this.widthInTiles) - { - this._startX = this.widthInTiles - this._maxX; - } - - if (this._startY + this._maxY > this.heightInTiles) - { - this._startY = this.heightInTiles - this._maxY; + this._startY = this.layer.height - this._maxY; } // Finally get the offset to avoid the blocky movement - this._dx = -(this.game.camera.x - (this._startX * this.tileWidth)); - this._dy = -(this.game.camera.y - (this._startY * this.tileHeight)); + this._dx = -(this._x - (this._startX * this.tileWidth)); + this._dy = -(this._y - (this._startY * this.tileHeight)); this._tx = this._dx; this._ty = this._dy; this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); - for (var row = this._startY; row < this._startY + this._maxY; row++) + for (var y = this._startY; y < this._startY + this._maxY; y++) { - this._columnData = this.mapData[row]; + this._column = this.layer.data[y]; - for (var tile = this._startX; tile < this._startX + this._maxX; tile++) + for (var x = this._startX; x < this._startX + this._maxX; x++) { - if (this.tileset.checkTileIndex(this._columnData[tile])) - { + // only -1 on TILED maps, not CSV + var tile = this.tileset.tiles[this._column[x]-1]; + + // if (this.tileset.checkTileIndex(tile)) + // { this.context.drawImage( this.tileset.image, - this.tileset.tiles[this._columnData[tile]].x, - this.tileset.tiles[this._columnData[tile]].y, + tile.x, + tile.y, this.tileWidth, this.tileHeight, this._tx, @@ -253,7 +234,7 @@ Phaser.TilemapLayer.prototype = { this.tileWidth, this.tileHeight ); - } + // } this._tx += this.tileWidth; @@ -269,39 +250,62 @@ Phaser.TilemapLayer.prototype = { PIXI.texturesToUpdate.push(this.baseTexture); } + this.dirty = false; + return true; - }, - - - dump: function () { - - var txt = ''; - var args = ['']; - - for (var y = 0; y < this.heightInTiles; y++) - { - for (var x = 0; x < this.widthInTiles; x++) - { - txt += "%c "; - - if (this.mapData[y][x] > 0) - { - args.push("background: rgb(50, 50, 50)"); - } - else - { - args.push("background: rgb(0, 0, 0)"); - } - } - - txt += "\n"; - } - - args[0] = txt; - console.log.apply(console, args); - } }; +Phaser.TilemapLayer.prototype.deltaAbsX = function () { + return (this.deltaX() > 0 ? this.deltaX() : -this.deltaX()); +} + +Phaser.TilemapLayer.prototype.deltaAbsY = function () { + return (this.deltaY() > 0 ? this.deltaY() : -this.deltaY()); +} + +Phaser.TilemapLayer.prototype.deltaX = function () { + return this._x - this._prevX; +} + +Phaser.TilemapLayer.prototype.deltaY = function () { + return this._y - this._prevY; +} + +Object.defineProperty(Phaser.TilemapLayer.prototype, "x", { + + get: function () { + return this._x; + }, + + set: function (value) { + + if (value !== this._x) + { + this._x = value; + this.dirty = true; + } + + } + +}); + +Object.defineProperty(Phaser.TilemapLayer.prototype, "y", { + + get: function () { + return this._y; + }, + + set: function (value) { + + if (value !== this._y) + { + this._y = value; + this.dirty = true; + } + + } + +}); diff --git a/src/tilemap/TilemapParser.js b/src/tilemap/TilemapParser.js index 1ac34209..b80a5df0 100644 --- a/src/tilemap/TilemapParser.js +++ b/src/tilemap/TilemapParser.js @@ -64,11 +64,11 @@ Phaser.TilemapParser = { parse: function (game, data, format) { - if (format == Phaser.Tilemap.CSV) + if (format === Phaser.Tilemap.CSV) { return this.parseCSV(data); } - else if (format == Phaser.Tilemap.TILED_JSON) + else if (format === Phaser.Tilemap.TILED_JSON) { return this.parseTiledJSON(data); } @@ -87,8 +87,9 @@ Phaser.TilemapParser = { data = data.trim(); var output = []; - var rows = data.split("\n"); + var height = rows.length; + var width = 0; for (var i = 0; i < rows.length; i++) { @@ -100,9 +101,14 @@ Phaser.TilemapParser = { { output[i][c] = parseInt(column[c]); } + + if (width == 0) + { + width = column.length; + } } - return [{ name: 'csv', alpha: 1, visible: true, tileMargin: 0, tileSpacing: 0, data: output }]; + return [{ name: 'csv', width: width, height: height, alpha: 1, visible: true, tileMargin: 0, tileSpacing: 0, data: output }]; }, @@ -131,10 +137,13 @@ Phaser.TilemapParser = { var layer = { name: json.layers[i].name, + width: json.layers[i].width, + height: json.layers[i].height, alpha: json.layers[i].opacity, visible: json.layers[i].visible, + tileMargin: json.tilesets[0].margin, - tileSpacing: json.tilesets[0].spacing + tileSpacing: json.tilesets[0].spacing, }; @@ -155,13 +164,13 @@ Phaser.TilemapParser = { if (c == json.layers[i].width) { output.push(row); - // layer.addColumn(row); c = 0; } } - layers.data = output; - this.layers.push(layer); + layer.data = output; + + layers.push(layer); } diff --git a/src/tilemap/Tileset.js b/src/tilemap/Tileset.js index 522edbdd..7b05868e 100644 --- a/src/tilemap/Tileset.js +++ b/src/tilemap/Tileset.js @@ -38,8 +38,6 @@ Phaser.Tileset.prototype = { checkTileIndex: function (index) { - console.log('checking tile', index); - return (this.tiles[index]); }