var Map = function(stage){
this._stage = stage;
//Isometric Map
this._map = null;
//Sprite Data
this._sprites = {};
//Initial Center Location
this._x = 0;
this._y = 0;
//Drawn Layers
this._layers = [];
this._ready = false;
//Viewport
this._vp = null;
//Define cache canvas size
this._cache = {
width:this._stage.attrs.width*2,
height:this._stage.attrs.height*2,
x:0,
y:0
}
this._offset = {
x:(this._cache.width-this._stage.attrs.width)/2,
y:(this._cache.height-this._stage.attrs.height)/2
}
this._info = {
updateLayer:$('#update_layer'),
getImages:$('#get_images'),
drawImages:$('#draw_images'),
drawCache:$('#draw_cache'),
draw:$('#draw'),
bgChildren:$('#count_bg'),
objChildren:$('#count_obj'),
totalChildren:$('#count_all')
}
this._tiles = {};
}
Map.prototype = {
_data:null,
//Main function to draw the map
draw:function(){
//If map is not initialized or there is no viewport,return
if(!this._ready) return;
var drawTime = this._t();
//If the viewport is not within the stage
if(!this._stageWithinViewport()){
//Update layer
this._updateLayers();
}
//draw Layer
this._drawLayers();
var drawDiff = this._t() - drawTime;
this._info.draw.text(drawDiff);
},
//Initial Function, loads json file and initialize Map
load:function(config){
var map = this;
this._x = config.x;
this._y = config.y;
$.ajax({
url:"js/maps/"+config.map+'.json',
success:function(data){
//Save the data
map._setData(data);
map._init();
map._initLayers();
map._loadImages();
}
});
},
_setData:function(data){
this._data = data;
},
_init:function(){
var d = this._data,
mw = d.width,mh=d.height,tw=d.tilewidth,th=d.tileheight;
if(d.orientation === 'isometric'){
//Create new Isometric Helper
this._map = new Kinetic.Isometric(tw, th, mw, mh);
}
//Center the stage at position x/y
var pos = this._map.pos2px(this._x,this._y); //calculate position 2 pixel
//set center position of stage
this._stage.attrs.x = -pos.left+this._cache.width/2-tw/2;
this._stage.attrs.y = -pos.top+this._cache.height/2;
},
//Function to create layers
_initLayers:function(){
//Loop throught layers
for(var i = 0,il = this._data.layers.length;i<il;i++){
var l = this._data.layers[i];
//If the layer is a tile layer
if(l.type === "tilelayer"){
//Create new layer
var layer = new Kinetic.Layer({
listening:false,
name:l.name,
data:l.data,
visible:l.visible
});
//if layer is visible
if(l.visible){
var map = this;
//Create a cache Canvas
var cache =new Kinetic.Canvas(this._cache.width,this._cache.height);
cache.name = 'cache';
//add chacheCanvas to layer
layer.cacheCanvas = cache;
//$('#cache').append(cache.getElement());
//sort the children before Draw
layer.beforeDraw(function(){
if(this.attrs.name === 'background') {
map._info.bgChildren.text(this.children.length);
}
if(this.attrs.name === 'object') {
map._info.objChildren.text(this.children.length);
}
this.children.sort(function(a,b){
return a.attrs.zIndex - b.attrs.zIndex;
});
this.cacheCanvas.clear();
});
layer.drawCache = function(){
var
w=map._stage.attrs.width,
h=map._stage.attrs.height,
x=(-map._stage.attrs.x-map._vp.x)+map._offset.x,
y=(-map._stage.attrs.y-map._vp.y)+map._offset.y;
this.getCanvas().clear();
//Draw the part of cached Canvas into layer canvas
this.getContext().drawImage(this.cacheCanvas.getElement(),x,y,w,h,0,0,w,h);
}
//create new array of visible layers
this._layers.push(layer);
}
//add layers to stage
this._stage.add(layer);
}
}
},
//Function to load images
_loadImages:function(){
var map = this;
//create sprites and get images to load from json file
var loader = new Kinetic.Loader(this._createSprites());
loader.onError(function(data){
});
loader.onProgress(function(data){
});
loader.onComplete(function(){
//draw map
map._updateLayers();
map._ready = true;
});
//start loading
loader.load();
},
//Function to create sprites array
_createSprites:function(){
var images = [];
for(var i =0,il = this._data.tilesets.length;i<il;i++){
var tileset = this._data.tilesets[i],id=tileset.firstgid;
for(var y = 0,yl = tileset.imageheight;y<yl;y+=tileset.tileheight){
for(var x = 0,xl = tileset.imagewidth;x<xl;x+=tileset.tilewidth){
//default offset
var offset = {
x:0,
y:0
};
//overwrite offset if set
if(tileset.tileoffset){
offset.x = -tileset.tileoffset.x;
offset.y = -tileset.tileoffset.y;
}
//create sprite object
this._sprites[id] = {
name:tileset.name,
x:x,
y:y,
width:tileset.tilewidth,
height:tileset.tileheight,
offset:offset
};
id++;
}
}
//push images to load
images.push({
src:tileset.image,
id:tileset.name
});
}
return images;
},
_drawLayers:function(){
var t = this._t();
//loop throught visible layers and draw part of chacecanvas into screencanvas
for(var l = 0,ll = this._layers.length;l<ll;l++){
this._layers[l].drawCache();
}
var diff = this._t() - t;
this._info.drawCache.text(diff);
},
_updateLayers:function(){
var updateTime = this._t();
this._vp = {
x:-this._stage.attrs.x,
y:-this._stage.attrs.y,
w:this._cache.width,
h:this._cache.height
}
//get area of viewport
var area = this._map.area(this._vp),mw=this._data.width,x=0,y=0,i=0,tiles = {},grid={};
//loop throught elements
var imageTime = this._t();
for(var a = 0,al = area.length;a<al;a++){
x = area[a][0]; //get x
y = area[a][1]; //get y
i = y*mw+x; //get index
//loop throught visible layers
for(var l = 0,ll = this._layers.length;l<ll;l++){
var layer = this._layers[l],
id = layer.attrs.data[i],
tile = this._sprites[id];
//if sprite not exists or sprite id = 0 continue to next layer
var name = "Y"+y+"X"+x+"Z"+(l+1);
grid[name] = true;
//reduce amount of loops
if(id < 1 || !tile || this._tiles[name]) continue;
//create individual tile name
var pos = this._map.pos2px(x,y);
var image = new Kinetic.Image({
x: pos.left,
y:pos.top-tile.height,
image: Kinetic.Assets[tile.name],
width: tile.width,
height: tile.height,
crop:{
x:tile.x,
y:tile.y,
width:tile.width,
height:tile.height
},
offset :tile.offset,
zIndex:pos.top*(l+1),
name:name
});
this._tiles[name]=image;
//add image to layer
layer.add(image);
}
}
var imageDiff = this._t()-imageTime;
this._info.getImages.text(imageDiff);
for(var i in this._tiles){
var t = this._tiles[i];
if(!grid[i]){ //if the name is in Grid var
t.attrs.visible = false;
}else{
//here i need to delete it
t.attrs.visible = true;
}
}
delete grid;
var drawTime = this._t();
//loop throught visible layers and draw children on cache canvas
var children = 0;
for(l = 0,ll = this._layers.length;l<ll;l++){
layer =this._layers[l];
children += layer.children.length;
layer.draw(layer.cacheCanvas);
}
this._info.totalChildren.text(children);
var drawDiff = this._t()-drawTime;
this._info.drawImages.text(drawDiff);
var updateDiff = this._t()-updateTime;
this._info.updateLayer.text(updateDiff);
},
_stageWithinViewport:function(){
//lazy vars
var s = this._stage.attrs,o = this._offset,vp = this._vp,tw =this._data.tilewidth,th = this._data.tileheight;
var stage = {
x:-s.x+(o.x-tw/2),
y:-s.y+(o.y-th),
w:s.width,
h:s.height
};
var viewport ={
x:vp.x,
y:vp.y,
w:vp.w,
h:vp.h
}
var within = viewport.x <= stage.x && viewport.x + viewport.w >= stage.x + stage.w &&
viewport.y <= stage.y && vp.y + viewport.h >= stage.y + stage.h;
return within;
},
_t:function(){
return Date.now();
},
isReady:function(){
return this._ready;
}
}
|