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

View file

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

View file

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

View file

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

View file

@ -18,7 +18,6 @@ var StaticTilemapCanvasRenderer = function (renderer, gameObject, interpolationP
var image = frame.source.image;
var tx = gameObject.x - camera.scrollX * gameObject.scrollFactorX;
var ty = gameObject.y - camera.scrollY * gameObject.scrollFactorY;
var boundsX = camera.scrollX;
ctx.save();
ctx.translate(tx, ty);
@ -29,6 +28,7 @@ var StaticTilemapCanvasRenderer = function (renderer, gameObject, interpolationP
for (var index = 0; index < tileCount; ++index)
{
var tile = tiles[index];
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;
renderer.setRenderer(gameObject.tilemapRenderer, frame.texture.source[frame.sourceIndex].glTexture, gameObject.renderTarget);
gameObject.tilemapRenderer.bind();
gameObject.upload(camera);
gameObject.vbo.bind();