├── README ├── cache.manifest ├── cash.js ├── file.htaccess ├── game.js ├── images ├── 511n9k.png ├── TileE-5.png ├── batalhao_tileset_cc_by_sa.png ├── map57.jpg ├── mi20041007b_medusachamber.png ├── rsyo0k.png ├── tiles.png └── tiles2.png ├── index.html ├── json.js ├── mapmodel.js ├── message.js ├── painter.js └── tilemap.js /README: -------------------------------------------------------------------------------- 1 | /*All code copyright 2010 by John Graham unless otherwise attributed*/ 2 | //Edits and additions by Jay Crossler, changes Creative Commons BY/3.0 license 3 | 4 | An HTML5 JavaScript library originally written by John Graham and updated by Jay Crossler 5 | 6 | Pulls a JSON object of a map set of tiles and sprites, then maps them onto a Canvas graphical object -------------------------------------------------------------------------------- /cache.manifest: -------------------------------------------------------------------------------- 1 | #CACHE MANIFEST 2 | 3 | # Offline cache 2010-10-31-v4 4 | 5 | CACHE: 6 | index.html 7 | message.js 8 | tilemap.js 9 | painter.js 10 | game.js 11 | mapmodel.js 12 | 13 | images/mi20041007b_medusachamber.png 14 | images/rsyo0k.png 15 | images/511n9k.png 16 | images/TileE-5.png 17 | images/tiles.png 18 | images/batalhao_tileset_cc_by_sa.png 19 | images/map57.jpg 20 | images/tiles2.png 21 | -------------------------------------------------------------------------------- /cash.js: -------------------------------------------------------------------------------- 1 | /*All code copyright 2010 by Jay Crossler unless otherwise attributed - CC BY/3.0 License */ 2 | 3 | /* 4 | Ver 0.3 - 3 Nov 2010 5 | 6 | TODO: 7 | - Calculate the size of images, then switch to Application Cache after 5mb 8 | - Save Date stored 9 | - Save/load two lookup columns as well as name 10 | X Have is_ready work from parent .js 11 | x Save in App Cache 12 | - Save canvas in app cache? 13 | */ 14 | var Cash = { //object to save images into HTML5 DB 15 | //Note, the biggest issue with dealing with an HTML5 Database is that all calls are asynchronous 16 | db: 0, //database id 17 | imageList: [], //list of currently cached images 18 | storeInAppCache: true, // if false, use HTML5-db. if true, use App Cache 19 | is_ready: false, 20 | loadToImg: function(src, img, makecanvas) { // load src into img from cache if exists 21 | if (Cash.storeInAppCache) { 22 | if (Cash.imgInCache(src)) { // Check the array of cached objects 23 | img.src = localStorage.getItem('img:'+src); 24 | console.log('Loaded from app cache: ' + src); 25 | } else { 26 | img.addEventListener('load', function() { 27 | Cash.saveImage(src, img); 28 | }, false); 29 | 30 | img.src = src; 31 | console.log('Img ' + src + ' is not in app cache. Loading normally.'); 32 | } 33 | }else{ //Store in HTML5 DB 34 | if (Cash.db) { 35 | if (Cash.imgInCache(src)) { // Check the array of cached objects 36 | Cash.db.readTransaction(function (transaction) { //Select from dDB 37 | transaction.executeSql('SELECT data FROM cache_images WHERE src = ?', [src], 38 | function (transaction, r) { 39 | if (r.rows && r.rows.length > 0) { //If Exists 40 | //get photodata, write to img.src 41 | img.src = r.rows.item(0)['data']; 42 | console.log('Loaded from db cache: ' + src); 43 | } else { 44 | //somehow doesn't exist, load normally 45 | img.src = src; 46 | console.log('Img should be in DB cache array, is not.'); 47 | //TODO: SaveData of img? 48 | } 49 | }, function (transaction, e) { // couldn't read database 50 | console.log('(db err: ' + e.message + ')'); 51 | }); 52 | }); 53 | } else { // Not in Cache Array 54 | //TODO: Check on iPad, make sure memory allows this 55 | // if (makecanvas) { //If true, store as a canvas, then enter into cache 56 | img.addEventListener('load', function() { 57 | Cash.saveImage(src, img); 58 | }, false); 59 | // } 60 | img.src = src; 61 | console.log('Img not in cache array, loading normally'); 62 | } 63 | } else {// No cache, just load img src 64 | img.src = src; 65 | console.log('No cache, standard loading of '+src); 66 | } 67 | } 68 | }, 69 | loadToCanvas: function(src, canvas, should_forceload) { // load src into canvas from cache if exists 70 | if (Cash.storeInAppCache) { 71 | if (Cash.imgInCache(src)) { // Check the array of cached objects 72 | Cash.drawImageOnCanvas(localStorage.getItem('img:'+src), canvas); 73 | console.log('Loaded from app cache: ' + src); 74 | } else { 75 | Cash.drawImageOnCanvas(src, canvas); 76 | console.log('Img ' + src + ' is not in app cache. Loading normally.'); 77 | } 78 | }else{ //Store in HTML5 DB 79 | if (Cash.db) { 80 | if (should_forceload || Cash.imgInCache(src)) { // Check the array of cached objects 81 | Cash.db.readTransaction(function (transaction) { //Select from dDB 82 | transaction.executeSql('SELECT data FROM cache_images WHERE src = ?', [src], 83 | function (transaction, r) { 84 | if (r.rows && r.rows.length > 0) { //If Exists 85 | //get photodata, write to canvas 86 | Cash.drawImageOnCanvas(r.rows.item(0)['data'], canvas); 87 | console.log('Loaded into canvas from cache: ' + src); 88 | } 89 | }, function (transaction, e) { // couldn't read database 90 | console.log('(db err: ' + e.message + ')'); 91 | }); 92 | }); 93 | } else { // Not in Cache Array 94 | console.log('Canvas src '+ src + ' not in cache array, not loading.'); 95 | } 96 | } else {// No cache, just load img src 97 | console.log('No image cache, Canvas not loading'); 98 | } 99 | } 100 | }, 101 | imgInCache: function(src) { //Is src saved in the array list 102 | var isfound = false; 103 | for (var i=0;i 0) { 181 | for (var i=0; i < localStorage.length; i++){ 182 | var key = localStorage.key(i); 183 | Cash.imageList.push(key); 184 | } 185 | console.log('Created imageList lookup array with '+localStorage.length); 186 | } else { 187 | console.log('No images found in app cache_image database'); 188 | } 189 | }else{ //Pull from HTML5 DB 190 | if (Cash.db) { 191 | Cash.db.transaction( 192 | function (transaction) { 193 | transaction.executeSql('SELECT src FROM cache_images', [], 194 | function (transaction, results) { //Function to run when successful 195 | if (results.rows && (results.rows.length > 0)) { //NOTE: Use .item(0), not [0] when accessing array 196 | for (var i=0;i0.66) //Save map every 3 changes to reduce local db load 179 | Cash.saveData('LastTileMap',document.getElementById('main_canvas').toDataURL(),true); 180 | } 181 | Cash.list(Message.message); 182 | FPS.fps_count++; //increments frame for fps display 183 | 184 | }, 185 | createTiles: function(mapJSONData){ //create and initialize tile engine 186 | if (mapJSONData) { //Added optional init data 187 | //Reload maps 188 | inputJSON = eval("("+mapJSONData+")"); //TODO, Change away from Eval for security reasons 189 | for (var i=0;i 2 | 3 | 4 | 5 | SMORGMap 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 79 | 80 | 81 | 82 | 83 |
84 | 85 | Unfortunately, your browser does not support the canvas tag. 86 | 87 |
88 | 89 |
90 | - [DEL] 91 |
92 |
93 | | 94 | 95 |
96 |
97 |
98 | Paint layer: 99 |
100 | 101 | Drawing pallette 102 | 103 |
104 |
105 | 106 |
107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /json.js: -------------------------------------------------------------------------------- 1 | /* 2 | http://www.JSON.org/json2.js 3 | 2010-08-25 4 | 5 | Public Domain. 6 | 7 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. 8 | 9 | See http://www.JSON.org/js.html 10 | 11 | 12 | This code should be minified before deployment. 13 | See http://javascript.crockford.com/jsmin.html 14 | 15 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO 16 | NOT CONTROL. 17 | 18 | 19 | This file creates a global JSON object containing two methods: stringify 20 | and parse. 21 | 22 | JSON.stringify(value, replacer, space) 23 | value any JavaScript value, usually an object or array. 24 | 25 | replacer an optional parameter that determines how object 26 | values are stringified for objects. It can be a 27 | function or an array of strings. 28 | 29 | space an optional parameter that specifies the indentation 30 | of nested structures. If it is omitted, the text will 31 | be packed without extra whitespace. If it is a number, 32 | it will specify the number of spaces to indent at each 33 | level. If it is a string (such as '\t' or ' '), 34 | it contains the characters used to indent at each level. 35 | 36 | This method produces a JSON text from a JavaScript value. 37 | 38 | When an object value is found, if the object contains a toJSON 39 | method, its toJSON method will be called and the result will be 40 | stringified. A toJSON method does not serialize: it returns the 41 | value represented by the name/value pair that should be serialized, 42 | or undefined if nothing should be serialized. The toJSON method 43 | will be passed the key associated with the value, and this will be 44 | bound to the value 45 | 46 | For example, this would serialize Dates as ISO strings. 47 | 48 | Date.prototype.toJSON = function (key) { 49 | function f(n) { 50 | // Format integers to have at least two digits. 51 | return n < 10 ? '0' + n : n; 52 | } 53 | 54 | return this.getUTCFullYear() + '-' + 55 | f(this.getUTCMonth() + 1) + '-' + 56 | f(this.getUTCDate()) + 'T' + 57 | f(this.getUTCHours()) + ':' + 58 | f(this.getUTCMinutes()) + ':' + 59 | f(this.getUTCSeconds()) + 'Z'; 60 | }; 61 | 62 | You can provide an optional replacer method. It will be passed the 63 | key and value of each member, with this bound to the containing 64 | object. The value that is returned from your method will be 65 | serialized. If your method returns undefined, then the member will 66 | be excluded from the serialization. 67 | 68 | If the replacer parameter is an array of strings, then it will be 69 | used to select the members to be serialized. It filters the results 70 | such that only members with keys listed in the replacer array are 71 | stringified. 72 | 73 | Values that do not have JSON representations, such as undefined or 74 | functions, will not be serialized. Such values in objects will be 75 | dropped; in arrays they will be replaced with null. You can use 76 | a replacer function to replace those with JSON values. 77 | JSON.stringify(undefined) returns undefined. 78 | 79 | The optional space parameter produces a stringification of the 80 | value that is filled with line breaks and indentation to make it 81 | easier to read. 82 | 83 | If the space parameter is a non-empty string, then that string will 84 | be used for indentation. If the space parameter is a number, then 85 | the indentation will be that many spaces. 86 | 87 | Example: 88 | 89 | text = JSON.stringify(['e', {pluribus: 'unum'}]); 90 | // text is '["e",{"pluribus":"unum"}]' 91 | 92 | 93 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); 94 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' 95 | 96 | text = JSON.stringify([new Date()], function (key, value) { 97 | return this[key] instanceof Date ? 98 | 'Date(' + this[key] + ')' : value; 99 | }); 100 | // text is '["Date(---current time---)"]' 101 | 102 | 103 | JSON.parse(text, reviver) 104 | This method parses a JSON text to produce an object or array. 105 | It can throw a SyntaxError exception. 106 | 107 | The optional reviver parameter is a function that can filter and 108 | transform the results. It receives each of the keys and values, 109 | and its return value is used instead of the original value. 110 | If it returns what it received, then the structure is not modified. 111 | If it returns undefined then the member is deleted. 112 | 113 | Example: 114 | 115 | // Parse the text. Values that look like ISO date strings will 116 | // be converted to Date objects. 117 | 118 | myData = JSON.parse(text, function (key, value) { 119 | var a; 120 | if (typeof value === 'string') { 121 | a = 122 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); 123 | if (a) { 124 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], 125 | +a[5], +a[6])); 126 | } 127 | } 128 | return value; 129 | }); 130 | 131 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { 132 | var d; 133 | if (typeof value === 'string' && 134 | value.slice(0, 5) === 'Date(' && 135 | value.slice(-1) === ')') { 136 | d = new Date(value.slice(5, -1)); 137 | if (d) { 138 | return d; 139 | } 140 | } 141 | return value; 142 | }); 143 | 144 | 145 | This is a reference implementation. You are free to copy, modify, or 146 | redistribute. 147 | */ 148 | 149 | /*jslint evil: true, strict: false */ 150 | 151 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, 152 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, 153 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, 154 | lastIndex, length, parse, prototype, push, replace, slice, stringify, 155 | test, toJSON, toString, valueOf 156 | */ 157 | 158 | 159 | // Create a JSON object only if one does not already exist. We create the 160 | // methods in a closure to avoid creating global variables. 161 | 162 | if (!this.JSON) { 163 | this.JSON = {}; 164 | } 165 | 166 | (function () { 167 | 168 | function f(n) { 169 | // Format integers to have at least two digits. 170 | return n < 10 ? '0' + n : n; 171 | } 172 | 173 | if (typeof Date.prototype.toJSON !== 'function') { 174 | 175 | Date.prototype.toJSON = function (key) { 176 | 177 | return isFinite(this.valueOf()) ? 178 | this.getUTCFullYear() + '-' + 179 | f(this.getUTCMonth() + 1) + '-' + 180 | f(this.getUTCDate()) + 'T' + 181 | f(this.getUTCHours()) + ':' + 182 | f(this.getUTCMinutes()) + ':' + 183 | f(this.getUTCSeconds()) + 'Z' : null; 184 | }; 185 | 186 | String.prototype.toJSON = 187 | Number.prototype.toJSON = 188 | Boolean.prototype.toJSON = function (key) { 189 | return this.valueOf(); 190 | }; 191 | } 192 | 193 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 194 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 195 | gap, 196 | indent, 197 | meta = { // table of character substitutions 198 | '\b': '\\b', 199 | '\t': '\\t', 200 | '\n': '\\n', 201 | '\f': '\\f', 202 | '\r': '\\r', 203 | '"' : '\\"', 204 | '\\': '\\\\' 205 | }, 206 | rep; 207 | 208 | 209 | function quote(string) { 210 | 211 | // If the string contains no control characters, no quote characters, and no 212 | // backslash characters, then we can safely slap some quotes around it. 213 | // Otherwise we must also replace the offending characters with safe escape 214 | // sequences. 215 | 216 | escapable.lastIndex = 0; 217 | return escapable.test(string) ? 218 | '"' + string.replace(escapable, function (a) { 219 | var c = meta[a]; 220 | return typeof c === 'string' ? c : 221 | '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 222 | }) + '"' : 223 | '"' + string + '"'; 224 | } 225 | 226 | 227 | function str(key, holder) { 228 | 229 | // Produce a string from holder[key]. 230 | 231 | var i, // The loop counter. 232 | k, // The member key. 233 | v, // The member value. 234 | length, 235 | mind = gap, 236 | partial, 237 | value = holder[key]; 238 | 239 | // If the value has a toJSON method, call it to obtain a replacement value. 240 | 241 | if (value && typeof value === 'object' && 242 | typeof value.toJSON === 'function') { 243 | value = value.toJSON(key); 244 | } 245 | 246 | // If we were called with a replacer function, then call the replacer to 247 | // obtain a replacement value. 248 | 249 | if (typeof rep === 'function') { 250 | value = rep.call(holder, key, value); 251 | } 252 | 253 | // What happens next depends on the value's type. 254 | 255 | switch (typeof value) { 256 | case 'string': 257 | return quote(value); 258 | 259 | case 'number': 260 | 261 | // JSON numbers must be finite. Encode non-finite numbers as null. 262 | 263 | return isFinite(value) ? String(value) : 'null'; 264 | 265 | case 'boolean': 266 | case 'null': 267 | 268 | // If the value is a boolean or null, convert it to a string. Note: 269 | // typeof null does not produce 'null'. The case is included here in 270 | // the remote chance that this gets fixed someday. 271 | 272 | return String(value); 273 | 274 | // If the type is 'object', we might be dealing with an object or an array or 275 | // null. 276 | 277 | case 'object': 278 | 279 | // Due to a specification blunder in ECMAScript, typeof null is 'object', 280 | // so watch out for that case. 281 | 282 | if (!value) { 283 | return 'null'; 284 | } 285 | 286 | // Make an array to hold the partial results of stringifying this object value. 287 | 288 | gap += indent; 289 | partial = []; 290 | 291 | // Is the value an array? 292 | 293 | if (Object.prototype.toString.apply(value) === '[object Array]') { 294 | 295 | // The value is an array. Stringify every element. Use null as a placeholder 296 | // for non-JSON values. 297 | 298 | length = value.length; 299 | for (i = 0; i < length; i += 1) { 300 | partial[i] = str(i, value) || 'null'; 301 | } 302 | 303 | // Join all of the elements together, separated with commas, and wrap them in 304 | // brackets. 305 | 306 | v = partial.length === 0 ? '[]' : 307 | gap ? '[\n' + gap + 308 | partial.join(',\n' + gap) + '\n' + 309 | mind + ']' : 310 | '[' + partial.join(',') + ']'; 311 | gap = mind; 312 | return v; 313 | } 314 | 315 | // If the replacer is an array, use it to select the members to be stringified. 316 | 317 | if (rep && typeof rep === 'object') { 318 | length = rep.length; 319 | for (i = 0; i < length; i += 1) { 320 | k = rep[i]; 321 | if (typeof k === 'string') { 322 | v = str(k, value); 323 | if (v) { 324 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 325 | } 326 | } 327 | } 328 | } else { 329 | 330 | // Otherwise, iterate through all of the keys in the object. 331 | 332 | for (k in value) { 333 | if (Object.hasOwnProperty.call(value, k)) { 334 | v = str(k, value); 335 | if (v) { 336 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 337 | } 338 | } 339 | } 340 | } 341 | 342 | // Join all of the member texts together, separated with commas, 343 | // and wrap them in braces. 344 | 345 | v = partial.length === 0 ? '{}' : 346 | gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + 347 | mind + '}' : '{' + partial.join(',') + '}'; 348 | gap = mind; 349 | return v; 350 | } 351 | } 352 | 353 | // If the JSON object does not yet have a stringify method, give it one. 354 | 355 | if (typeof JSON.stringify !== 'function') { 356 | JSON.stringify = function (value, replacer, space) { 357 | 358 | // The stringify method takes a value and an optional replacer, and an optional 359 | // space parameter, and returns a JSON text. The replacer can be a function 360 | // that can replace values, or an array of strings that will select the keys. 361 | // A default replacer method can be provided. Use of the space parameter can 362 | // produce text that is more easily readable. 363 | 364 | var i; 365 | gap = ''; 366 | indent = ''; 367 | 368 | // If the space parameter is a number, make an indent string containing that 369 | // many spaces. 370 | 371 | if (typeof space === 'number') { 372 | for (i = 0; i < space; i += 1) { 373 | indent += ' '; 374 | } 375 | 376 | // If the space parameter is a string, it will be used as the indent string. 377 | 378 | } else if (typeof space === 'string') { 379 | indent = space; 380 | } 381 | 382 | // If there is a replacer, it must be a function or an array. 383 | // Otherwise, throw an error. 384 | 385 | rep = replacer; 386 | if (replacer && typeof replacer !== 'function' && 387 | (typeof replacer !== 'object' || 388 | typeof replacer.length !== 'number')) { 389 | throw new Error('JSON.stringify'); 390 | } 391 | 392 | // Make a fake root object containing our value under the key of ''. 393 | // Return the result of stringifying the value. 394 | 395 | return str('', {'': value}); 396 | }; 397 | } 398 | 399 | 400 | // If the JSON object does not yet have a parse method, give it one. 401 | 402 | if (typeof JSON.parse !== 'function') { 403 | JSON.parse = function (text, reviver) { 404 | 405 | // The parse method takes a text and an optional reviver function, and returns 406 | // a JavaScript value if the text is a valid JSON text. 407 | 408 | var j; 409 | 410 | function walk(holder, key) { 411 | 412 | // The walk method is used to recursively walk the resulting structure so 413 | // that modifications can be made. 414 | 415 | var k, v, value = holder[key]; 416 | if (value && typeof value === 'object') { 417 | for (k in value) { 418 | if (Object.hasOwnProperty.call(value, k)) { 419 | v = walk(value, k); 420 | if (v !== undefined) { 421 | value[k] = v; 422 | } else { 423 | delete value[k]; 424 | } 425 | } 426 | } 427 | } 428 | return reviver.call(holder, key, value); 429 | } 430 | 431 | 432 | // Parsing happens in four stages. In the first stage, we replace certain 433 | // Unicode characters with escape sequences. JavaScript handles many characters 434 | // incorrectly, either silently deleting them, or treating them as line endings. 435 | 436 | text = String(text); 437 | cx.lastIndex = 0; 438 | if (cx.test(text)) { 439 | text = text.replace(cx, function (a) { 440 | return '\\u' + 441 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 442 | }); 443 | } 444 | 445 | // In the second stage, we run the text against regular expressions that look 446 | // for non-JSON patterns. We are especially concerned with '()' and 'new' 447 | // because they can cause invocation, and '=' because it can cause mutation. 448 | // But just to be safe, we want to reject all unexpected forms. 449 | 450 | // We split the second stage into 4 regexp operations in order to work around 451 | // crippling inefficiencies in IE's and Safari's regexp engines. First we 452 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we 453 | // replace all simple value tokens with ']' characters. Third, we delete all 454 | // open brackets that follow a colon or comma or that begin the text. Finally, 455 | // we look to see that the remaining characters are only whitespace or ']' or 456 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. 457 | 458 | if (/^[\],:{}\s]*$/ 459 | .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') 460 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']') 461 | .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { 462 | 463 | // In the third stage we use the eval function to compile the text into a 464 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity 465 | // in JavaScript: it can begin a block or an object literal. We wrap the text 466 | // in parens to eliminate the ambiguity. 467 | 468 | j = eval('(' + text + ')'); 469 | 470 | // In the optional fourth stage, we recursively walk the new structure, passing 471 | // each name/value pair to a reviver function for possible transformation. 472 | 473 | 474 | return typeof reviver === 'function' ? 475 | walk({'': j}, '') : j; 476 | } 477 | 478 | // If the text is not JSON parseable, then a SyntaxError is thrown. 479 | 480 | throw new SyntaxError('JSON.parse'); 481 | }; 482 | } 483 | }()); -------------------------------------------------------------------------------- /mapmodel.js: -------------------------------------------------------------------------------- 1 | /*All code copyright 2010 by Jay Crossler unless otherwise attributed - BY/3.0 License */ 2 | 3 | var MapModel = { //object to parse JSON and update map model 4 | //MapModel.putMapIdDataName(0,MapModel.mapAsJSON(),"Tank Map","local"); 5 | //MapModel.listMaps("local") 6 | //MapModel.getMapById(0,"local"); 7 | message: 0, //hold element where messages will be added 8 | init: function(){ 9 | Message.message = document.getElementById('message'); 10 | }, 11 | getMapById: function(mapid, source) { 12 | var mapdata; 13 | if (source=="local") { //use local HTML5 Storage 14 | mapdata = localStorage.getItem("SMORGmap" + mapid); 15 | } 16 | return mapdata; 17 | }, 18 | loadMapById: function(mapid, source) { 19 | var mapdata = MapModel.getMapById(mapid, "local"); 20 | Game.createTiles(mapdata); 21 | }, 22 | putMapIdDataName: function(mapid, mapdata, mapname, source) { 23 | if (source=="local") { //use local HTML5 Storage 24 | //TODO: Check for overflow 25 | localStorage.setItem("SMORGmap" + mapid, mapdata); //saves to the database, “key”, “value” 26 | localStorage.setItem("SMORGmapName" + mapid, mapname); //saves to the database, “key”, “value” 27 | } 28 | }, 29 | saveCurrentMap: function(source) { 30 | var MapsList = MapModel.listMaps("local"); 31 | var countMaps = MapsList.length; 32 | MapModel.putMapIdDataName(countMaps, MapModel.mapAsJSON(), "Map "+countMaps,"local"); 33 | Painter.listSelectableMaps("listofmaps"); 34 | }, 35 | listMaps: function(source, filter) { 36 | var listOfMapNames = []; 37 | if (source=="local") { //use local HTML5 Storage 38 | //TODO: Temporary solution - assumes two variables saved for every map 39 | for (var i=0;i<10;i++) { 40 | var mapname = "SMORGmapName" + i; 41 | var mapdataname = localStorage.getItem(mapname); 42 | if (mapdataname) { 43 | listOfMapNames.push(mapdataname); 44 | } 45 | } 46 | } 47 | return listOfMapNames; 48 | }, 49 | deleteMap: function(mapid, source) { 50 | localStorage.removeItem("SMORGmap" + mapid); 51 | localStorage.removeItem("SMORGmapName" + mapid); 52 | Painter.listSelectableMaps("listofmaps"); 53 | }, 54 | initJSON: function(msg){ //add new message 55 | //TODO 56 | }, 57 | mapAsJSON: function(){ //add new message 58 | var strL, layer, strJSON = 59 | '{"tilesWide": ' + Game.tileEngine[0].tilesWide + ', ' + 60 | '"tilesHigh": ' + Game.tileEngine[0].tilesHigh + ', ' + 61 | '"layers": ['; 62 | for (var i=0;i'; 14 | Message.message.innerHTML += msg; 15 | console.log(msg); 16 | } 17 | }, 18 | newMessage: function(msg){ //add new message 19 | if(Message.message){ 20 | msg = '- '+msg+'
'; 21 | Message.message.innerHTML = msg; 22 | console.log(msg); 23 | } 24 | }, 25 | newMessageSingle: function(msg){ //add new message 26 | if(Message.message_single){ 27 | msg = '- '+msg; 28 | Message.message_single.innerHTML = msg; 29 | } 30 | } 31 | }; 32 | 33 | var FPS = { 34 | fps: 0, //hold element to display fps 35 | fps_count: 0, //hold frame count 36 | fps_timer: 0, //timer for FPS update (2 sec) 37 | init: function(){ 38 | FPS.fps = document.getElementById('fps'); 39 | FPS.fps_timer = setInterval(FPS.updateFPS, 2000); 40 | }, 41 | updateFPS: function(){ //add new message 42 | if(FPS.fps){ 43 | FPS.fps.innerHTML = (FPS.fps_count / 2) + 'fps (' + Game.fps + ')'; 44 | } 45 | FPS.fps_count = 0; 46 | } 47 | }; 48 | 49 | 50 | 51 | Message.init(); 52 | FPS.init(); -------------------------------------------------------------------------------- /painter.js: -------------------------------------------------------------------------------- 1 | /*All code copyright 2010 by Jay Crossler - CC BY/3.0 license */ 2 | 3 | 4 | //ToDo: Checking browser type is a kludge 5 | var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; 6 | var is_firefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; 7 | 8 | var Painter = { 9 | currentLayer: 0, 10 | tileToPaint: 0, 11 | optionPainterSelect: 0, 12 | init: function(){ 13 | drawImageOnCanvas("painter_palette","images/tiles.png"); 14 | Painter.listSelectableMaps("listofmaps"); 15 | }, 16 | addCanvasEvents: function(){ 17 | document.body.addEventListener('touchmove',ev_touch_body,false); 18 | window.addEventListener('resize',Painter.sizeCanvasToMax,false); 19 | 20 | 21 | var canv_obj = document.getElementById('main_canvas'); 22 | canv_obj.addEventListener('mousemove', ev_mousemove, false); 23 | canv_obj.addEventListener('mouseup', ev_mouseup, false); 24 | canv_obj.addEventListener('mousedown', ev_mousedown, false); 25 | canv_obj.addEventListener('touchstart', touchHandler, false); 26 | canv_obj.addEventListener('touchmove', touchHandler, false); 27 | canv_obj.addEventListener('touchend', touchHandler, false); 28 | canv_obj.addEventListener("touchcancel", touchHandler, true); 29 | 30 | 31 | var paint_obj = document.getElementById('painter_palette'); 32 | paint_obj.addEventListener('click', ev_click_painter, false); 33 | 34 | 35 | Painter.optionPainterSelect = document.getElementById('painter_layer_num'); 36 | Painter.optionPainterSelect.addEventListener('change', ev_change_painter, false); 37 | 38 | 39 | var footer_obj = document.getElementById('bottomLeft'); 40 | footer_obj.addEventListener('touchmove', ev_click_footer, false); 41 | // footer_obj.addEventListener('click', ev_click_footer, false); 42 | 43 | }, 44 | setLayerOptions: function(){ //add new message 45 | if(Painter.optionPainterSelect){ 46 | for (var i=0;i" + MapsList[i] + " " + 77 | "[DEL]
"; 78 | } 79 | listHolder.innerHTML = strItems; 80 | } 81 | 82 | 83 | }; 84 | function ev_touch_body(event) { 85 | // Tell Safari not to move the window. 86 | event.preventDefault() ; 87 | } 88 | var isfooterdown = true; 89 | function ev_click_footer(event) { 90 | var footer_obj = document.getElementById('bottomLeft'); 91 | if (isfooterdown) { 92 | footer_obj.style.height = (document.getElementById('painter_palette').height+30)+"px"; 93 | // //TODO: Make based on amount of Mouse Move 94 | footer_obj.style.width = document.getElementById('painter_palette').width+"px"; 95 | isfooterdown = false; 96 | } else { 97 | footer_obj.style.height = "60px"; 98 | footer_obj.style.width = "150px"; 99 | isfooterdown = true; 100 | } 101 | } 102 | 103 | //---------------- 104 | //From: http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript 105 | //Intercepts iOs and Android touch events, turns into drag events 106 | function touchHandler(event) 107 | { 108 | var touches = event.changedTouches, 109 | first = touches[0], 110 | type = ""; 111 | switch(event.type) 112 | { 113 | case "touchstart": type="mousedown"; break; 114 | case "touchmove": type="mousemove"; break; 115 | case "touchend": type="mouseup"; break; 116 | default: return; 117 | } 118 | 119 | //initMouseEvent(type, canBubble, cancelable, view, clickCount, 120 | // screenX, screenY, clientX, clientY, ctrlKey, 121 | // altKey, shiftKey, metaKey, button, relatedTarget); 122 | 123 | var simulatedEvent = document.createEvent("MouseEvent"); 124 | simulatedEvent.initMouseEvent(type, true, true, window, 1, 125 | first.screenX, first.screenY, 126 | first.clientX, first.clientY, false, 127 | false, false, false, 0/*left*/, null); 128 | 129 | first.target.dispatchEvent(simulatedEvent); 130 | event.preventDefault(); 131 | } 132 | 133 | //---------------- 134 | var isMouseDownOnCanvas = false; 135 | function ev_mousemove (ev) { 136 | var coords = getCoords(ev); 137 | 138 | var tilepos = MapModel.tileScreenXYBasedOnMouseOverXY(coords.x,coords.y); 139 | var zoneinf = MapModel.zoneAndTileNumBasedOnMapXY(tilepos.x, tilepos.y); 140 | var tileval = MapModel.tileValBasedOnArrayNum(MapModel.tileArrayNumBasedOnMapXY(tilepos.x, tilepos.y)); 141 | Message.newMessageSingle("Tile: " + tilepos.x + " " + tilepos.y + " - Zone:" + zoneinf.zone + " Tile:" + zoneinf.tile + " - Val:" + tileval); 142 | 143 | if(isMouseDownOnCanvas) { 144 | MapModel.updateMapTileAtXY(tilepos.x, tilepos.y, Painter.tileToPaint); 145 | Game.hasChanged = true; 146 | } 147 | }; 148 | function ev_mousedown (ev) { 149 | isMouseDownOnCanvas = true; 150 | var coords = getCoords(ev); 151 | 152 | Game.fps = 0.1; 153 | Game.startTimer(); 154 | var tiles = MapModel.tileScreenXYBasedOnMouseOverXY(coords.x,coords.y); 155 | MapModel.updateMapTileAtXY(tiles.x, tiles.y, Painter.tileToPaint); 156 | Game.hasChanged = true; 157 | 158 | }; 159 | function ev_mouseup (ev) { 160 | isMouseDownOnCanvas = false; 161 | Game.fps = Game.fpsOld; 162 | Game.startTimer(); 163 | 164 | }; 165 | //------------------- 166 | 167 | function ev_click_painter (ev) { 168 | var canvas = ev.currentTarget; 169 | var coords = getCoords(ev); 170 | 171 | var i = Painter.currentLayer; 172 | var pos_x=0, pos_y=0, tile=0, border_size=0; 173 | 174 | pos_x = Math.floor(coords.x / Game.tileEngine[i].tileWidth); 175 | pos_y = Math.ceil(coords.y / Game.tileEngine[i].tileHeight); 176 | tile = ((pos_y -1) * Game.tileEngine[i].sourceTileAcross) + pos_x; 177 | Message.newMessageSingle("Tile to paint with: #" + tile + " from layer " + i); 178 | 179 | Painter.tileToPaint = tile; 180 | }; 181 | 182 | function ev_change_painter (ev) { 183 | var i = Painter.optionPainterSelect.selectedIndex; 184 | Painter.currentLayer = i; 185 | Painter.tileToPaint = 0; 186 | drawImageOnCanvas("painter_palette",Game.tileEngine[i].sourceFiles); 187 | if (!isfooterdown) { 188 | var img = new Image(); 189 | img.onload = function(){ 190 | document.getElementById('bottomLeft').style.width = img.width+"px"; 191 | document.getElementById('bottomLeft').style.height = (img.height+30)+"px"; 192 | } 193 | img.src = Game.tileEngine[i].sourceFiles; 194 | } 195 | } 196 | 197 | 198 | //------------------- 199 | function drawImageOnCanvas(canvasid, imgsrc) { 200 | var canv= document.getElementById(canvasid); 201 | if (canv) { 202 | var ctx = canv.getContext('2d'); 203 | var img = new Image(); 204 | img.onload = function(){ 205 | canv.width = img.width; 206 | canv.height = img.height; 207 | ctx.drawImage(img,0,0); 208 | } 209 | img.src = imgsrc; 210 | } 211 | } 212 | function getCoords(e) { 213 | var posx = 0; 214 | var posy = 0; 215 | if (!e) var e = window.event; 216 | if (e.pageX || e.pageY) { 217 | posx = e.pageX; 218 | posy = e.pageY; 219 | } 220 | else if (e.clientX || e.clientY) { 221 | posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 222 | posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 223 | } 224 | 225 | if (e.currentTarget) { 226 | //ToDo: Recursively find parent's OffsetTops, not just one level up 227 | 228 | 229 | posx -= (e.currentTarget.offsetLeft + e.currentTarget.parentNode.offsetLeft) ; 230 | posy -= (e.currentTarget.offsetTop + e.currentTarget.parentNode.offsetTop); 231 | } 232 | 233 | // posx and posy contain the mouse position relative to the document 234 | // Do something with this information 235 | return {"x": posx, "y": posy}; 236 | } 237 | -------------------------------------------------------------------------------- /tilemap.js: -------------------------------------------------------------------------------- 1 | /*All code copyright 2010 by John Graham unless otherwise attributed*/ 2 | //Minor changes by Jay Crossler - CC BY/3.0 license 3 | 4 | function newSourceImage(){ //image used to create tile 5 | var SourceImage = { 6 | imageFilename: 0, //filename for image 7 | image: 0, //dom image object 8 | is_ready: 0, //is image loaded and ready to be drawn 9 | init: function(file){ 10 | try{ 11 | SourceImage.imageFilename = file; 12 | SourceImage.is_ready = false; 13 | SourceImage.image = new Image(); //create new image object 14 | //SourceImage.image.src = file; //load file into image object 15 | console.log("About to load sourceimage "+ file); 16 | Cash.loadToImg(file, SourceImage.image, false); //Added Cash saving 17 | 18 | } catch (exception) { 19 | if (exception == QUOTA_EXCEEDED_ERR) { 20 | console.log("Over cache quota!"); 21 | } else { 22 | console.log("Other exception!"); 23 | } 24 | } 25 | } 26 | }; 27 | return SourceImage; 28 | } 29 | 30 | function newTileSource(){ //image used to create tile 31 | var TileSource = { 32 | canvas: 0, //main canvas object 33 | ctx: 0, //main canvas drawing context 34 | sourceImage: 0, //image source for this tile 35 | init: function(width, height, src_x, src_y, source){ 36 | try { 37 | TileSource.sourceImage = source; //set image source 38 | TileSource.canvas = document.createElement('canvas'); 39 | TileSource.ctx = TileSource.canvas.getContext('2d'); //create main drawing canvas 40 | TileSource.canvas.setAttribute('width', width); //set tile source canvas size 41 | TileSource.canvas.setAttribute('height', height); 42 | TileSource.ctx.drawImage(TileSource.sourceImage.image, src_x, src_y, width, height, 0, 0, width, height); //draw image to tile source canvas 43 | } catch (exception) { 44 | console.log("Other exception!"); 45 | } 46 | } 47 | }; 48 | return TileSource; 49 | } 50 | 51 | /*** function to create and then return a new Tile object */ 52 | function newTile(){ 53 | var Tile = { 54 | x: 0, // X position of this tile 55 | y: 0, //Y position of this tile 56 | width: 0, //width and height of this tile 57 | height: 0, 58 | sourceIndex: 0, //index of tile source in tile engine's source array 59 | init: function(x, y, width, height, source){ //initialize sprite 60 | try { 61 | Tile.x = x; 62 | Tile.y = y; 63 | Tile.width = width; 64 | Tile.height = height; 65 | Tile.sourceIndex = source; // set index of tile source for this tile 66 | } catch (exception) { 67 | Message.addMessage("Other exception!"); 68 | } 69 | } 70 | }; 71 | return Tile; //returns newly created sprite object 72 | }; 73 | 74 | function newZone(){ 75 | var Zone = { 76 | canvas: 0, //zone canvas object 77 | tileEngine: 0, //the main tile engine object (used to fetch tile sources) 78 | ctx: 0, //zone canvas drawing context 79 | left: 0, //x position of this zone in the tile map 80 | top: 0, //y position of this zone in the tile map 81 | right: 0, //x position of right edge 82 | bottom: 0, //y position of bottom edge 83 | tileWidth: 0, 84 | tileHeight: 0, 85 | width: 0, 86 | height: 0, 87 | color: 0, 88 | tiles: 0, //array of tiles in this zone 89 | init: function(engine, left, top, tilesWide, tilesHigh, tileWidth, tileHeight, width, height){ 90 | Zone.tileEngine = engine; 91 | Zone.left = left; 92 | Zone.top = top; 93 | Zone.right = left + width; 94 | Zone.bottom = top + height; 95 | Zone.tileWidth = tileWidth; 96 | Zone.tileHeight = tileHeight; 97 | Zone.width = width; 98 | Zone.height = height; 99 | Zone.canvas = document.createElement('canvas'); 100 | Zone.ctx = Zone.canvas.getContext('2d'); //create main drawing canvas 101 | Zone.canvas.setAttribute('width', width); //set tile source canvas size 102 | Zone.canvas.setAttribute('height', height); 103 | Zone.tiles = new Array(); 104 | 105 | var r = Math.floor(Math.random() * 255); 106 | var g = Math.floor(Math.random() * 255); 107 | var b = Math.floor(Math.random() * 255); 108 | Zone.color = "rgba(" + r + "," + g + "," + b + ",.6)"; 109 | }, 110 | addTile: function(tile){ 111 | Zone.tiles.push(tile); 112 | }, 113 | arrangeTiles: function(){ 114 | var tiles_wide = Zone.width / Zone.tileWidth; 115 | var tiles_high = Zone.height / Zone.tileHeight; 116 | var index = 0; 117 | for(var i = 0; i < tiles_high; i++) 118 | { 119 | for(var j = 0; j < tiles_wide; j++) 120 | { 121 | Zone.tiles[index].x = j * Zone.tileWidth; 122 | Zone.tiles[index].y = i * Zone.tileHeight; 123 | index++; 124 | } 125 | } 126 | }, 127 | drawTiles: function(viewX, viewY, viewWidth, viewHeight){ 128 | Zone.ctx.clearRect(0,0,Zone.width, Zone.height);//clear main canvas 129 | if(Zone.tiles){ 130 | var drawTiles = new Array(); //array to hold only the tiles we are drawing 131 | var x = viewX; 132 | var y = viewY; 133 | var width = viewWidth; 134 | var height = viewHeight; 135 | for(var i = 0, ii = Zone.tiles.length; i < ii; i++){ 136 | var check_tile = Zone.tiles[i]; 137 | 138 | //check to see if each tile is outside the viewport 139 | if((check_tile.x >= width || check_tile.y >= height) ||((check_tile.x + check_tile.width) < x || (check_tile.y + check_tile.height < y))){ 140 | continue;//if it's outside, loop again 141 | } 142 | else{ 143 | drawTiles.push(check_tile); //if it's inside add it to be drawn 144 | } 145 | } 146 | //now loop through and draw only what needs to be drawn 147 | for(var j = 0, jj = drawTiles.length; j < jj; j++){ 148 | var tile = drawTiles[j]; 149 | if(Zone.tileEngine.tileSource[tile.sourceIndex]){ 150 | Zone.ctx.drawImage(Zone.tileEngine.tileSource[tile.sourceIndex].canvas, tile.x, tile.y); //draw tile based on its source index and position 151 | } 152 | } 153 | } 154 | //Added check for optional colors 155 | if(Game.tileEngine.showZoneColors) { 156 | Zone.ctx.fillStyle = Zone.color; 157 | Zone.ctx.fillRect(0,0,Zone.width, Zone.height); 158 | } 159 | } 160 | }; 161 | return Zone; 162 | } 163 | 164 | 165 | function newTileEngine(){ 166 | var TileEngine = { //main canvas and demo container 167 | canvas: 0, //main canvas object 168 | ctx: 0, //main canvas drawing context 169 | tiles: 0, //array of tiles 170 | zones: 0, //array of tile zones 171 | sources: 0, //array of source images 172 | tileSource: 0, //array of tile source objects, one for each unique tile 173 | width: 0, //width of tile map 174 | height: 0, //height of tile map 175 | zoneTilesWide: 0, //width in tiles of a zone 176 | zoneTilesHigh: 0, //height in tiles of a zone 177 | tilesHigh: 0, //height in tiles of entire map 178 | tilesWide: 0, //width in tiles of entire map 179 | tileWidth: 0, //width in pixels single tile 180 | tileHeight: 0, //height in pixels of single tile 181 | layerName: "no name", 182 | sourceFiles: 0, 183 | sourceTileCounts: 0, 184 | sourceTileAcross: 0, 185 | tileOffsetX: 0, 186 | tileOffsetY: 0, 187 | tilesArray: 0, 188 | showZoneColors: 0, 189 | init: function(){ //initialize experiment 190 | TileEngine.canvas = document.getElementById('main_canvas'); //get canvas element from html 191 | TileEngine.ctx = TileEngine.canvas.getContext('2d'); //create main drawing canvas 192 | // TileEngine.canvas.setAttribute('width', TileEngine.width); //set attributes of canvas 193 | // TileEngine.canvas.setAttribute('height', TileEngine.height); 194 | TileEngine.sources = new Array(); 195 | TileEngine.loadSource(); 196 | TileEngine.sources[0].image.onload = function(){ //event handler for image load 197 | TileEngine.sources[0].is_ready = true; // image source is ready when image is loaded 198 | TileEngine.tileSource = new Array(); 199 | TileEngine.createTileSource(TileEngine.sourceTileCounts, TileEngine.sourceTileAcross); //create tile sources using image source 200 | Game.hasChanged = true; //added to force a redraw 201 | // Cash.saveImage(TileEngine.sources[0].image.src, TileEngine.sources[0].image); //TODO: If not exist 202 | 203 | } 204 | TileEngine.tiles = new Array(); 205 | TileEngine.zones = new Array(); 206 | TileEngine.createTiles(); //create tiles - uses tilesArray declared below 207 | 208 | }, 209 | setMapAttributes: function(obj){ //this function must be called prior to initializing tile engine 210 | TileEngine.width = obj.width; 211 | TileEngine.height = obj.height; 212 | TileEngine.tileWidth = obj.tileWidth; 213 | TileEngine.tileHeight = obj.tileHeight; 214 | TileEngine.zoneTilesWide = obj.zoneTilesWide; 215 | TileEngine.zoneTilesHigh = obj.zoneTilesHigh; 216 | TileEngine.tilesWide = obj.tilesWide; 217 | TileEngine.tilesHigh = obj.tilesHigh; 218 | TileEngine.sourceFiles = obj.sourceFiles; 219 | TileEngine.sourceTileCounts = obj.sourceTileCounts; 220 | TileEngine.sourceTileAcross = obj.sourceTileAcross; 221 | TileEngine.tileOffsetX = obj.tileOffsetX; 222 | TileEngine.tileOffsetY = obj.tileOffsetY; 223 | TileEngine.tilesArray = obj.tilesArray; 224 | TileEngine.showZoneColors = obj.showZoneColors; 225 | 226 | //Added 227 | TileEngine.layerName = obj.layerName; 228 | TileEngine.startX = obj.startX; 229 | TileEngine.startY = obj.startY; 230 | }, 231 | loadSource: function(){ //create and initialize image source 232 | var source = newSourceImage(); 233 | source.init(TileEngine.sourceFiles); 234 | TileEngine.sources.push(source); 235 | }, 236 | drawFrame: function(){ //main drawing function 237 | // TileEngine.ctx.clearRect(0,0,TileEngine.width, TileEngine.height); //clear main canvas 238 | if(TileEngine.zones){ 239 | for(var i = 0, ii = TileEngine.zones.length; i < ii; i++){ 240 | var check_zone = TileEngine.zones[i]; 241 | //check to see if each zone is outside the viewport 242 | if((check_zone.x >= TileEngine.width || check_zone.y >= TileEngine.height)||((check_zone.x + check_zone.width) < TileEngine.x || (check_zone.y + check_zone.height < TileEngine.y))){ //only draw zones that are in the viewport 243 | continue;//if it's outside, loop again 244 | } 245 | else{ 246 | TileEngine.zones[i].drawTiles(0,0,TileEngine.width, TileEngine.height); 247 | TileEngine.ctx.drawImage(TileEngine.zones[i].canvas, TileEngine.zones[i].left, TileEngine.zones[i].top); 248 | } 249 | } 250 | 251 | } 252 | }, 253 | createTileSource: function(count, accross){ //create tiles sources 254 | var accross_count = 0; 255 | var x = 0; 256 | var y = 0; 257 | for(var i = 0; i < count; i++){ 258 | var new_tileSource = newTileSource(); 259 | new_tileSource.init(TileEngine.tileWidth, TileEngine.tileHeight, x, y, TileEngine.sources[0]); 260 | TileEngine.tileSource.push(new_tileSource); 261 | accross_count++; 262 | x += TileEngine.tileWidth; 263 | if(accross_count >= accross){ 264 | accross_count = 0; 265 | y += TileEngine.tileHeight; 266 | x = 0; 267 | } 268 | } 269 | }, 270 | createZones: function(){//create array of zones for map 271 | //caluculate how many zones we need (width by height) 272 | var zone_wide = Math.ceil(TileEngine.tilesWide/TileEngine.zoneTilesWide); 273 | var zone_high = Math.ceil(TileEngine.tilesHigh/TileEngine.zoneTilesHigh); 274 | 275 | /*these are used if tilemap is not evenly divisible by size of zones in tiles 276 | **they are used to define the size of zones on the right and bottom edges of the 277 | **map */ 278 | var x_remainder = TileEngine.tilesWide%TileEngine.zoneTilesWide; 279 | var y_remainder = TileEngine.tilesHigh%TileEngine.zoneTilesHigh; 280 | 281 | for(var h = 0; h < zone_high; h++){ //loop through zone rows 282 | for(var i = 0; i < zone_wide; i++) //loop through zone columns 283 | { 284 | var new_zone = newZone(); //create new zone 285 | var x = i * TileEngine.zoneTilesWide * TileEngine.tileWidth //set x pos of new zone 286 | var y = h * TileEngine.zoneTilesHigh * TileEngine.tileHeight //set y pos of new zone 287 | var width = TileEngine.zoneTilesWide * TileEngine.tileWidth; //set width of new zone 288 | var tiles_wide = TileEngine.zoneTilesWide //set tiles wide for new zone 289 | if(i == (zone_wide - 1) && x_remainder > 0) //if is last zone on horizontal row and tiles divide unevenly into zones 290 | { 291 | tiles_wide = x_remainder; //change new zone tiles wide to be correct 292 | width = tiles_wide * TileEngine.tileWidth; //change new zone width to be correct 293 | } 294 | var height = TileEngine.zoneTilesHigh * TileEngine.tileHeight; //set height of new zone 295 | var tiles_high = TileEngine.zoneTilesHigh //set tiles high for new zone 296 | if(h == (zone_high - 1) && y_remainder > 0) //if last zones on bottom and tiles divide unevenly into zones 297 | { 298 | tiles_high = y_remainder; //adjust tiles high 299 | height = tiles_high * TileEngine.tileHeight; //adjust zone height 300 | } 301 | 302 | new_zone.init(TileEngine, x, y, tiles_wide, TileEngine.zoneTilesHigh, TileEngine.tileWidth, TileEngine.tileHeight, width, height); //intitialize new zone 303 | TileEngine.zones.push(new_zone); //push zone to tile engine array 304 | } 305 | } 306 | 307 | }, 308 | createTiles: function() { //load tile array 309 | TileEngine.createZones(); //create zones 310 | var tile_index = 0; //track current position in tile array 311 | var y_zone = 0; //used to determine which zone to add tile to 312 | var x_zone = 0; //used to determine which zone to add tile to 313 | var zone_index = 0; //track current position in zone array 314 | var zone_wide = Math.ceil(TileEngine.tilesWide/TileEngine.zoneTilesWide); //how many zones are there horizontally 315 | for(var h = 0, hh = TileEngine.tilesHigh; h < hh; h++) 316 | { 317 | y_zone = Math.floor(h/TileEngine.zoneTilesHigh); //calculate which vertical zone we are in 318 | for(var i = 0, ii = TileEngine.tilesWide; i < ii; i++){ //cycle through each row 319 | 320 | x_zone = Math.floor(i/TileEngine.zoneTilesWide);// calculate which horizontal zone we are in 321 | var new_tile = newTile(); //create new tile object 322 | new_tile.init(0, 0, TileEngine.tileWidth, TileEngine.tileHeight, TileEngine.tilesArray[tile_index]); //init tile 323 | zone_index = (y_zone * zone_wide) + x_zone;//find what zone to add to using vert and horizontal positions 324 | TileEngine.zones[zone_index].addTile(new_tile); //add tile to zone 325 | tile_index++; 326 | } 327 | x_zone = 0; //reset horizontal position when we loop to new row 328 | } 329 | 330 | for(var j = 0, jj = TileEngine.zones.length; j < jj; j++){ 331 | TileEngine.zones[j].arrangeTiles(); //go throughh and arange x and y positions of tiles in zones 332 | } 333 | } 334 | } 335 | return TileEngine; 336 | }; 337 | 338 | 339 | --------------------------------------------------------------------------------