From 0201baef112b16111a107e7a7746d1815ba59c42 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Fri, 11 Oct 2013 18:18:27 +0100 Subject: [PATCH] And Tilemaps are rendering again - and much better than ever before :) Just one final optimisation pass to do and then it's on to collision. --- Docs/Screen Shots/phaser_tilemap_debug.png | Bin 0 -> 93528 bytes .../maps/{cybernoid.png.png => cybernoid.png} | Bin examples/tilemaps/wip1.php | 75 ++++--- src/gameobjects/Sprite.js | 6 + src/loader/Cache.js | 8 +- src/loader/Loader.js | 4 +- src/tilemap/Tilemap.js | 135 +++++++++++- src/tilemap/TilemapLayer.js | 194 +++++++++--------- src/tilemap/TilemapParser.js | 25 ++- src/tilemap/Tileset.js | 2 - 10 files changed, 304 insertions(+), 145 deletions(-) create mode 100644 Docs/Screen Shots/phaser_tilemap_debug.png rename examples/assets/maps/{cybernoid.png.png => cybernoid.png} (100%) diff --git a/Docs/Screen Shots/phaser_tilemap_debug.png b/Docs/Screen Shots/phaser_tilemap_debug.png new file mode 100644 index 0000000000000000000000000000000000000000..392022cebb65cf1dd9ebd7f1841354fd78ac97e7 GIT binary patch literal 93528 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 Ndb;|#taD0e0stPvvPb{` literal 0 HcmV?d00001 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]); }