1 if(require) { var jaws = require("./core.js"); }
  2 
  3 var jaws = (function(jaws) {
  4   /**
  5    * @class Create and access tilebased 2D maps with very fast access of invidual tiles. "Field Summary" contains options for the TileMap()-constructor.
  6    *
  7    * @property {array} cell_size        Size of each cell in tilemap, defaults to [32,32]
  8    * @property {array} size             Size of tilemap, defaults to [100,100]
  9    * @property {function} sortFunction  Function used by sortCells() to sort cells, defaults to no sorting
 10    *
 11    * @example
 12    * var tile_map = new TileMap({size: [10, 10], cell_size: [16,16]})
 13    * var sprite = new jaws.Sprite({x: 40, y: 40})
 14    * var sprite2 = new jaws.Sprite({x: 41, y: 41})
 15    * tile_map.push(sprite)
 16    *
 17    * tile_map.at(10,10)  // []
 18    * tile_map.at(40,40)  // [sprite]
 19    * tile_map.cell(0,0)  // []
 20    * tile_map.cell(1,1)  // [sprite]
 21    *
 22    */
 23   jaws.TileMap = function TileMap(options) {
 24     if( !(this instanceof arguments.callee) ) return new arguments.callee( options );
 25 
 26     jaws.parseOptions(this, options, this.default_options);
 27     this.cells = new Array(this.size[0]);
 28 
 29     for(var col=0; col < this.size[0]; col++) {
 30       this.cells[col] = new Array(this.size[1]);
 31       for(var row=0; row < this.size[1]; row++) {
 32         this.cells[col][row] = [] // populate each cell with an empty array
 33       }
 34     }
 35   }
 36 
 37   jaws.TileMap.prototype.default_options = {
 38     cell_size: [32,32],
 39     size: [100,100],
 40     sortFunction: null
 41   }
 42 
 43   /** Clear all cells in tile map */
 44   jaws.TileMap.prototype.clear = function() {
 45     for(var col=0; col < this.size[0]; col++) {
 46       for(var row=0; row < this.size[1]; row++) {
 47         this.cells[col][row] = [];
 48       }
 49     }
 50   }
 51 
 52   /** Sort arrays in each cell in tile map according to sorter-function (see Array.sort) */
 53   jaws.TileMap.prototype.sortCells = function(sortFunction) {
 54     for(var col=0; col < this.size[0]; col++) {
 55       for(var row=0; row < this.size[1]; row++) {
 56         this.cells[col][row].sort( sortFunction )
 57       }
 58     }
 59   }
 60 
 61   /**
 62    * Push obj (or array of objs) into our cell-grid.
 63    *
 64    * Tries to read obj.x and obj.y to calculate what cell to occopy
 65    */
 66   jaws.TileMap.prototype.push = function(obj) {
 67     var that = this;
 68     if(obj.forEach) { 
 69       obj.forEach( function(item) { that.push(item) } );
 70       return obj;
 71     }
 72     if(obj.rect) {
 73       return this.pushAsRect(obj, obj.rect());
 74     }
 75     else {
 76       var col = parseInt(obj.x / this.cell_size[0]);
 77       var row = parseInt(obj.y / this.cell_size[1]);
 78       return this.pushToCell(col, row, obj);
 79     }
 80   }
 81   /** 
 82    * Push objects into tilemap.
 83    * Disregard height and width and only use x/y when calculating cell-position
 84    */
 85   jaws.TileMap.prototype.pushAsPoint = function(obj) {
 86     if(Array.isArray(obj)) { 
 87       for(var i=0; i < obj.length; i++) { this.pushAsPoint(obj[i]) }
 88       return obj;
 89     }
 90     else {
 91       var col = parseInt(obj.x / this.cell_size[0]);
 92       var row = parseInt(obj.y / this.cell_size[1]);
 93       return this.pushToCell(col, row, obj);
 94     }
 95   }
 96 
 97   /** push obj into cells touched by rect */
 98   jaws.TileMap.prototype.pushAsRect = function(obj, rect) {
 99     var from_col = parseInt(rect.x / this.cell_size[0]);
100     var to_col = parseInt((rect.right-1) / this.cell_size[0]); // -1
101     //jaws.log("rect.right: " + rect.right + " from/to col: " + from_col + " " + to_col, true)
102 
103     for(var col = from_col; col <= to_col; col++) {
104       var from_row = parseInt(rect.y / this.cell_size[1]);
105       var to_row = parseInt((rect.bottom-1) / this.cell_size[1]); // -1
106 
107       //jaws.log("rect.bottom " + rect.bottom + " from/to row: " + from_row + " " + to_row, true)
108       for(var row = from_row; row <= to_row; row++) {
109         // console.log("pushAtRect() col/row: " + col + "/" + row + " - " + this.cells[col][row])
110         this.pushToCell(col, row, obj);
111       }
112     }
113     return obj
114   }
115 
116   /** 
117    * Push obj to a specific cell specified by col and row 
118    * If cell is already occupied we create an array and push to that
119    */
120   jaws.TileMap.prototype.pushToCell = function(col, row, obj) {
121     this.cells[col][row].push(obj);
122     if(this.sortFunction) this.cells[col][row].sort(this.sortFunction);
123     return this
124   }
125 
126   //
127   // READERS
128   // 
129 
130   /** Get objects in cell that exists at coordinates x / y  */
131   jaws.TileMap.prototype.at = function(x, y) {
132     var col = parseInt(x / this.cell_size[0]);
133     var row = parseInt(y / this.cell_size[1]);
134     // console.log("at() col/row: " + col + "/" + row)
135     return this.cells[col][row];
136   }
137 
138   /** Returns occupants of all cells touched by 'rect' */
139   jaws.TileMap.prototype.atRect = function(rect) {
140     var objects = [];
141     var items;
142 
143     try {
144       var from_col = parseInt(rect.x / this.cell_size[0]);
145       if (from_col < 0) {
146         from_col = 0;
147       }
148       var to_col = parseInt(rect.right / this.cell_size[0]);
149       if (to_col >= this.size[0]) {
150         to_col = this.size[0] - 1;
151       }
152       var from_row = parseInt(rect.y / this.cell_size[1]);
153       if (from_row < 0) {
154         from_row = 0;
155       }
156       var to_row = parseInt(rect.bottom / this.cell_size[1]);
157       if (to_row >= this.size[1]) {
158         to_row = this.size[1] - 1;
159       }
160 
161       for(var col = from_col; col <= to_col; col++) {
162         for(var row = from_row; row <= to_row; row++) {
163           this.cells[col][row].forEach( function(item, total) { 
164             if(objects.indexOf(item) == -1) { objects.push(item) }
165           })
166         }
167       }
168     }
169     catch(e) {
170       // ... problems
171     }
172     return objects
173   }
174 
175   /** Returns all objects in tile map */
176   jaws.TileMap.prototype.all = function() {
177     var all = [];
178     for(var col=0; col < this.size[0]; col++) {
179       for(var row=0; row < this.size[1]; row++) {
180         this.cells[col][row].forEach( function(element, total) {
181           all.push(element)
182         });
183       }
184     }
185     return all
186   }
187 
188   /** Get objects in cell at col / row */
189   jaws.TileMap.prototype.cell = function(col, row) {
190     return this.cells[col][row]
191   }
192 
193   /** Debugstring for TileMap() */
194   jaws.TileMap.prototype.toString = function() { return "[TileMap " + this.size[0] + " cols, " + this.size[1] + " rows]" }
195 
196   return jaws;
197 })(jaws || {});
198 
199 // Support CommonJS require()
200 if(typeof module !== "undefined" && ('exports' in module)) { module.exports = jaws.TileMap }
201