Completely empty Tilemaps can now be created. This allows for dynamic map generation at runtime.

Loads of updates across most the Tilemap files. Not finished yet, still CSV loading to do and a multi-tileset issue to resolve, but it's a lot more flexible now.
This commit is contained in:
photonstorm
2014-03-03 05:19:46 +00:00
parent 6f513042c1
commit d8f5832fa2
12 changed files with 396 additions and 85 deletions
+1
View File
@@ -160,6 +160,7 @@ Updates:
* ScaleManager has 2 new events: ScaleManager.enterFullScreen and ScaleManager.leaveFullScreen, so you can respond to fullscreen changes directly.
* RandomDataGenerator.integerInRange(min, max) now includes both `min` and `max` within its range (#501)
* Tween no longer copies all the object properties into the `_valuesStart` object on creation.
* Completely empty Tilemaps can now be created. This allows for dynamic map generation at runtime.
Bug Fixes:
+22 -2
View File
@@ -13,6 +13,7 @@ var layer;
var marker;
var currentTile;
var cursors;
function create() {
@@ -30,6 +31,8 @@ function create() {
marker.lineStyle(2, 0x000000, 1);
marker.drawRect(0, 0, 32, 32);
cursors = game.input.keyboard.createCursorKeys();
}
function update() {
@@ -52,11 +55,28 @@ 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() {
game.debug.text('Left-click to paint. Shift + Left-click to select tile.', 32, 32, 'rgb(0,0,0)');
game.debug.text('Tile: ' + map.getTile(layer.getTileX(marker.x), layer.getTileY(marker.y)), 32, 48, 'rgb(0,0,0)');
game.debug.text('Left-click to paint. Shift + Left-click to select tile. Arrows to scroll.', 32, 32, '#efefef');
}
+68
View File
@@ -0,0 +1,68 @@
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.image('ground_1x1', 'assets/tilemaps/tiles/ground_1x1.png');
}
var map;
var tileset;
var layer;
var cursors;
function create() {
game.stage.backgroundColor = '#787878';
// Creates a blank tilemap
map = game.add.tilemap();
// Creates a layer and sets-up the map dimensions.
// In this case the map is 30x30 tiles in size and the tiles are 32x32 pixels in size.
map.create('level1', 30, 30, 32, 32);
// Add a Tileset image to the map
map.addTilesetImage('ground_1x1');
map.putTile(4, 1, 1)
map.putTile(10, 2, 1)
map.putTile(10, 3, 1)
map.putTile(10, 4, 1)
// Create a layer. This is where the map is rendered to.
layer = map.createLayer('level1');
// layer.resizeWorld();
// map.setCollisionBetween(1, 12);
// layer.debug = true;
cursors = game.input.keyboard.createCursorKeys();
}
function update() {
if (cursors.left.isDown)
{
}
else if (cursors.right.isDown)
{
}
if (cursors.up.isDown)
{
}
else if (cursors.down.isDown)
{
}
}
function render() {
game.debug.cameraInfo(game.camera, 32, 32);
}
+39
View File
@@ -0,0 +1,39 @@
var game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', { preload: preload, create: create, update: update, render: render });
function preload() {
game.load.spritesheet('mummy', 'assets/sprites/metalslug_mummy37x45.png', 37, 45, 18);
}
var mummy;
function create() {
game.stage.backgroundColor = 0x3d4d3d;
mummy = game.add.sprite(300, 300, 'mummy', 5);
var t = game.add.tween(mummy).to( { "x": 400, "y": 400 }, 5000, Phaser.Easing.Linear.None, true);
// var t = game.add.tween(mummy).to( { "scale.x": 4, "scale.y": 4 }, 5000, Phaser.Easing.Linear.None, true);
t.onComplete.add(tweenOver, this);
}
function tweenOver(a) {
console.log('over');
console.log(a);
}
function update() {
}
function render() {
}
+3 -4
View File
@@ -273,13 +273,12 @@ Phaser.GameObjectCreator.prototype = {
* Creates a new Tilemap object.
*
* @method Phaser.GameObjectCreator#tilemap
* @param {string} key - Asset key for the JSON or CSV map data in the cache.
* @param {object|string} tilesets - An object mapping Cache.tileset keys with the tileset names in the JSON file. If a string is provided that will be used.
* @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.
*/
tilemap: function (key, tilesets) {
tilemap: function (key) {
return new Phaser.Tilemap(this.game, key, tilesets);
return new Phaser.Tilemap(this.game, key);
},
+3 -4
View File
@@ -304,13 +304,12 @@ Phaser.GameObjectFactory.prototype = {
* Creates a new Tilemap object.
*
* @method Phaser.GameObjectFactory#tilemap
* @param {string} key - Asset key for the JSON or CSV map data in the cache.
* @param {object|string} tilesets - An object mapping Cache.tileset keys with the tileset names in the JSON file. If a string is provided that will be used.
* @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.
*/
tilemap: function (key, tilesets) {
tilemap: function (key) {
return new Phaser.Tilemap(this.game, key, tilesets);
return new Phaser.Tilemap(this.game, key);
},
+4 -1
View File
@@ -367,7 +367,10 @@ Phaser.Physics.World.prototype = {
if (this.bounds !== null)
{
this.world.removeBody(this.bounds);
if (this.bounds.world)
{
this.world.removeBody(this.bounds);
}
var i = this.bounds.shapes.length;
+69 -16
View File
@@ -11,7 +11,7 @@
* @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.
* @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.
*/
Phaser.Tilemap = function (game, key) {
@@ -155,37 +155,52 @@ Phaser.Tilemap.prototype = {
* Creates an empty map of the given dimensions.
*
* @method Phaser.Tilemap#create
* @param {string} name - The name of the map (mostly used for debugging)
* @param {string} name - The name of the default layer of the map
* @param {number} width - The width of the map in tiles.
* @param {number} height - The height of the map in tiles.
* @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.
*/
create: function (name, width, height) {
create: function (name, width, height, tileWidth, tileHeight) {
var data = [];
this.width = width;
this.height = height;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.widthInPixels = width * tileWidth;
this.heightInPixels = height * tileHeight;
var row;
var output = [];
for (var y = 0; y < height; y++)
{
data[y] = [];
row = [];
for (var x = 0; x < width; x++)
{
data[y][x] = 0;
row.push(null);
}
output.push(row);
}
this.layers.push({
name: name,
x: 0,
y: 0,
width: width,
height: height,
widthInPixels: this.widthInPixels,
heightInPixels: this.heightInPixels,
alpha: 1,
visible: true,
tileMargin: 0,
tileSpacing: 0,
format: Phaser.Tilemap.CSV,
data: data,
properties: {},
indexes: [],
dirty: true
callbacks: [],
bodies: [],
data: output
});
@@ -200,8 +215,17 @@ Phaser.Tilemap.prototype = {
* @method Phaser.Tilemap#addTilesetImage
* @param {string} tileset - The name of the tileset as specified in the map data.
* @param {string} [key] - The key of the Phaser.Cache image used for this tileset. If not specified it will look for an image with a key matching the tileset parameter.
* @param {number} [tileWidth] - The width of the tiles in the Tileset Image. If not given it will default to the map.tileWidth value.
* @param {number} [tileHeight] - The height of the tiles in the Tileset Image. If not given it will default to the map.tileHeight value.
* @param {number} [tileMargin=0] - The width of the tiles in the Tileset Image. If not given it will default to the map.tileWidth value.
* @param {number} [tileSpacing=0] - The height of the tiles in the Tileset Image. If not given it will default to the map.tileHeight value.
*/
addTilesetImage: function (tileset, key) {
addTilesetImage: function (tileset, key, tileWidth, tileHeight, tileMargin, tileSpacing) {
if (typeof tileWidth === 'undefined') { tileWidth = this.tileWidth; }
if (typeof tileHeight === 'undefined') { tileHeight = this.tileHeight; }
if (typeof tileMargin === 'undefined') { tileMargin = 0; }
if (typeof tileSpacing === 'undefined') { tileSpacing = 0; }
if (typeof key === 'undefined')
{
@@ -222,10 +246,17 @@ Phaser.Tilemap.prototype = {
if (this.tilesets[tileset])
{
this.tilesets[tileset].image = this.game.cache.getImage(key);
this.tilesets[tileset].setImage(this.game.cache.getImage(key));
return true;
}
else
{
var newSet = new Phaser.Tileset(key, 0, tileWidth, tileHeight, tileMargin, tileSpacing, {});
newSet.setImage(this.game.cache.getImage(key));
this.tilesets.push(newSet);
}
return false;
@@ -920,6 +951,12 @@ Phaser.Tilemap.prototype = {
},
hasTile: function (x, y, layer) {
return (this.layers[layer].data[y] !== null && this.layers[layer].data[y][x] !== null);
},
/**
* Puts a tile of the given index value at the coordinate specified.
*
@@ -937,14 +974,30 @@ Phaser.Tilemap.prototype = {
{
if (tile instanceof Phaser.Tile)
{
this.layers[layer].data[y][x].copy(tile);
if (this.hasTile(x, y, layer))
{
this.layers[layer].data[y][x].copy(tile);
}
else
{
//Phaser.Tile = function (layer, index, x, y, width, height) {
this.layers[layer].data[y][x] = new Phaser.Tile(layer, tile.index, x, y, tile.width, tile.height);
}
}
else
{
this.layers[layer].data[y][x].index = tile;
if (this.hasTile(x, y, layer))
{
this.layers[layer].data[y][x].index = tile;
}
else
{
this.layers[layer].data[y][x] = new Phaser.Tile(layer, tile, x, y, this.tileWidth, this.tileHeight);
}
}
this.layers[layer].dirty = true;
this.calculateFaces(layer);
}
+106 -8
View File
@@ -62,7 +62,8 @@ Phaser.TilemapLayer = function (game, tilemap, index, width, height) {
*/
this.textureFrame = new Phaser.Frame(0, 0, 0, width, height, 'tilemapLayer', game.rnd.uuid());
Phaser.Sprite.call(this, this.game, 0, 0, this.texture, this.textureFrame);
// Phaser.Sprite.call(this, this.game, 0, 0, this.texture, this.textureFrame);
Phaser.Image.call(this, this.game, 0, 0, this.texture, this.textureFrame);
/**
* @property {string} name - The name of the layer.
@@ -280,8 +281,8 @@ Phaser.TilemapLayer = function (game, tilemap, index, width, height) {
};
Phaser.TilemapLayer.prototype = Object.create(Phaser.Sprite.prototype);
Phaser.TilemapLayer.prototype = Phaser.Utils.extend(true, Phaser.TilemapLayer.prototype, Phaser.Sprite.prototype, PIXI.Sprite.prototype);
Phaser.TilemapLayer.prototype = Object.create(Phaser.Image.prototype);
// Phaser.TilemapLayer.prototype = Phaser.Utils.extend(true, Phaser.TilemapLayer.prototype, Phaser.Sprite.prototype, PIXI.Sprite.prototype);
Phaser.TilemapLayer.prototype.constructor = Phaser.TilemapLayer;
/**
@@ -292,7 +293,8 @@ Phaser.TilemapLayer.prototype.constructor = Phaser.TilemapLayer;
*/
Phaser.TilemapLayer.prototype.postUpdate = function () {
Phaser.Sprite.prototype.postUpdate.call(this);
// Phaser.Sprite.prototype.postUpdate.call(this);
Phaser.Image.prototype.postUpdate.call(this);
// Stops you being able to auto-scroll the camera if it's not following a sprite
this.scrollX = this.game.camera.x * this.scrollFactorX;
@@ -554,7 +556,7 @@ Phaser.TilemapLayer.prototype.updateMax = function () {
*/
Phaser.TilemapLayer.prototype.render = function () {
if (this.layer.dirty)
if (this.layer.dirty)
{
this.dirty = true;
}
@@ -587,6 +589,102 @@ Phaser.TilemapLayer.prototype.render = function () {
this.context.globalAlpha = this.debugAlpha;
}
for (var y = this._startY, lenY = this._startY + this._maxY; y < lenY; y++)
{
this._column = this.layer.data[y];
for (var x = this._startX, lenX = this._startX + this._maxX; x < lenX; x++)
{
if (this._column[x])
{
tile = this._column[x];
// this needs to know which set the index is from
// set = this.map.tilesets[this.map.tiles[tile.index][2]]
set = this.map.tilesets[0];
if (this.debug === false && tile.alpha !== this.context.globalAlpha)
{
this.context.globalAlpha = tile.alpha;
}
set.draw(this.context, Math.floor(this._tx), Math.floor(this._ty), tile.index);
if (tile.debug)
{
this.context.fillStyle = 'rgba(0, 255, 0, 0.4)';
this.context.fillRect(Math.floor(this._tx), Math.floor(this._ty), this.map.tileWidth, this.map.tileHeight);
}
}
this._tx += this.map.tileWidth;
}
this._tx = this._dx;
this._ty += this.map.tileHeight;
}
if (this.debug)
{
this.context.globalAlpha = 1;
this.renderDebug();
}
if (this.game.renderType === Phaser.WEBGL)
{
// PIXI.updateWebGLTexture(this.baseTexture, renderSession.gl);
PIXI.updateWebGLTexture(this.baseTexture, this.game.renderer.gl);
}
this.dirty = false;
this.layer.dirty = false;
return true;
}
/**
* Renders the tiles to the layer canvas and pushes to the display.
* @method Phaser.TilemapLayer#render
* @memberof Phaser.TilemapLayer
*/
Phaser.TilemapLayer.prototype.OLDrender = function () {
if (this.layer.dirty)
{
this.dirty = true;
}
if (!this.dirty || !this.visible)
{
// return;
}
this._prevX = this._dx;
this._prevY = this._dy;
this._dx = -(this._x - (this._startX * this.map.tileWidth));
this._dy = -(this._y - (this._startY * this.map.tileHeight));
this._tx = this._dx;
this._ty = this._dy;
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.fillStyle = this.tileColor;
var tile;
var set;
var ox = 0;
var oy = 0;
if (this.debug)
{
this.context.globalAlpha = this.debugAlpha;
}
for (var y = this._startY, lenY = this._startY + this._maxY; y < lenY; y++)
{
this._column = this.layer.data[y];
@@ -638,11 +736,11 @@ Phaser.TilemapLayer.prototype.render = function () {
);
}
if (tile.debug)
{
// if (tile.debug)
// {
this.context.fillStyle = 'rgba(0, 255, 0, 0.4)';
this.context.fillRect(Math.floor(this._tx), Math.floor(this._ty), this.map.tileWidth, this.map.tileHeight);
}
// }
}
else
{
+6 -1
View File
@@ -74,6 +74,11 @@ Phaser.TilemapParser = {
*/
parse: function (game, key) {
if (typeof key === 'undefined')
{
return this.getEmptyData();
}
var map = game.cache.getTilemapData(key);
if (map)
@@ -89,7 +94,7 @@ Phaser.TilemapParser = {
}
else
{
return this.getEmptyData();
console.warn('Phaser.TilemapParser.parse - No map data found for key ' + key);
}
},
+65 -49
View File
@@ -11,7 +11,7 @@
* @class Phaser.Tileset
* @constructor
* @param {string} name - The name of the tileset in the map data.
* @param {number} firstgid - The Tiled firstgid value.
* @param {number} firstgid - The Tiled firstgid value. In non-Tiled data this should be considered the starting index value of the first tile in this set.
* @param {number} width - Width of each tile in pixels.
* @param {number} height - Height of each tile in pixels.
* @param {number} margin - The amount of margin around the tilesheet.
@@ -26,8 +26,7 @@ Phaser.Tileset = function (name, firstgid, width, height, margin, spacing, prope
this.name = name;
/**
* @property {number} firstgid - The Tiled firstgid value.
* @default
* @property {number} firstgid - The Tiled firstgid value. In non-Tiled data this should be considered the starting index value of the first tile in this set.
*/
this.firstgid = firstgid;
@@ -42,12 +41,12 @@ Phaser.Tileset = function (name, firstgid, width, height, margin, spacing, prope
this.tileHeight = height;
/**
* @property {number} tileMargin - The margin around the tiles in the sheet.
* @property {number} tileMargin - The margin around the tiles in the tileset.
*/
this.tileMargin = margin;
/**
* @property {number} tileSpacing - The margin around the tiles in the sheet.
* @property {number} tileSpacing - The spacing in pixels between each tile in the tileset.
*/
this.tileSpacing = spacing;
@@ -56,11 +55,6 @@ Phaser.Tileset = function (name, firstgid, width, height, margin, spacing, prope
*/
this.properties = properties;
/**
* @property {object} tilePproperties - Tile specific properties (typically defined in the Tiled editor).
*/
// this.tileProperties = {};
/**
* @property {object} image - The image used for rendering. This is a reference to the image stored in Phaser.Cache.
*/
@@ -81,48 +75,81 @@ Phaser.Tileset = function (name, firstgid, width, height, margin, spacing, prope
*/
this.total = 0;
/**
* @property {array} draw - The tile drawImage look-up table
* @private
*/
this.drawCoords = [];
};
Phaser.Tileset.prototype = {
/**
* Gets a Tile from this set.
* Draws a tile from this Tileset at the given coordinates on the context.
*
* @method Phaser.Tileset#getTile
* @param {number} index - The index of the tile within the set.
* @return {object} The tile object.
getTile: function (index) {
* @method Phaser.Tileset#draw
* @param {HTMLCanvasContext} context - The context to draw the tile onto.
* @param {number} x - The x coordinate to draw to.
* @param {number} y - The y coordinate to draw to.
* @param {number} index - The index of the tile within the set to draw.
*/
draw: function (context, x, y, index) {
return this.tiles[index];
if (!this.image || !this.drawCoords[index])
{
return;
}
context.drawImage(
this.image,
this.drawCoords[index][0],
this.drawCoords[index][1],
this.tileWidth,
this.tileHeight,
x,
y,
this.tileWidth,
this.tileHeight
);
},
*/
/**
* Gets a Tile from this set.
* Adds a reference from this Tileset to an Image stored in the Phaser.Cache.
*
* @method Phaser.Tileset#getTileX
* @param {number} index - The index of the tile within the set.
* @return {object} The tile object.
getTileX: function (index) {
* @method Phaser.Tileset#setImage
* @param {Image} image - The image this tileset will use to draw with.
*/
setImage: function (image) {
return this.tiles[index][0];
this.image = image;
this.rows = Math.round((image.height - this.tileMargin) / (this.tileHeight + this.tileSpacing));
this.columns = Math.round((image.width - this.tileMargin) / (this.tileWidth + this.tileSpacing));
this.total = this.rows * this.columns;
// Create the index look-up
this.drawCoords.length = 0;
var tx = this.tileMargin;
var ty = this.tileMargin;
var i = this.firstgid;
for (var y = 0; y < this.rows; y++)
{
for (var x = 0; x < this.columns; x++)
{
this.drawCoords[i] = [ tx, ty ];
tx += this.tileWidth + this.tileSpacing;
i++;
}
tx = this.tileMargin;
ty += this.tileHeight + this.tileSpacing;
}
},
*/
/**
* Gets a Tile from this set.
*
* @method Phaser.Tileset#getTileY
* @param {number} index - The index of the tile within the set.
* @return {object} The tile object.
getTileY: function (index) {
return this.tiles[index][1];
},
*/
/**
* Sets tile spacing and margins.
@@ -136,20 +163,9 @@ Phaser.Tileset.prototype = {
this.tileMargin = margin;
this.tileSpacing = spacing;
},
/**
* Checks if the tile at the given index exists.
*
* @method Phaser.Tileset#checkTileIndex
* @param {number} index - The index of the tile within the set.
* @return {boolean} True if a tile exists at the given index otherwise false.
checkTileIndex: function (index) {
return (this.tiles[index]);
this.setImage(this.image);
}
*/
};
+10
View File
@@ -90,6 +90,11 @@ Phaser.Utils.Debug = function (game) {
*/
this.currentAlpha = 1;
/**
* @property {boolean} dirty - Does the canvas need re-rendering?
*/
this.dirty = false;
};
Phaser.Utils.Debug.prototype = {
@@ -142,6 +147,11 @@ Phaser.Utils.Debug.prototype = {
this.currentAlpha = this.context.globalAlpha;
this.columnWidth = columnWidth;
if (this.sprite && this.dirty)
{
// this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
this.context.save();
this.context.setTransform(1, 0, 0, 1, 0, 0);
this.context.strokeStyle = color;