Phaser.TilemapLayer = function (game, tilemap, index, width, height){ width |= 0; height |= 0; Phaser.Sprite.call(this, game, 0, 0); this.map = tilemap; this.index = index; this.layer = tilemap.layers[index]; this.canvas = PIXI.CanvasPool.create(this, width, height); this.context = this.canvas.getContext('2d'); this.setTexture(new PIXI.Texture(new PIXI.BaseTexture(this.canvas))); this.type = Phaser.TILEMAPLAYER; this.physicsType = Phaser.TILEMAPLAYER; this.renderSettings = { enableScrollDelta: false , overdrawRatio: 0.2, copyCanvas: null } ; this.debug = false ; this.exists = true ; this.debugSettings = { missingImageFill: 'rgb(255,255,255)', debuggedTileOverfill: 'rgba(0,255,0,0.4)', forceFullRedraw: true , debugAlpha: 0.5, facingEdgeStroke: 'rgba(0,255,0,1)', collidingTileOverfill: 'rgba(0,255,0,0.2)'} ; this.scrollFactorX = 1; this.scrollFactorY = 1; this.dirty = true ; this.rayStepRate = 4; this._wrap = false ; this._mc = { scrollX: 0, scrollY: 0, renderWidth: 0, renderHeight: 0, tileWidth: tilemap.tileWidth, tileHeight: tilemap.tileHeight, cw: tilemap.tileWidth, ch: tilemap.tileHeight, tilesets: [] } ; this._scrollX = 0; this._scrollY = 0; this._results = [] ; if (!game.device.canvasBitBltShift) { this.renderSettings.copyCanvas = Phaser.TilemapLayer.ensureSharedCopyCanvas(); } this.fixedToCamera = true ; } ; Phaser.TilemapLayer.prototype = Object.create(Phaser.Sprite.prototype); Phaser.TilemapLayer.prototype.constructor = Phaser.TilemapLayer; Phaser.TilemapLayer.prototype.preUpdateCore = Phaser.Component.Core.preUpdate; Phaser.TilemapLayer.sharedCopyCanvas = null ; Phaser.TilemapLayer.ensureSharedCopyCanvas = function (){ if (!this.sharedCopyCanvas) { this.sharedCopyCanvas = Phaser.Canvas.create(2, 2); } return this.sharedCopyCanvas; } ; Phaser.TilemapLayer.prototype.preUpdate = function (){ return this.preUpdateCore(); } ; Phaser.TilemapLayer.prototype.postUpdate = function (){ Phaser.Component.FixedToCamera.postUpdate.call(this); var camera = this.game.camera; this.scrollX = camera.x * this.scrollFactorX / this.scale.x; this.scrollY = camera.y * this.scrollFactorY / this.scale.y; this.render(); } ; Phaser.TilemapLayer.prototype.destroy = function (){ PIXI.CanvasPool.remove(this); Phaser.Component.Destroy.prototype.destroy.call(this); } ; Phaser.TilemapLayer.prototype.resize = function (width, height){ this.canvas.width = width; this.canvas.height = height; this.texture.frame.resize(width, height); this.texture.width = width; this.texture.height = height; this.texture.crop.width = width; this.texture.crop.height = height; this.texture.baseTexture.width = width; this.texture.baseTexture.height = height; this.texture.baseTexture.dirty(); this.texture.requiresUpdate = true ; this.texture._updateUvs(); this.dirty = true ; } ; Phaser.TilemapLayer.prototype.resizeWorld = function (){ this.game.world.setBounds(0, 0, this.layer.widthInPixels * this.scale.x, this.layer.heightInPixels * this.scale.y); } ; Phaser.TilemapLayer.prototype._fixX = function (x){ if (x < 0) { x = 0; } if (this.scrollFactorX === 1) { return x; } return this._scrollX + (x - (this._scrollX / this.scrollFactorX)); } ; Phaser.TilemapLayer.prototype._unfixX = function (x){ if (this.scrollFactorX === 1) { return x; } return (this._scrollX / this.scrollFactorX) + (x - this._scrollX); } ; Phaser.TilemapLayer.prototype._fixY = function (y){ if (y < 0) { y = 0; } if (this.scrollFactorY === 1) { return y; } return this._scrollY + (y - (this._scrollY / this.scrollFactorY)); } ; Phaser.TilemapLayer.prototype._unfixY = function (y){ if (this.scrollFactorY === 1) { return y; } return (this._scrollY / this.scrollFactorY) + (y - this._scrollY); } ; Phaser.TilemapLayer.prototype.getTileX = function (x){ return Math.floor(this._fixX(x) / this._mc.tileWidth); } ; Phaser.TilemapLayer.prototype.getTileY = function (y){ return Math.floor(this._fixY(y) / this._mc.tileHeight); } ; Phaser.TilemapLayer.prototype.getTileXY = function (x, y, point){ point.x = this.getTileX(x); point.y = this.getTileY(y); return point; } ; Phaser.TilemapLayer.prototype.getRayCastTiles = function (line, stepRate, collides, interestingFace){ if (!stepRate) { stepRate = this.rayStepRate; } if (collides === undefined) { collides = false ; } if (interestingFace === undefined) { interestingFace = false ; } var tiles = this.getTiles(line.x, line.y, line.width, line.height, collides, interestingFace); if (_AN_Read_length('length', tiles) === 0) { return [] ; } var coords = line.coordinatesOnLine(stepRate); var results = [] ; for (var i = 0; i < _AN_Read_length('length', tiles); i++ ){ for (var t = 0; t < _AN_Read_length('length', coords); t++ ){ var tile = tiles[i]; var coord = coords[t]; if (tile.containsPoint(coord[0], coord[1])) { results.push(tile); break ; } } } return results; } ; Phaser.TilemapLayer.prototype.getTiles = function (x, y, width, height, collides, interestingFace){ if (collides === undefined) { collides = false ; } if (interestingFace === undefined) { interestingFace = false ; } var fetchAll = !(collides || interestingFace); x = this._fixX(x); y = this._fixY(y); var tx = Math.floor(x / (this._mc.cw * this.scale.x)); var ty = Math.floor(y / (this._mc.ch * this.scale.y)); var tw = Math.ceil((x + width) / (this._mc.cw * this.scale.x)) - tx; var th = Math.ceil((y + height) / (this._mc.ch * this.scale.y)) - ty; while (this._results.length){ this._results.pop(); } for (var wy = ty; wy < ty + th; wy++ ){ for (var wx = tx; wx < tx + tw; wx++ ){ var row = this.layer.data[wy]; if (row && row[wx]) { if (fetchAll || row[wx].isInteresting(collides, interestingFace)) { this._results.push(row[wx]); } } } } return this._results.slice(); } ; Phaser.TilemapLayer.prototype.resolveTileset = function (tileIndex){ var tilesets = this._mc.tilesets; if (tileIndex < 2000) { while (_AN_Read_length('length', tilesets) < tileIndex){ tilesets.push(undefined); } } var setIndex = this.map.tiles[tileIndex] && this.map.tiles[tileIndex][2]; if (setIndex != null ) { var tileset = this.map.tilesets[setIndex]; if (tileset && tileset.containsTileIndex(tileIndex)) { return (tilesets[tileIndex] = tileset); } } return (tilesets[tileIndex] = null ); } ; Phaser.TilemapLayer.prototype.resetTilesetCache = function (){ var tilesets = this._mc.tilesets; while (tilesets.length){ tilesets.pop(); } } ; Phaser.TilemapLayer.prototype.setScale = function (xScale, yScale){ xScale = xScale || 1; yScale = yScale || xScale; for (var y = 0; y < _AN_Read_length('length', this.layer.data); y++ ){ var row = this.layer.data[y]; for (var x = 0; x < _AN_Read_length('length', row); x++ ){ var tile = row[x]; tile.width = this.map.tileWidth * xScale; tile.height = this.map.tileHeight * yScale; tile.worldX = tile.x * tile.width; tile.worldY = tile.y * tile.height; } } this.scale.setTo(xScale, yScale); } ; Phaser.TilemapLayer.prototype.shiftCanvas = function (context, x, y){ var canvas = context.canvas; var copyW = canvas.width - Math.abs(x); var copyH = canvas.height - Math.abs(y); var dx = 0; var dy = 0; var sx = x; var sy = y; if (x < 0) { dx = - x; sx = 0; } if (y < 0) { dy = - y; sy = 0; } var copyCanvas = this.renderSettings.copyCanvas; if (copyCanvas) { if (copyCanvas.width < copyW || copyCanvas.height < copyH) { copyCanvas.width = copyW; copyCanvas.height = copyH; } var copyContext = copyCanvas.getContext('2d'); copyContext.clearRect(0, 0, copyW, copyH); copyContext.drawImage(canvas, dx, dy, copyW, copyH, 0, 0, copyW, copyH); context.clearRect(sx, sy, copyW, copyH); context.drawImage(copyCanvas, 0, 0, copyW, copyH, sx, sy, copyW, copyH); } else { context.save(); context.globalCompositeOperation = 'copy'; context.drawImage(canvas, dx, dy, copyW, copyH, sx, sy, copyW, copyH); context.restore(); } } ; Phaser.TilemapLayer.prototype.renderRegion = function (scrollX, scrollY, left, top, right, bottom){ var context = this.context; var width = this.layer.width; var height = this.layer.height; var tw = this._mc.tileWidth; var th = this._mc.tileHeight; var tilesets = this._mc.tilesets; var lastAlpha = NaN; if (!this._wrap) { if (left <= right) { left = Math.max(0, left); right = Math.min(width - 1, right); } if (top <= bottom) { top = Math.max(0, top); bottom = Math.min(height - 1, bottom); } } var baseX = (left * tw) - scrollX; var baseY = (top * th) - scrollY; var normStartX = (left + ((1 << 20) * width)) % width; var normStartY = (top + ((1 << 20) * height)) % height; var tx, ty, x, y, xmax, ymax; context.fillStyle = this.tileColor; for (y = normStartY, ymax = bottom - top, ty = baseY; ymax >= 0; y++ , ymax-- , ty += th){ if (y >= height) { y -= height; } var row = this.layer.data[y]; for (x = normStartX, xmax = right - left, tx = baseX; xmax >= 0; x++ , xmax-- , tx += tw){ if (x >= width) { x -= width; } var tile = row[x]; if (!tile || tile.index < 0) { continue ; } var index = tile.index; var set = tilesets[index]; if (set === undefined) { set = this.resolveTileset(index); } if (tile.alpha !== lastAlpha && !this.debug) { context.globalAlpha = tile.alpha; lastAlpha = tile.alpha; } if (set) { if (tile.rotation || tile.flipped) { context.save(); context.translate(tx + tile.centerX, ty + tile.centerY); context.rotate(tile.rotation); if (tile.flipped) { context.scale(-1, 1); } set.draw(context, - tile.centerX, - tile.centerY, index); context.restore(); } else { set.draw(context, tx, ty, index); } } else if (this.debugSettings.missingImageFill) { context.fillStyle = this.debugSettings.missingImageFill; context.fillRect(tx, ty, tw, th); } if (tile.debug && this.debugSettings.debuggedTileOverfill) { context.fillStyle = this.debugSettings.debuggedTileOverfill; context.fillRect(tx, ty, tw, th); } } } } ; Phaser.TilemapLayer.prototype.renderDeltaScroll = function (shiftX, shiftY){ var scrollX = this._mc.scrollX; var scrollY = this._mc.scrollY; var renderW = this.canvas.width; var renderH = this.canvas.height; var tw = this._mc.tileWidth; var th = this._mc.tileHeight; var left = 0; var right = - tw; var top = 0; var bottom = - th; if (shiftX < 0) { left = renderW + shiftX; right = renderW - 1; } else if (shiftX > 0) { right = shiftX; } if (shiftY < 0) { top = renderH + shiftY; bottom = renderH - 1; } else if (shiftY > 0) { bottom = shiftY; } this.shiftCanvas(this.context, shiftX, shiftY); left = Math.floor((left + scrollX) / tw); right = Math.floor((right + scrollX) / tw); top = Math.floor((top + scrollY) / th); bottom = Math.floor((bottom + scrollY) / th); if (left <= right) { this.context.clearRect(((left * tw) - scrollX), 0, (right - left + 1) * tw, renderH); var trueTop = Math.floor((0 + scrollY) / th); var trueBottom = Math.floor((renderH - 1 + scrollY) / th); this.renderRegion(scrollX, scrollY, left, trueTop, right, trueBottom); } if (top <= bottom) { this.context.clearRect(0, ((top * th) - scrollY), renderW, (bottom - top + 1) * th); var trueLeft = Math.floor((0 + scrollX) / tw); var trueRight = Math.floor((renderW - 1 + scrollX) / tw); this.renderRegion(scrollX, scrollY, trueLeft, top, trueRight, bottom); } } ; Phaser.TilemapLayer.prototype.renderFull = function (){ var scrollX = this._mc.scrollX; var scrollY = this._mc.scrollY; var renderW = this.canvas.width; var renderH = this.canvas.height; var tw = this._mc.tileWidth; var th = this._mc.tileHeight; var left = Math.floor(scrollX / tw); var right = Math.floor((renderW - 1 + scrollX) / tw); var top = Math.floor(scrollY / th); var bottom = Math.floor((renderH - 1 + scrollY) / th); this.context.clearRect(0, 0, renderW, renderH); this.renderRegion(scrollX, scrollY, left, top, right, bottom); } ; Phaser.TilemapLayer.prototype.render = function (){ var redrawAll = false ; if (!this.visible) { return ; } if (this.dirty || this.layer.dirty) { this.layer.dirty = false ; redrawAll = true ; } var renderWidth = this.canvas.width; var renderHeight = this.canvas.height; var scrollX = this._scrollX | 0; var scrollY = this._scrollY | 0; var mc = this._mc; var shiftX = mc.scrollX - scrollX; var shiftY = mc.scrollY - scrollY; if (!redrawAll && shiftX === 0 && shiftY === 0 && mc.renderWidth === renderWidth && mc.renderHeight === renderHeight) { return ; } this.context.save(); mc.scrollX = scrollX; mc.scrollY = scrollY; if (mc.renderWidth !== renderWidth || mc.renderHeight !== renderHeight) { mc.renderWidth = renderWidth; mc.renderHeight = renderHeight; } if (this.debug) { this.context.globalAlpha = this.debugSettings.debugAlpha; if (this.debugSettings.forceFullRedraw) { redrawAll = true ; } } if (!redrawAll && this.renderSettings.enableScrollDelta && (Math.abs(shiftX) + Math.abs(shiftY)) < Math.min(renderWidth, renderHeight)) { this.renderDeltaScroll(shiftX, shiftY); } else { this.renderFull(); } if (this.debug) { this.context.globalAlpha = 1; this.renderDebug(); } this.texture.baseTexture.dirty(); this.dirty = false ; this.context.restore(); return true ; } ; Phaser.TilemapLayer.prototype.renderDebug = function (){ var scrollX = this._mc.scrollX; var scrollY = this._mc.scrollY; var context = this.context; var renderW = this.canvas.width; var renderH = this.canvas.height; var width = this.layer.width; var height = this.layer.height; var tw = this._mc.tileWidth; var th = this._mc.tileHeight; var left = Math.floor(scrollX / tw); var right = Math.floor((renderW - 1 + scrollX) / tw); var top = Math.floor(scrollY / th); var bottom = Math.floor((renderH - 1 + scrollY) / th); var baseX = (left * tw) - scrollX; var baseY = (top * th) - scrollY; var normStartX = (left + ((1 << 20) * width)) % width; var normStartY = (top + ((1 << 20) * height)) % height; var tx, ty, x, y, xmax, ymax; context.strokeStyle = this.debugSettings.facingEdgeStroke; for (y = normStartY, ymax = bottom - top, ty = baseY; ymax >= 0; y++ , ymax-- , ty += th){ if (y >= height) { y -= height; } var row = this.layer.data[y]; for (x = normStartX, xmax = right - left, tx = baseX; xmax >= 0; x++ , xmax-- , tx += tw){ if (x >= width) { x -= width; } var tile = row[x]; if (!tile || tile.index < 0 || !tile.collides) { continue ; } if (this.debugSettings.collidingTileOverfill) { context.fillStyle = this.debugSettings.collidingTileOverfill; context.fillRect(tx, ty, this._mc.cw, this._mc.ch); } if (this.debugSettings.facingEdgeStroke) { context.beginPath(); if (tile.faceTop) { context.moveTo(tx, ty); context.lineTo(tx + this._mc.cw, ty); } if (tile.faceBottom) { context.moveTo(tx, ty + this._mc.ch); context.lineTo(tx + this._mc.cw, ty + this._mc.ch); } if (tile.faceLeft) { context.moveTo(tx, ty); context.lineTo(tx, ty + this._mc.ch); } if (tile.faceRight) { context.moveTo(tx + this._mc.cw, ty); context.lineTo(tx + this._mc.cw, ty + this._mc.ch); } context.stroke(); } } } } ; Object.defineProperty(Phaser.TilemapLayer.prototype, "wrap", { get: function (){ return this._wrap; } , set: function (value){ this._wrap = value; this.dirty = true ; } } ); Object.defineProperty(Phaser.TilemapLayer.prototype, "scrollX", { get: function (){ return this._scrollX; } , set: function (value){ this._scrollX = value; } } ); Object.defineProperty(Phaser.TilemapLayer.prototype, "scrollY", { get: function (){ return this._scrollY; } , set: function (value){ this._scrollY = value; } } ); Object.defineProperty(Phaser.TilemapLayer.prototype, "collisionWidth", { get: function (){ return this._mc.cw; } , set: function (value){ this._mc.cw = value | 0; this.dirty = true ; } } ); Object.defineProperty(Phaser.TilemapLayer.prototype, "collisionHeight", { get: function (){ return this._mc.ch; } , set: function (value){ this._mc.ch = value | 0; this.dirty = true ; } } );