2012-06-21 10:13:21 +02:00
|
|
|
ig.module(
|
|
|
|
'impact.background-map'
|
|
|
|
)
|
|
|
|
.requires(
|
|
|
|
'impact.map',
|
|
|
|
'impact.image'
|
|
|
|
)
|
2012-06-22 17:26:53 +02:00
|
|
|
.defines(function(){ "use strict";
|
2012-06-21 10:13:21 +02:00
|
|
|
|
|
|
|
ig.BackgroundMap = ig.Map.extend({
|
|
|
|
tiles: null,
|
|
|
|
scroll: {x: 0, y:0},
|
|
|
|
distance: 1,
|
|
|
|
repeat: false,
|
|
|
|
tilesetName: '',
|
|
|
|
foreground: false,
|
|
|
|
enabled: true,
|
|
|
|
|
|
|
|
preRender: false,
|
|
|
|
preRenderedChunks: null,
|
|
|
|
chunkSize: 512,
|
|
|
|
debugChunks: false,
|
|
|
|
|
|
|
|
|
|
|
|
anims: {},
|
|
|
|
|
|
|
|
|
|
|
|
init: function( tilesize, data, tileset ) {
|
|
|
|
this.parent( tilesize, data );
|
|
|
|
this.setTileset( tileset );
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
setTileset: function( tileset ) {
|
|
|
|
this.tilesetName = tileset instanceof ig.Image ? tileset.path : tileset;
|
|
|
|
this.tiles = new ig.Image( this.tilesetName );
|
|
|
|
this.preRenderedChunks = null;
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
setScreenPos: function( x, y ) {
|
|
|
|
this.scroll.x = x / this.distance;
|
|
|
|
this.scroll.y = y / this.distance;
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
preRenderMapToChunks: function() {
|
|
|
|
var totalWidth = this.width * this.tilesize * ig.system.scale,
|
|
|
|
totalHeight = this.height * this.tilesize * ig.system.scale;
|
|
|
|
|
|
|
|
var chunkCols = Math.ceil(totalWidth / this.chunkSize),
|
|
|
|
chunkRows = Math.ceil(totalHeight / this.chunkSize);
|
|
|
|
|
|
|
|
this.preRenderedChunks = [];
|
|
|
|
for( var y = 0; y < chunkRows; y++ ) {
|
|
|
|
this.preRenderedChunks[y] = [];
|
|
|
|
|
|
|
|
for( var x = 0; x < chunkCols; x++ ) {
|
|
|
|
|
|
|
|
|
|
|
|
var chunkWidth = (x == chunkCols-1)
|
|
|
|
? totalWidth - x * this.chunkSize
|
|
|
|
: this.chunkSize;
|
|
|
|
|
|
|
|
var chunkHeight = (y == chunkRows-1)
|
|
|
|
? totalHeight - y * this.chunkSize
|
|
|
|
: this.chunkSize;
|
|
|
|
|
|
|
|
this.preRenderedChunks[y][x] = this.preRenderChunk( x, y, chunkWidth, chunkHeight );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
preRenderChunk: function( cx, cy, w, h ) {
|
2012-06-22 17:26:53 +02:00
|
|
|
var tw = w / this.tilesize / ig.system.scale + 1,
|
2012-06-21 10:13:21 +02:00
|
|
|
th = h / this.tilesize / ig.system.scale + 1;
|
|
|
|
|
|
|
|
var nx = (cx * this.chunkSize / ig.system.scale) % this.tilesize,
|
|
|
|
ny = (cy * this.chunkSize / ig.system.scale) % this.tilesize;
|
|
|
|
|
|
|
|
var tx = Math.floor(cx * this.chunkSize / this.tilesize / ig.system.scale),
|
|
|
|
ty = Math.floor(cy * this.chunkSize / this.tilesize / ig.system.scale);
|
|
|
|
|
|
|
|
|
|
|
|
var chunk = ig.$new( 'canvas');
|
|
|
|
chunk.width = w;
|
|
|
|
chunk.height = h;
|
|
|
|
|
|
|
|
var oldContext = ig.system.context;
|
|
|
|
ig.system.context = chunk.getContext("2d");
|
|
|
|
|
|
|
|
for( var x = 0; x < tw; x++ ) {
|
|
|
|
for( var y = 0; y < th; y++ ) {
|
|
|
|
if( x + tx < this.width && y + ty < this.height ) {
|
|
|
|
var tile = this.data[y+ty][x+tx];
|
|
|
|
if( tile ) {
|
|
|
|
this.tiles.drawTile(
|
|
|
|
x * this.tilesize - nx, y * this.tilesize - ny,
|
|
|
|
tile - 1, this.tilesize
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ig.system.context = oldContext;
|
|
|
|
|
|
|
|
return chunk;
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
draw: function() {
|
|
|
|
if( !this.tiles.loaded || !this.enabled ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( this.preRender ) {
|
|
|
|
this.drawPreRendered();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.drawTiled();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
drawPreRendered: function() {
|
|
|
|
if( !this.preRenderedChunks ) {
|
|
|
|
this.preRenderMapToChunks();
|
|
|
|
}
|
|
|
|
|
|
|
|
var dx = ig.system.getDrawPos(this.scroll.x),
|
|
|
|
dy = ig.system.getDrawPos(this.scroll.y);
|
|
|
|
|
|
|
|
|
|
|
|
if( this.repeat ) {
|
|
|
|
dx %= this.width * this.tilesize * ig.system.scale;
|
|
|
|
dy %= this.height * this.tilesize * ig.system.scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
var minChunkX = Math.max( Math.floor(dx / this.chunkSize), 0 ),
|
|
|
|
minChunkY = Math.max( Math.floor(dy / this.chunkSize), 0 ),
|
|
|
|
maxChunkX = Math.ceil((dx+ig.system.realWidth) / this.chunkSize),
|
|
|
|
maxChunkY = Math.ceil((dy+ig.system.realHeight) / this.chunkSize),
|
|
|
|
maxRealChunkX = this.preRenderedChunks[0].length,
|
|
|
|
maxRealChunkY = this.preRenderedChunks.length;
|
|
|
|
|
|
|
|
|
|
|
|
if( !this.repeat ) {
|
|
|
|
maxChunkX = Math.min( maxChunkX, maxRealChunkX );
|
|
|
|
maxChunkY = Math.min( maxChunkY, maxRealChunkY );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var nudgeY = 0;
|
|
|
|
for( var cy = minChunkY; cy < maxChunkY; cy++ ) {
|
|
|
|
|
|
|
|
var nudgeX = 0;
|
|
|
|
for( var cx = minChunkX; cx < maxChunkX; cx++ ) {
|
|
|
|
var chunk = this.preRenderedChunks[cy % maxRealChunkY][cx % maxRealChunkX];
|
|
|
|
|
|
|
|
var x = -dx + cx * this.chunkSize - nudgeX;
|
|
|
|
var y = -dy + cy * this.chunkSize - nudgeY;
|
|
|
|
ig.system.context.drawImage( chunk, x, y);
|
|
|
|
ig.Image.drawCount++;
|
|
|
|
|
|
|
|
if( this.debugChunks ) {
|
|
|
|
ig.system.context.strokeStyle = '#f0f';
|
|
|
|
ig.system.context.strokeRect( x, y, this.chunkSize, this.chunkSize );
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we repeat in X and this chunks width wasn't the full chunk size
|
|
|
|
// and the screen is not already filled, we need to draw anohter chunk
|
|
|
|
// AND nudge it to be flush with the last chunk
|
|
|
|
if( this.repeat && chunk.width < this.chunkSize && x + chunk.width < ig.system.realWidth ) {
|
|
|
|
nudgeX = this.chunkSize - chunk.width;
|
|
|
|
maxChunkX++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same as above, but for Y
|
|
|
|
if( this.repeat && chunk.height < this.chunkSize && y + chunk.height < ig.system.realHeight ) {
|
|
|
|
nudgeY = this.chunkSize - chunk.height;
|
|
|
|
maxChunkY++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
drawTiled: function() {
|
|
|
|
var tile = 0,
|
|
|
|
anim = null,
|
|
|
|
tileOffsetX = (this.scroll.x / this.tilesize).toInt(),
|
|
|
|
tileOffsetY = (this.scroll.y / this.tilesize).toInt(),
|
|
|
|
pxOffsetX = this.scroll.x % this.tilesize,
|
|
|
|
pxOffsetY = this.scroll.y % this.tilesize,
|
|
|
|
pxMinX = -pxOffsetX - this.tilesize,
|
|
|
|
pxMinY = -pxOffsetY - this.tilesize,
|
|
|
|
pxMaxX = ig.system.width + this.tilesize - pxOffsetX,
|
|
|
|
pxMaxY = ig.system.height + this.tilesize - pxOffsetY;
|
|
|
|
|
|
|
|
|
|
|
|
// FIXME: could be sped up for non-repeated maps: restrict the for loops
|
|
|
|
// to the map size instead of to the screen size and skip the 'repeat'
|
|
|
|
// checks inside the loop.
|
|
|
|
|
|
|
|
for( var mapY = -1, pxY = pxMinY; pxY < pxMaxY; mapY++, pxY += this.tilesize) {
|
|
|
|
var tileY = mapY + tileOffsetY;
|
|
|
|
|
|
|
|
// Repeat Y?
|
|
|
|
if( tileY >= this.height || tileY < 0 ) {
|
|
|
|
if( !this.repeat ) { continue; }
|
|
|
|
tileY = tileY > 0
|
|
|
|
? tileY % this.height
|
|
|
|
: ((tileY+1) % this.height) + this.height - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( var mapX = -1, pxX = pxMinX; pxX < pxMaxX; mapX++, pxX += this.tilesize ) {
|
|
|
|
var tileX = mapX + tileOffsetX;
|
|
|
|
|
|
|
|
// Repeat X?
|
|
|
|
if( tileX >= this.width || tileX < 0 ) {
|
|
|
|
if( !this.repeat ) { continue; }
|
|
|
|
tileX = tileX > 0
|
|
|
|
? tileX % this.width
|
|
|
|
: ((tileX+1) % this.width) + this.width - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw!
|
|
|
|
if( (tile = this.data[tileY][tileX]) ) {
|
|
|
|
if( (anim = this.anims[tile-1]) ) {
|
|
|
|
anim.draw( pxX, pxY );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.tiles.drawTile( pxX, pxY, tile-1, this.tilesize );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // end for x
|
|
|
|
} // end for y
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|