Both Static and Dynamic Tilemaps support the new property skipIndexZero which allows them to skip over index 0 tiles. Works in both canvas and webgl. Fix #3052

This commit is contained in:
Richard Davey 2017-11-03 16:52:57 +00:00
parent 954e7ef025
commit 0d38e232e6
7 changed files with 136 additions and 71 deletions

View file

@ -4,17 +4,22 @@ function Tile (properties)
this.id = properties.id; this.id = properties.id;
this.x = properties.x; this.x = properties.x;
this.y = properties.y; this.y = properties.y;
this.width = properties.width; this.width = properties.width;
this.height = properties.height; this.height = properties.height;
this.frameX = properties.frameX; this.frameX = properties.frameX;
this.frameY = properties.frameY; this.frameY = properties.frameY;
this.frameWidth = properties.frameWidth; this.frameWidth = properties.frameWidth;
this.frameHeight = properties.frameHeight; this.frameHeight = properties.frameHeight;
this.alpha = 1.0; this.alpha = 1.0;
this.tint = 0xFFFFFF; this.tint = 0xFFFFFF;
this.visible = true; this.visible = true;
this.textureWidth = properties.textureWidth; this.textureWidth = properties.textureWidth;
this.textureHeight = properties.textureHeight; this.textureHeight = properties.textureHeight;
this.border = properties.border; this.border = properties.border;
this.center = properties.center; this.center = properties.center;
} }
@ -22,18 +27,24 @@ function Tile (properties)
Tile.prototype.setId = function (id) Tile.prototype.setId = function (id)
{ {
var tileId = this.id = id; var tileId = this.id = id;
var tileWidth = this.width; var tileWidth = this.width;
var tileHeight = this.height; var tileHeight = this.height;
var setWidth = this.textureWidth / tileWidth; var setWidth = this.textureWidth / tileWidth;
var tileWidthBorder = (tileWidth + this.border * 2); var tileWidthBorder = (tileWidth + this.border * 2);
var tileHeightBorder = (tileHeight + this.border * 2); var tileHeightBorder = (tileHeight + this.border * 2);
var halfTileWidth = tileWidthBorder * 0.5; var halfTileWidth = tileWidthBorder * 0.5;
var halfTileHeight = tileHeightBorder * 0.5; var halfTileHeight = tileHeightBorder * 0.5;
if (!this.center) if (!this.center)
{ {
halfTileWidth = 0; halfTileWidth = 0;
halfTileHeight = 0; halfTileHeight = 0;
} }
var rectx = (((tileId % setWidth)|0) * tileWidthBorder) + halfTileWidth; var rectx = (((tileId % setWidth)|0) * tileWidthBorder) + halfTileWidth;
var recty = (((tileId / setWidth)|0) * tileHeightBorder) + halfTileHeight; var recty = (((tileId / setWidth)|0) * tileHeightBorder) + halfTileHeight;

View file

@ -31,18 +31,24 @@ var Tilemap = new Class({
GameObject.call(this, scene, 'Tilemap'); GameObject.call(this, scene, 'Tilemap');
this.mapData = (mapData !== null) ? new Uint32Array(mapData) : new Uint32Array(mapWidth * mapHeight); this.mapData = (mapData !== null) ? new Uint32Array(mapData) : new Uint32Array(mapWidth * mapHeight);
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.mapWidth = mapWidth; this.mapWidth = mapWidth;
this.mapHeight = mapHeight; this.mapHeight = mapHeight;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.tileArray = []; this.tileArray = [];
this.culledTiles = []; this.culledTiles = [];
this.tileBorder = tileBorder; this.tileBorder = tileBorder;
this.setTexture(texture, frame); this.setTexture(texture, frame);
this.setPosition(x, y); this.setPosition(x, y);
this.setSizeToFrame(); this.setSizeToFrame();
this.setOrigin(); this.setOrigin();
this.setSize(tileWidth * mapWidth, tileHeight * mapHeight); this.setSize(tileWidth * mapWidth, tileHeight * mapHeight);
this.skipIndexZero = false;
this.buildTilemap(!!scene.sys.game.renderer.gl); this.buildTilemap(!!scene.sys.game.renderer.gl);
}, },
@ -61,15 +67,19 @@ var Tilemap = new Class({
var tileArray = this.tileArray; var tileArray = this.tileArray;
var mapData = this.mapData; var mapData = this.mapData;
var border = this.tileBorder; var border = this.tileBorder;
var tileWidth = this.tileWidth; var tileWidth = this.tileWidth;
var tileHeight = this.tileHeight; var tileHeight = this.tileHeight;
var tileWidthBorder = tileWidth + border * 2; var tileWidthBorder = tileWidth + border * 2;
var tileHeightBorder = tileHeight + border * 2; var tileHeightBorder = tileHeight + border * 2;
var width = this.texture.source[0].width; var width = this.texture.source[0].width;
var height = this.texture.source[0].height; var height = this.texture.source[0].height;
var mapWidth = this.mapWidth; var mapWidth = this.mapWidth;
var mapHeight = this.mapHeight; var mapHeight = this.mapHeight;
var setWidth = width / tileWidth; var setWidth = width / tileWidth;
var tileWidthBorderHalf = tileWidthBorder * 0.5; var tileWidthBorderHalf = tileWidthBorder * 0.5;
var tileHeightBorderHalf = tileHeightBorder * 0.5; var tileHeightBorderHalf = tileHeightBorder * 0.5;
@ -157,7 +167,7 @@ var Tilemap = new Class({
// frameX // frameX
// frameY // frameY
// id // id
// index = the tile in the tilset to render // index = the tile in the tileset to render
// textureWidth = tileset texture size // textureWidth = tileset texture size
// textureHeight // textureHeight
// tint // tint

View file

@ -12,9 +12,11 @@ var TilemapCanvasRenderer = function (renderer, gameObject, interpolationPercent
var tiles = gameObject.culledTiles; var tiles = gameObject.culledTiles;
var tileCount = tiles.length; var tileCount = tiles.length;
var image = gameObject.frame.source.image; var image = gameObject.frame.source.image;
var scrollFactorX = gameObject.scrollFactorX;
var scrollFactorY = gameObject.scrollFactorY; // var scrollFactorX = gameObject.scrollFactorX;
var alpha = gameObject.alpha; // var scrollFactorY = gameObject.scrollFactorY;
// var alpha = gameObject.alpha;
var tx = gameObject.x - camera.scrollX * gameObject.scrollFactorX; var tx = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
var ty = gameObject.y - camera.scrollY * gameObject.scrollFactorY; var ty = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
var ctx = renderer.gameContext; var ctx = renderer.gameContext;
@ -29,6 +31,11 @@ var TilemapCanvasRenderer = function (renderer, gameObject, interpolationPercent
{ {
var tile = tiles[index]; var tile = tiles[index];
if (tile.id <= 0 && gameObject.skipIndexZero)
{
continue;
}
ctx.drawImage( ctx.drawImage(
image, image,
tile.frameX, tile.frameY, tile.frameX, tile.frameY,

View file

@ -25,6 +25,12 @@ var TilemapWebGLRenderer = function (renderer, gameObject, interpolationPercenta
for (var index = 0; index < length; ++index) for (var index = 0; index < length; ++index)
{ {
var tile = renderTiles[index]; var tile = renderTiles[index];
if (tile.id <= 0 && gameObject.skipIndexZero)
{
continue;
}
batch.addTileTextureRect( batch.addTileTextureRect(
texture, texture,
x + tile.x, y + tile.y, tile.width, tile.height, alpha * tile.alpha, tile.tint, x + tile.x, y + tile.y, tile.width, tile.height, alpha * tile.alpha, tile.tint,

View file

@ -1,8 +1,8 @@
var Class = require('../../../utils/Class'); var Class = require('../../../utils/Class');
var GameObject = require('../../GameObject');
var Components = require('../../components'); var Components = require('../../components');
var StaticTilemapRender = require('./StaticTilemapRender');
var CONST = require('../../../renderer/webgl/renderers/tilemaprenderer/const'); var CONST = require('../../../renderer/webgl/renderers/tilemaprenderer/const');
var GameObject = require('../../GameObject');
var StaticTilemapRender = require('./StaticTilemapRender');
var StaticTilemap = new Class({ var StaticTilemap = new Class({
@ -35,40 +35,43 @@ var StaticTilemap = new Class({
this.tilemapRenderer = scene.sys.game.renderer.tilemapRenderer ? scene.sys.game.renderer.tilemapRenderer : null; this.tilemapRenderer = scene.sys.game.renderer.tilemapRenderer ? scene.sys.game.renderer.tilemapRenderer : null;
this.resourceManager = this.gl ? scene.sys.game.renderer.resourceManager : null; this.resourceManager = this.gl ? scene.sys.game.renderer.resourceManager : null;
this.bufferData = null; this.bufferData = null;
this.mapData = mapData; this.mapData = mapData;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.mapWidth = mapWidth; this.mapWidth = mapWidth;
this.mapHeight = mapHeight; this.mapHeight = mapHeight;
this.tileWidth = tileWidth;
this.tileHeight = tileHeight;
this.dirty = true; this.dirty = true;
this.vertexCount = 0; this.vertexCount = 0;
this.cullStart = 0; this.cullStart = 0;
this.cullEnd = 0; this.cullEnd = 0;
this.tileBorder = tileBorder; this.tileBorder = tileBorder;
this.setTexture(texture, frame); this.setTexture(texture, frame);
this.setPosition(x, y); this.setPosition(x, y);
this.setSizeToFrame(); this.setSizeToFrame();
this.setOrigin(); this.setOrigin();
this.setSize(tileWidth * mapWidth, tileHeight * mapHeight); this.setSize(tileWidth * mapWidth, tileHeight * mapHeight);
var _this = this; this.skipIndexZero = false;
scene.sys.game.renderer.addContextRestoredCallback(function (renderer) {
_this.tileTexture = null; scene.sys.game.renderer.addContextRestoredCallback(this.contextRestore.bind(this));
_this.dirty = true; },
_this.vbo = null;
_this.gl = renderer.gl; contextRestore: function (renderer)
_this.tilemapRenderer = renderer.tilemapRenderer; {
}); this.tileTexture = null;
this.dirty = true;
this.vbo = null;
this.gl = renderer.gl;
this.tilemapRenderer = renderer.tilemapRenderer;
}, },
upload: function (camera) upload: function (camera)
{ {
if (this.gl)
{
if (this.dirty)
{
var gl = this.gl;
var vbo = this.vbo;
var mapWidth = this.mapWidth; var mapWidth = this.mapWidth;
var mapHeight = this.mapHeight; var mapHeight = this.mapHeight;
var border = this.tileBorder; var border = this.tileBorder;
@ -76,44 +79,68 @@ var StaticTilemap = new Class({
var tileHeight = this.tileHeight; var tileHeight = this.tileHeight;
var tileWidthBorder = tileWidth + border * 2; var tileWidthBorder = tileWidth + border * 2;
var tileHeightBorder = tileHeight + border * 2; var tileHeightBorder = tileHeight + border * 2;
var bufferData = this.bufferData;
var bufferF32, bufferU32;
var voffset = 0;
var vertexCount = 0;
var width = this.texture.source[0].width; var width = this.texture.source[0].width;
var height = this.texture.source[0].height; var height = this.texture.source[0].height;
var setWidth = width / tileWidth; var setWidth = width / tileWidth;
var mapData = this.mapData; var mapData = this.mapData;
var x;
var y;
if (this.gl)
{
if (this.dirty)
{
var gl = this.gl;
var vbo = this.vbo;
var bufferData = this.bufferData;
var bufferF32;
var voffset = 0;
var vertexCount = 0;
if (this.vbo === null) if (this.vbo === null)
{ {
vbo = this.resourceManager.createBuffer(gl.ARRAY_BUFFER, (4 * 6 * (mapWidth * mapHeight)) * 4, gl.STATIC_DRAW); vbo = this.resourceManager.createBuffer(gl.ARRAY_BUFFER, (4 * 6 * (mapWidth * mapHeight)) * 4, gl.STATIC_DRAW);
vbo.addAttribute(this.tilemapRenderer.shader.getAttribLocation('a_position'), 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 0); vbo.addAttribute(this.tilemapRenderer.shader.getAttribLocation('a_position'), 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 0);
vbo.addAttribute(this.tilemapRenderer.shader.getAttribLocation('a_tex_coord'), 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 8); vbo.addAttribute(this.tilemapRenderer.shader.getAttribLocation('a_tex_coord'), 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 8);
bufferData = this.bufferData = new ArrayBuffer((4 * 6 * (mapWidth * mapHeight)) * 4); bufferData = this.bufferData = new ArrayBuffer((4 * 6 * (mapWidth * mapHeight)) * 4);
this.vbo = vbo; this.vbo = vbo;
vbo.bind(); vbo.bind();
} }
bufferF32 = new Float32Array(bufferData); bufferF32 = new Float32Array(bufferData);
for (var y = 0; y < mapHeight; ++y) for (y = 0; y < mapHeight; ++y)
{ {
for (var x = 0; x < mapWidth; ++x) for (x = 0; x < mapWidth; ++x)
{ {
var tileId = mapData[y * mapWidth + x]; var tileId = mapData[y * mapWidth + x];
if (tileId <= 0 && this.skipIndexZero)
{
continue;
}
var halfTileWidth = (tileWidthBorder) * 0.5; var halfTileWidth = (tileWidthBorder) * 0.5;
var halfTileHeight = (tileHeightBorder) * 0.5; var halfTileHeight = (tileHeightBorder) * 0.5;
var rectx = (((tileId % setWidth)|0) * tileWidthBorder) + halfTileWidth; var rectx = (((tileId % setWidth)|0) * tileWidthBorder) + halfTileWidth;
var recty = (((tileId / setWidth)|0) * tileHeightBorder) + halfTileHeight; var recty = (((tileId / setWidth)|0) * tileHeightBorder) + halfTileHeight;
var tx = x * tileWidth; var tx = x * tileWidth;
var ty = y * tileHeight; var ty = y * tileHeight;
var txw = tx + tileWidth; var txw = tx + tileWidth;
var tyh = ty + tileHeight; var tyh = ty + tileHeight;
var u0 = (rectx - (halfTileWidth - 0.5)) / width; var u0 = (rectx - (halfTileWidth - 0.5)) / width;
var v0 = (recty - (halfTileHeight - 0.5)) / height; var v0 = (recty - (halfTileHeight - 0.5)) / height;
var u1 = (rectx + (halfTileWidth - 0.5)) / width; var u1 = (rectx + (halfTileWidth - 0.5)) / width;
var v1 = (recty + (halfTileHeight - 0.5)) / height; var v1 = (recty + (halfTileHeight - 0.5)) / height;
var tx0 = tx; var tx0 = tx;
var ty0 = ty; var ty0 = ty;
var tx1 = tx; var tx1 = tx;
@ -157,18 +184,24 @@ var StaticTilemap = new Class({
vertexCount += 6; vertexCount += 6;
} }
} }
this.vertexCount = vertexCount; this.vertexCount = vertexCount;
vbo.updateResource(bufferData, 0); vbo.updateResource(bufferData, 0);
this.dirty = false; this.dirty = false;
} }
this.tilemapRenderer.shader.setConstantFloat2(this.tilemapRenderer.scrollLocation, camera.scrollX, camera.scrollY);
this.tilemapRenderer.shader.setConstantFloat2(this.tilemapRenderer.scrollFactorLocation, this.scrollFactorX, this.scrollFactorY); var renderer = this.tilemapRenderer;
this.tilemapRenderer.shader.setConstantFloat2(this.tilemapRenderer.tilemapPositionLocation, this.x, this.y);
renderer.shader.setConstantFloat2(renderer.scrollLocation, camera.scrollX, camera.scrollY);
renderer.shader.setConstantFloat2(renderer.scrollFactorLocation, this.scrollFactorX, this.scrollFactorY);
renderer.shader.setConstantFloat2(renderer.tilemapPositionLocation, this.x, this.y);
var cmat = camera.matrix.matrix; var cmat = camera.matrix.matrix;
this.tilemapRenderer.shader.setConstantMatrix3x3( renderer.shader.setConstantMatrix3x3(
this.tilemapRenderer.cameraTransformLocation, renderer.cameraTransformLocation,
[ [
cmat[0], cmat[1], 0.0, cmat[0], cmat[1], 0.0,
cmat[2], cmat[3], 0.0, cmat[2], cmat[3], 0.0,
@ -178,33 +211,25 @@ var StaticTilemap = new Class({
} }
else if (this.dirty && !this.gl) else if (this.dirty && !this.gl)
{ {
var mapWidth = this.mapWidth;
var mapHeight = this.mapHeight;
var border = this.tileBorder;
var tileWidth = this.tileWidth;
var tileHeight = this.tileHeight;
var tileWidthBorder = tileWidth + border * 2;
var tileHeightBorder = tileHeight + border * 2;
var width = this.texture.source[0].width;
var height = this.texture.source[0].height;
var setWidth = width / tileWidth;
var mapData = this.mapData;
this.tiles = []; this.tiles = [];
for (var y = 0; y < mapHeight; ++y) for (y = 0; y < mapHeight; ++y)
{ {
for (var x = 0; x < mapWidth; ++x) for (x = 0; x < mapWidth; ++x)
{ {
var tileId = mapData[y * mapWidth + x]; var id = mapData[y * mapWidth + x];
var frameX = (((tileId % setWidth)|0) * tileWidthBorder);
var frameY = (((tileId / setWidth)|0) * tileHeightBorder); if (id <= 0 && this.skipIndexZero)
var tx = x * tileWidth; {
var ty = y * tileHeight; continue;
}
var frameX = (((id % setWidth) | 0) * tileWidthBorder);
var frameY = (((id / setWidth) | 0) * tileHeightBorder);
this.tiles.push({ this.tiles.push({
x: tx, x: x * tileWidth,
y: ty, y: y * tileHeight,
frameX: frameX, frameX: frameX,
frameY: frameY frameY: frameY
}); });
@ -224,6 +249,7 @@ var StaticTilemap = new Class({
getVisibleTileCount: function (camera) getVisibleTileCount: function (camera)
{ {
this.cull(camera); this.cull(camera);
return (this.cullEnd - this.cullStart) / 6; return (this.cullEnd - this.cullStart) / 6;
}, },
@ -231,8 +257,10 @@ var StaticTilemap = new Class({
{ {
this.cullStart = 0; this.cullStart = 0;
this.cullEnd = 0; this.cullEnd = 0;
var tileWidth = this.tileWidth; var tileWidth = this.tileWidth;
var tileHeight = this.tileHeight; var tileHeight = this.tileHeight;
var pixelX = this.x - (camera.scrollX * this.scrollFactorX); var pixelX = this.x - (camera.scrollX * this.scrollFactorX);
var pixelY = this.y - (camera.scrollY * this.scrollFactorY); var pixelY = this.y - (camera.scrollY * this.scrollFactorY);
var pixelWidth = this.mapWidth * tileWidth; var pixelWidth = this.mapWidth * tileWidth;
@ -245,11 +273,13 @@ var StaticTilemap = new Class({
{ {
var interX = Math.max(pixelX, camera.x + -(tileWidth * 2)); var interX = Math.max(pixelX, camera.x + -(tileWidth * 2));
var interY = Math.max(pixelY, camera.y + -(tileHeight * 2)); var interY = Math.max(pixelY, camera.y + -(tileHeight * 2));
var interWidth = Math.min(pixelX + pixelWidth, camera.x + camera.width + (tileWidth * 2)) - interX; var interWidth = Math.min(pixelX + pixelWidth, camera.x + camera.width + (tileWidth * 2)) - interX;
var interHeight = Math.min(pixelY + pixelHeight, camera.y + camera.height + (tileHeight * 2)) - interY; var interHeight = Math.min(pixelY + pixelHeight, camera.y + camera.height + (tileHeight * 2)) - interY;
interX = ((interX + (camera.scrollX * this.scrollFactorX)) / tileWidth) | 0; interX = ((interX + (camera.scrollX * this.scrollFactorX)) / tileWidth) | 0;
interY = ((interY + (camera.scrollY * this.scrollFactorY)) / tileHeight) | 0; interY = ((interY + (camera.scrollY * this.scrollFactorY)) / tileHeight) | 0;
interWidth = (interWidth / tileWidth) | 0; interWidth = (interWidth / tileWidth) | 0;
interHeight = (interHeight / tileHeight) | 0; interHeight = (interHeight / tileHeight) | 0;

View file

@ -18,7 +18,6 @@ var StaticTilemapCanvasRenderer = function (renderer, gameObject, interpolationP
var image = frame.source.image; var image = frame.source.image;
var tx = gameObject.x - camera.scrollX * gameObject.scrollFactorX; var tx = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
var ty = gameObject.y - camera.scrollY * gameObject.scrollFactorY; var ty = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
var boundsX = camera.scrollX;
ctx.save(); ctx.save();
ctx.translate(tx, ty); ctx.translate(tx, ty);
@ -29,6 +28,7 @@ var StaticTilemapCanvasRenderer = function (renderer, gameObject, interpolationP
for (var index = 0; index < tileCount; ++index) for (var index = 0; index < tileCount; ++index)
{ {
var tile = tiles[index]; var tile = tiles[index];
ctx.drawImage(image, tile.frameX, tile.frameY, tileWidth, tileHeight, tile.x, tile.y, tileWidth, tileHeight); ctx.drawImage(image, tile.frameX, tile.frameY, tileWidth, tileHeight, tile.x, tile.y, tileWidth, tileHeight);
} }

View file

@ -12,6 +12,7 @@ var StaticTilemapWebGLRenderer = function (renderer, src, interpolationPercentag
var gl = gameObject.gl; var gl = gameObject.gl;
renderer.setRenderer(gameObject.tilemapRenderer, frame.texture.source[frame.sourceIndex].glTexture, gameObject.renderTarget); renderer.setRenderer(gameObject.tilemapRenderer, frame.texture.source[frame.sourceIndex].glTexture, gameObject.renderTarget);
gameObject.tilemapRenderer.bind(); gameObject.tilemapRenderer.bind();
gameObject.upload(camera); gameObject.upload(camera);
gameObject.vbo.bind(); gameObject.vbo.bind();