1 /**************************************************************************** 2 Copyright (c) 2011-2012 cocos2d-x.org 3 Copyright (c) 2013-2014 Chukong Technologies Inc. 4 5 http://www.cocos2d-x.org 6 7 Permission is hereby granted, free of charge, to any person obtaining a copy 8 of this software and associated documentation files (the "Software"), to deal 9 in the Software without restriction, including without limitation the rights 10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 copies of the Software, and to permit persons to whom the Software is 12 furnished to do so, subject to the following conditions: 13 14 The above copyright notice and this permission notice shall be included in 15 all copies or substantial portions of the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 THE SOFTWARE. 24 ****************************************************************************/ 25 26 /** 27 * The main namespace of Cocos2d-JS, all engine core classes, functions, properties and constants are defined in this namespace 28 * @namespace 29 * @name cc 30 */ 31 var cc = cc || {}; 32 cc._tmp = cc._tmp || {}; 33 cc._LogInfos = {}; 34 35 /** @expose */ 36 window._p; 37 _p = window; 38 /** @expose */ 39 _p.gl; 40 /** @expose */ 41 _p.WebGLRenderingContext; 42 /** @expose */ 43 _p.DeviceOrientationEvent; 44 /** @expose */ 45 _p.DeviceMotionEvent; 46 /** @expose */ 47 _p.AudioContext; 48 /** @expose */ 49 _p.webkitAudioContext; 50 /** @expose */ 51 _p.mozAudioContext; 52 _p = Object.prototype; 53 /** @expose */ 54 _p._super; 55 /** @expose */ 56 _p.ctor; 57 delete window._p; 58 59 cc.newElement = function (x) { 60 return document.createElement(x); 61 }; 62 63 cc._addEventListener = function (element, type, listener, useCapture) { 64 element.addEventListener(type, listener, useCapture); 65 }; 66 67 //is nodejs ? Used to support node-webkit. 68 cc._isNodeJs = typeof require !== 'undefined' && require("fs"); 69 70 /** 71 * Iterate over an object or an array, executing a function for each matched element. 72 * @param {object|array} obj 73 * @param {function} iterator 74 * @param {object} [context] 75 */ 76 cc.each = function (obj, iterator, context) { 77 if (!obj) 78 return; 79 if (obj instanceof Array) { 80 for (var i = 0, li = obj.length; i < li; i++) { 81 if (iterator.call(context, obj[i], i) === false) 82 return; 83 } 84 } else { 85 for (var key in obj) { 86 if (iterator.call(context, obj[key], key) === false) 87 return; 88 } 89 } 90 }; 91 92 /** 93 * Copy all of the properties in source objects to target object and return the target object. 94 * @param {object} target 95 * @param {object} *sources 96 * @returns {object} 97 */ 98 cc.extend = function(target) { 99 var sources = arguments.length >= 2 ? Array.prototype.slice.call(arguments, 1) : []; 100 101 cc.each(sources, function(src) { 102 for(var key in src) { 103 if (src.hasOwnProperty(key)) { 104 target[key] = src[key]; 105 } 106 } 107 }); 108 return target; 109 }; 110 111 /** 112 * Check the obj whether is function or not 113 * @param {*} obj 114 * @returns {boolean} 115 */ 116 cc.isFunction = function(obj) { 117 return typeof obj === 'function'; 118 }; 119 120 /** 121 * Check the obj whether is number or not 122 * @param {*} obj 123 * @returns {boolean} 124 */ 125 cc.isNumber = function(obj) { 126 return typeof obj === 'number' || Object.prototype.toString.call(obj) === '[object Number]'; 127 }; 128 129 /** 130 * Check the obj whether is string or not 131 * @param {*} obj 132 * @returns {boolean} 133 */ 134 cc.isString = function(obj) { 135 return typeof obj === 'string' || Object.prototype.toString.call(obj) === '[object String]'; 136 }; 137 138 /** 139 * Check the obj whether is array or not 140 * @param {*} obj 141 * @returns {boolean} 142 */ 143 cc.isArray = function(obj) { 144 return Array.isArray(obj) || 145 (typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Array]'); 146 }; 147 148 /** 149 * Check the obj whether is undefined or not 150 * @param {*} obj 151 * @returns {boolean} 152 */ 153 cc.isUndefined = function(obj) { 154 return typeof obj === 'undefined'; 155 }; 156 157 /** 158 * Check the obj whether is object or not 159 * @param {*} obj 160 * @returns {boolean} 161 */ 162 cc.isObject = function(obj) { 163 return typeof obj === "object" && Object.prototype.toString.call(obj) === '[object Object]'; 164 }; 165 166 /** 167 * Check the url whether cross origin 168 * @param {String} url 169 * @returns {boolean} 170 */ 171 cc.isCrossOrigin = function (url) { 172 if (!url) { 173 cc.log("invalid URL"); 174 return false; 175 } 176 var startIndex = url.indexOf("://"); 177 if (startIndex === -1) 178 return false; 179 180 var endIndex = url.indexOf("/", startIndex + 3); 181 var urlOrigin = (endIndex === -1) ? url : url.substring(0, endIndex); 182 return urlOrigin !== location.origin; 183 }; 184 185 //+++++++++++++++++++++++++something about async begin+++++++++++++++++++++++++++++++ 186 /** 187 * Async Pool class, a helper of cc.async 188 * @param {Object|Array} srcObj 189 * @param {Number} limit the limit of parallel number 190 * @param {function} iterator 191 * @param {function} onEnd 192 * @param {object} target 193 * @constructor 194 */ 195 cc.AsyncPool = function(srcObj, limit, iterator, onEnd, target){ 196 var self = this; 197 self._srcObj = srcObj; 198 self._limit = limit; 199 self._pool = []; 200 self._iterator = iterator; 201 self._iteratorTarget = target; 202 self._onEnd = onEnd; 203 self._onEndTarget = target; 204 self._results = srcObj instanceof Array ? [] : {}; 205 self._isErr = false; 206 207 cc.each(srcObj, function(value, index){ 208 self._pool.push({index : index, value : value}); 209 }); 210 211 self.size = self._pool.length; 212 self.finishedSize = 0; 213 self._workingSize = 0; 214 215 self._limit = self._limit || self.size; 216 217 self.onIterator = function(iterator, target){ 218 self._iterator = iterator; 219 self._iteratorTarget = target; 220 }; 221 222 self.onEnd = function(endCb, endCbTarget){ 223 self._onEnd = endCb; 224 self._onEndTarget = endCbTarget; 225 }; 226 227 self._handleItem = function(){ 228 var self = this; 229 if(self._pool.length === 0 || self._workingSize >= self._limit) 230 return; //return directly if the array's length = 0 or the working size great equal limit number 231 232 var item = self._pool.shift(); 233 var value = item.value, index = item.index; 234 self._workingSize++; 235 self._iterator.call(self._iteratorTarget, value, index, 236 function(err) { 237 if (self._isErr) 238 return; 239 240 self.finishedSize++; 241 self._workingSize--; 242 if (err) { 243 self._isErr = true; 244 if (self._onEnd) 245 self._onEnd.call(self._onEndTarget, err); 246 return; 247 } 248 249 var arr = Array.prototype.slice.call(arguments, 1); 250 self._results[this.index] = arr[0]; 251 if (self.finishedSize === self.size) { 252 if (self._onEnd) 253 self._onEnd.call(self._onEndTarget, null, self._results); 254 return; 255 } 256 self._handleItem(); 257 }.bind(item), 258 self); 259 }; 260 261 self.flow = function(){ 262 var self = this; 263 if(self._pool.length === 0) { 264 if(self._onEnd) 265 self._onEnd.call(self._onEndTarget, null, []); 266 return; 267 } 268 for(var i = 0; i < self._limit; i++) 269 self._handleItem(); 270 } 271 }; 272 273 /** 274 * @class 275 */ 276 cc.async = /** @lends cc.async# */{ 277 /** 278 * Do tasks series. 279 * @param {Array|Object} tasks 280 * @param {function} [cb] callback 281 * @param {Object} [target] 282 * @return {cc.AsyncPool} 283 */ 284 series : function(tasks, cb, target){ 285 var asyncPool = new cc.AsyncPool(tasks, 1, function(func, index, cb1){ 286 func.call(target, cb1); 287 }, cb, target); 288 asyncPool.flow(); 289 return asyncPool; 290 }, 291 292 /** 293 * Do tasks parallel. 294 * @param {Array|Object} tasks 295 * @param {function} cb callback 296 * @param {Object} [target] 297 * @return {cc.AsyncPool} 298 */ 299 parallel : function(tasks, cb, target){ 300 var asyncPool = new cc.AsyncPool(tasks, 0, function(func, index, cb1){ 301 func.call(target, cb1); 302 }, cb, target); 303 asyncPool.flow(); 304 return asyncPool; 305 }, 306 307 /** 308 * Do tasks waterfall. 309 * @param {Array|Object} tasks 310 * @param {function} cb callback 311 * @param {Object} [target] 312 * @return {cc.AsyncPool} 313 */ 314 waterfall : function(tasks, cb, target){ 315 var args = []; 316 var lastResults = [null];//the array to store the last results 317 var asyncPool = new cc.AsyncPool(tasks, 1, 318 function (func, index, cb1) { 319 args.push(function (err) { 320 args = Array.prototype.slice.call(arguments, 1); 321 if(tasks.length - 1 === index) lastResults = lastResults.concat(args);//while the last task 322 cb1.apply(null, arguments); 323 }); 324 func.apply(target, args); 325 }, function (err) { 326 if (!cb) 327 return; 328 if (err) 329 return cb.call(target, err); 330 cb.apply(target, lastResults); 331 }); 332 asyncPool.flow(); 333 return asyncPool; 334 }, 335 336 /** 337 * Do tasks by iterator. 338 * @param {Array|Object} tasks 339 * @param {function|Object} iterator 340 * @param {function} [callback] 341 * @param {Object} [target] 342 * @return {cc.AsyncPool} 343 */ 344 map : function(tasks, iterator, callback, target){ 345 var locIterator = iterator; 346 if(typeof(iterator) === "object"){ 347 callback = iterator.cb; 348 target = iterator.iteratorTarget; 349 locIterator = iterator.iterator; 350 } 351 var asyncPool = new cc.AsyncPool(tasks, 0, locIterator, callback, target); 352 asyncPool.flow(); 353 return asyncPool; 354 }, 355 356 /** 357 * Do tasks by iterator limit. 358 * @param {Array|Object} tasks 359 * @param {Number} limit 360 * @param {function} iterator 361 * @param {function} cb callback 362 * @param {Object} [target] 363 */ 364 mapLimit : function(tasks, limit, iterator, cb, target){ 365 var asyncPool = new cc.AsyncPool(tasks, limit, iterator, cb, target); 366 asyncPool.flow(); 367 return asyncPool; 368 } 369 }; 370 //+++++++++++++++++++++++++something about async end+++++++++++++++++++++++++++++++++ 371 372 //+++++++++++++++++++++++++something about path begin++++++++++++++++++++++++++++++++ 373 /** 374 * @class 375 */ 376 cc.path = /** @lends cc.path# */{ 377 /** 378 * Join strings to be a path. 379 * @example 380 cc.path.join("a", "b.png");//-->"a/b.png" 381 cc.path.join("a", "b", "c.png");//-->"a/b/c.png" 382 cc.path.join("a", "b");//-->"a/b" 383 cc.path.join("a", "b", "/");//-->"a/b/" 384 cc.path.join("a", "b/", "/");//-->"a/b/" 385 * @returns {string} 386 */ 387 join: function () { 388 var l = arguments.length; 389 var result = ""; 390 for (var i = 0; i < l; i++) { 391 result = (result + (result === "" ? "" : "/") + arguments[i]).replace(/(\/|\\\\)$/, ""); 392 } 393 return result; 394 }, 395 396 /** 397 * Get the ext name of a path. 398 * @example 399 cc.path.extname("a/b.png");//-->".png" 400 cc.path.extname("a/b.png?a=1&b=2");//-->".png" 401 cc.path.extname("a/b");//-->null 402 cc.path.extname("a/b?a=1&b=2");//-->null 403 * @param {string} pathStr 404 * @returns {*} 405 */ 406 extname: function (pathStr) { 407 var temp = /(\.[^\.\/\?\\]*)(\?.*)?$/.exec(pathStr); 408 return temp ? temp[1] : null; 409 }, 410 411 /** 412 * Get the main name of a file name 413 * @param {string} fileName 414 * @returns {string} 415 */ 416 mainFileName: function(fileName){ 417 if(fileName){ 418 var idx = fileName.lastIndexOf("."); 419 if(idx !== -1) 420 return fileName.substring(0,idx); 421 } 422 return fileName; 423 }, 424 425 /** 426 * Get the file name of a file path. 427 * @example 428 cc.path.basename("a/b.png");//-->"b.png" 429 cc.path.basename("a/b.png?a=1&b=2");//-->"b.png" 430 cc.path.basename("a/b.png", ".png");//-->"b" 431 cc.path.basename("a/b.png?a=1&b=2", ".png");//-->"b" 432 cc.path.basename("a/b.png", ".txt");//-->"b.png" 433 * @param {string} pathStr 434 * @param {string} [extname] 435 * @returns {*} 436 */ 437 basename: function (pathStr, extname) { 438 var index = pathStr.indexOf("?"); 439 if (index > 0) pathStr = pathStr.substring(0, index); 440 var reg = /(\/|\\\\)([^(\/|\\\\)]+)$/g; 441 var result = reg.exec(pathStr.replace(/(\/|\\\\)$/, "")); 442 if (!result) return null; 443 var baseName = result[2]; 444 if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() === extname.toLowerCase()) 445 return baseName.substring(0, baseName.length - extname.length); 446 return baseName; 447 }, 448 449 /** 450 * Get dirname of a file path. 451 * @example 452 * unix 453 cc.path.driname("a/b/c.png");//-->"a/b" 454 cc.path.driname("a/b/c.png?a=1&b=2");//-->"a/b" 455 cc.path.dirname("a/b/");//-->"a/b" 456 cc.path.dirname("c.png");//-->"" 457 * windows 458 cc.path.driname("a\\b\\c.png");//-->"a\b" 459 cc.path.driname("a\\b\\c.png?a=1&b=2");//-->"a\b" 460 * @param {string} pathStr 461 * @returns {*} 462 */ 463 dirname: function (pathStr) { 464 return pathStr.replace(/((.*)(\/|\\|\\\\))?(.*?\..*$)?/, '$2'); 465 }, 466 467 /** 468 * Change extname of a file path. 469 * @example 470 cc.path.changeExtname("a/b.png", ".plist");//-->"a/b.plist" 471 cc.path.changeExtname("a/b.png?a=1&b=2", ".plist");//-->"a/b.plist?a=1&b=2" 472 * @param {string} pathStr 473 * @param {string} [extname] 474 * @returns {string} 475 */ 476 changeExtname: function (pathStr, extname) { 477 extname = extname || ""; 478 var index = pathStr.indexOf("?"); 479 var tempStr = ""; 480 if (index > 0) { 481 tempStr = pathStr.substring(index); 482 pathStr = pathStr.substring(0, index); 483 } 484 index = pathStr.lastIndexOf("."); 485 if (index < 0) return pathStr + extname + tempStr; 486 return pathStr.substring(0, index) + extname + tempStr; 487 }, 488 /** 489 * Change file name of a file path. 490 * @example 491 cc.path.changeBasename("a/b/c.plist", "b.plist");//-->"a/b/b.plist" 492 cc.path.changeBasename("a/b/c.plist?a=1&b=2", "b.plist");//-->"a/b/b.plist?a=1&b=2" 493 cc.path.changeBasename("a/b/c.plist", ".png");//-->"a/b/c.png" 494 cc.path.changeBasename("a/b/c.plist", "b");//-->"a/b/b" 495 cc.path.changeBasename("a/b/c.plist", "b", true);//-->"a/b/b.plist" 496 * @param {String} pathStr 497 * @param {String} basename 498 * @param {Boolean} [isSameExt] 499 * @returns {string} 500 */ 501 changeBasename: function (pathStr, basename, isSameExt) { 502 if (basename.indexOf(".") === 0) return this.changeExtname(pathStr, basename); 503 var index = pathStr.indexOf("?"); 504 var tempStr = ""; 505 var ext = isSameExt ? this.extname(pathStr) : ""; 506 if (index > 0) { 507 tempStr = pathStr.substring(index); 508 pathStr = pathStr.substring(0, index); 509 } 510 index = pathStr.lastIndexOf("/"); 511 index = index <= 0 ? 0 : index + 1; 512 return pathStr.substring(0, index) + basename + ext + tempStr; 513 } 514 }; 515 //+++++++++++++++++++++++++something about path end++++++++++++++++++++++++++++++++ 516 517 //+++++++++++++++++++++++++something about loader start+++++++++++++++++++++++++++ 518 /** 519 * Loader for resource loading process. It's a singleton object. 520 * @class 521 */ 522 cc.loader = /** @lends cc.loader# */{ 523 _jsCache: {},//cache for js 524 _register: {},//register of loaders 525 _langPathCache: {},//cache for lang path 526 _aliases: {},//aliases for res url 527 528 resPath: "",//root path of resource 529 audioPath: "",//root path of audio 530 cache: {},//cache for data loaded 531 532 /** 533 * Get XMLHttpRequest. 534 * @returns {XMLHttpRequest} 535 */ 536 getXMLHttpRequest: function () { 537 return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP"); 538 }, 539 540 //@MODE_BEGIN DEV 541 542 _getArgs4Js: function (args) { 543 var a0 = args[0], a1 = args[1], a2 = args[2], results = ["", null, null]; 544 545 if (args.length === 1) { 546 results[1] = a0 instanceof Array ? a0 : [a0]; 547 } else if (args.length === 2) { 548 if (typeof a1 === "function") { 549 results[1] = a0 instanceof Array ? a0 : [a0]; 550 results[2] = a1; 551 } else { 552 results[0] = a0 || ""; 553 results[1] = a1 instanceof Array ? a1 : [a1]; 554 } 555 } else if (args.length === 3) { 556 results[0] = a0 || ""; 557 results[1] = a1 instanceof Array ? a1 : [a1]; 558 results[2] = a2; 559 } else throw "arguments error to load js!"; 560 return results; 561 }, 562 563 /** 564 * Load js files. 565 * If the third parameter doesn't exist, then the baseDir turns to be "". 566 * 567 * @param {string} [baseDir] The pre path for jsList or the list of js path. 568 * @param {array} jsList List of js path. 569 * @param {function} [cb] Callback function 570 * @returns {*} 571 */ 572 loadJs: function (baseDir, jsList, cb) { 573 var self = this, localJsCache = self._jsCache, 574 args = self._getArgs4Js(arguments); 575 576 var preDir = args[0], list = args[1], callback = args[2]; 577 if (navigator.userAgent.indexOf("Trident/5") > -1) { 578 self._loadJs4Dependency(preDir, list, 0, callback); 579 } else { 580 cc.async.map(list, function (item, index, cb1) { 581 var jsPath = cc.path.join(preDir, item); 582 if (localJsCache[jsPath]) return cb1(null); 583 self._createScript(jsPath, false, cb1); 584 }, callback); 585 } 586 }, 587 /** 588 * Load js width loading image. 589 * 590 * @param {string} [baseDir] 591 * @param {array} jsList 592 * @param {function} [cb] 593 */ 594 loadJsWithImg: function (baseDir, jsList, cb) { 595 var self = this, jsLoadingImg = self._loadJsImg(), 596 args = self._getArgs4Js(arguments); 597 this.loadJs(args[0], args[1], function (err) { 598 if (err) throw err; 599 jsLoadingImg.parentNode.removeChild(jsLoadingImg);//remove loading gif 600 if (args[2]) args[2](); 601 }); 602 }, 603 _createScript: function (jsPath, isAsync, cb) { 604 var d = document, self = this, s = cc.newElement('script'); 605 s.async = isAsync; 606 self._jsCache[jsPath] = true; 607 if(cc.game.config["noCache"] && typeof jsPath === "string"){ 608 if(self._noCacheRex.test(jsPath)) 609 s.src = jsPath + "&_t=" + (new Date() - 0); 610 else 611 s.src = jsPath + "?_t=" + (new Date() - 0); 612 }else{ 613 s.src = jsPath; 614 } 615 cc._addEventListener(s, 'load', function () { 616 s.parentNode.removeChild(s); 617 this.removeEventListener('load', arguments.callee, false); 618 cb(); 619 }, false); 620 cc._addEventListener(s, 'error', function () { 621 s.parentNode.removeChild(s); 622 cb("Load " + jsPath + " failed!"); 623 }, false); 624 d.body.appendChild(s); 625 }, 626 _loadJs4Dependency: function (baseDir, jsList, index, cb) { 627 if (index >= jsList.length) { 628 if (cb) cb(); 629 return; 630 } 631 var self = this; 632 self._createScript(cc.path.join(baseDir, jsList[index]), false, function (err) { 633 if (err) return cb(err); 634 self._loadJs4Dependency(baseDir, jsList, index + 1, cb); 635 }); 636 }, 637 _loadJsImg: function () { 638 var d = document, jsLoadingImg = d.getElementById("cocos2d_loadJsImg"); 639 if (!jsLoadingImg) { 640 jsLoadingImg = cc.newElement('img'); 641 642 if (cc._loadingImage) 643 jsLoadingImg.src = cc._loadingImage; 644 645 var canvasNode = d.getElementById(cc.game.config["id"]); 646 canvasNode.style.backgroundColor = "black"; 647 canvasNode.parentNode.appendChild(jsLoadingImg); 648 649 var canvasStyle = getComputedStyle ? getComputedStyle(canvasNode) : canvasNode.currentStyle; 650 if (!canvasStyle) 651 canvasStyle = {width: canvasNode.width, height: canvasNode.height}; 652 jsLoadingImg.style.left = canvasNode.offsetLeft + (parseFloat(canvasStyle.width) - jsLoadingImg.width) / 2 + "px"; 653 jsLoadingImg.style.top = canvasNode.offsetTop + (parseFloat(canvasStyle.height) - jsLoadingImg.height) / 2 + "px"; 654 jsLoadingImg.style.position = "absolute"; 655 } 656 return jsLoadingImg; 657 }, 658 //@MODE_END DEV 659 660 /** 661 * Load a single resource as txt. 662 * @param {string} url 663 * @param {function} [cb] arguments are : err, txt 664 */ 665 loadTxt: function (url, cb) { 666 if (!cc._isNodeJs) { 667 var xhr = this.getXMLHttpRequest(), 668 errInfo = "load " + url + " failed!"; 669 xhr.open("GET", url, true); 670 if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { 671 // IE-specific logic here 672 xhr.setRequestHeader("Accept-Charset", "utf-8"); 673 xhr.onreadystatechange = function () { 674 if(xhr.readyState === 4) 675 xhr.status === 200 ? cb(null, xhr.responseText) : cb(errInfo); 676 }; 677 } else { 678 if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8"); 679 xhr.onload = function () { 680 if(xhr.readyState === 4) 681 xhr.status === 200 ? cb(null, xhr.responseText) : cb(errInfo); 682 }; 683 } 684 xhr.send(null); 685 } else { 686 var fs = require("fs"); 687 fs.readFile(url, function (err, data) { 688 err ? cb(err) : cb(null, data.toString()); 689 }); 690 } 691 }, 692 _loadTxtSync: function (url) { 693 if (!cc._isNodeJs) { 694 var xhr = this.getXMLHttpRequest(); 695 xhr.open("GET", url, false); 696 if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { 697 // IE-specific logic here 698 xhr.setRequestHeader("Accept-Charset", "utf-8"); 699 } else { 700 if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8"); 701 } 702 xhr.send(null); 703 if (!xhr.readyState === 4 || xhr.status !== 200) { 704 return null; 705 } 706 return xhr.responseText; 707 } else { 708 var fs = require("fs"); 709 return fs.readFileSync(url).toString(); 710 } 711 }, 712 713 loadCsb: function(url, cb){ 714 var xhr = new XMLHttpRequest(); 715 xhr.open("GET", url, true); 716 xhr.responseType = "arraybuffer"; 717 718 xhr.onload = function () { 719 var arrayBuffer = xhr.response; // Note: not oReq.responseText 720 if (arrayBuffer) { 721 window.msg = arrayBuffer; 722 } 723 if(xhr.readyState === 4) 724 xhr.status === 200 ? cb(null, xhr.response) : cb("load " + url + " failed!"); 725 }; 726 727 xhr.send(null); 728 }, 729 730 /** 731 * Load a single resource as json. 732 * @param {string} url 733 * @param {function} [cb] arguments are : err, json 734 */ 735 loadJson: function (url, cb) { 736 this.loadTxt(url, function (err, txt) { 737 if (err) { 738 cb(err); 739 } 740 else { 741 try { 742 var result = JSON.parse(txt); 743 } 744 catch (e) { 745 throw "parse json [" + url + "] failed : " + e; 746 return; 747 } 748 cb(null, result); 749 } 750 }); 751 }, 752 753 _checkIsImageURL: function (url) { 754 var ext = /(\.png)|(\.jpg)|(\.bmp)|(\.jpeg)|(\.gif)/.exec(url); 755 return (ext != null); 756 }, 757 /** 758 * Load a single image. 759 * @param {!string} url 760 * @param {object} [option] 761 * @param {function} callback 762 * @returns {Image} 763 */ 764 loadImg: function (url, option, callback) { 765 var opt = { 766 isCrossOrigin: true 767 }; 768 if (callback !== undefined) 769 opt.isCrossOrigin = option.isCrossOrigin === null ? opt.isCrossOrigin : option.isCrossOrigin; 770 else if (option !== undefined) 771 callback = option; 772 773 var img = this.getRes(url); 774 if (img) { 775 callback && callback(null, img); 776 return img; 777 } 778 779 img = new Image(); 780 if (opt.isCrossOrigin && location.origin !== "file://") 781 img.crossOrigin = "Anonymous"; 782 783 var loadCallback = function () { 784 this.removeEventListener('load', loadCallback, false); 785 this.removeEventListener('error', errorCallback, false); 786 787 cc.loader.cache[url] = img; 788 if (callback) 789 callback(null, img); 790 }; 791 792 var self = this; 793 var errorCallback = function () { 794 this.removeEventListener('error', errorCallback, false); 795 796 if(img.crossOrigin && img.crossOrigin.toLowerCase() === "anonymous"){ 797 opt.isCrossOrigin = false; 798 self.release(url); 799 cc.loader.loadImg(url, opt, callback); 800 }else{ 801 typeof callback === "function" && callback("load image failed"); 802 } 803 }; 804 805 cc._addEventListener(img, "load", loadCallback); 806 cc._addEventListener(img, "error", errorCallback); 807 img.src = url; 808 return img; 809 }, 810 811 /** 812 * Iterator function to load res 813 * @param {object} item 814 * @param {number} index 815 * @param {function} [cb] 816 * @returns {*} 817 * @private 818 */ 819 _loadResIterator: function (item, index, cb) { 820 var self = this, url = null; 821 var type = item.type; 822 if (type) { 823 type = "." + type.toLowerCase(); 824 url = item.src ? item.src : item.name + type; 825 } else { 826 url = item; 827 type = cc.path.extname(url); 828 } 829 830 var obj = self.getRes(url); 831 if (obj) 832 return cb(null, obj); 833 var loader = null; 834 if (type) { 835 loader = self._register[type.toLowerCase()]; 836 } 837 if (!loader) { 838 cc.error("loader for [" + type + "] not exists!"); 839 return cb(); 840 } 841 var basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; 842 var realUrl = self.getUrl(basePath, url); 843 if(cc.game.config["noCache"] && typeof realUrl === "string"){ 844 if(self._noCacheRex.test(realUrl)) 845 realUrl += "&_t=" + (new Date() - 0); 846 else 847 realUrl += "?_t=" + (new Date() - 0); 848 } 849 loader.load(realUrl, url, item, function (err, data) { 850 if (err) { 851 cc.log(err); 852 self.cache[url] = null; 853 delete self.cache[url]; 854 cb(); 855 } else { 856 self.cache[url] = data; 857 cb(null, data); 858 } 859 }); 860 }, 861 _noCacheRex: /\?/, 862 863 /** 864 * Get url with basePath. 865 * @param {string} basePath 866 * @param {string} [url] 867 * @returns {*} 868 */ 869 getUrl: function (basePath, url) { 870 var self = this, langPathCache = self._langPathCache, path = cc.path; 871 if (basePath !== undefined && url === undefined) { 872 url = basePath; 873 var type = path.extname(url); 874 type = type ? type.toLowerCase() : ""; 875 var loader = self._register[type]; 876 if (!loader) 877 basePath = self.resPath; 878 else 879 basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; 880 } 881 url = cc.path.join(basePath || "", url); 882 if (url.match(/[\/(\\\\)]lang[\/(\\\\)]/i)) { 883 if (langPathCache[url]) 884 return langPathCache[url]; 885 var extname = path.extname(url) || ""; 886 url = langPathCache[url] = url.substring(0, url.length - extname.length) + "_" + cc.sys.language + extname; 887 } 888 return url; 889 }, 890 891 /** 892 * Load resources then call the callback. 893 * @param {string} resources 894 * @param {function} [option] callback or trigger 895 * @param {function|Object} [loadCallback] 896 * @return {cc.AsyncPool} 897 */ 898 load : function(resources, option, loadCallback){ 899 var self = this; 900 var len = arguments.length; 901 if(len === 0) 902 throw "arguments error!"; 903 904 if(len === 3){ 905 if(typeof option === "function"){ 906 if(typeof loadCallback === "function") 907 option = {trigger : option, cb : loadCallback }; 908 else 909 option = { cb : option, cbTarget : loadCallback}; 910 } 911 }else if(len === 2){ 912 if(typeof option === "function") 913 option = {cb : option}; 914 }else if(len === 1){ 915 option = {}; 916 } 917 918 if(!(resources instanceof Array)) 919 resources = [resources]; 920 var asyncPool = new cc.AsyncPool( 921 resources, 0, 922 function (value, index, AsyncPoolCallback, aPool) { 923 self._loadResIterator(value, index, function (err) { 924 if (err) 925 return AsyncPoolCallback(err); 926 var arr = Array.prototype.slice.call(arguments, 1); 927 if (option.trigger) 928 option.trigger.call(option.triggerTarget, arr[0], aPool.size, aPool.finishedSize); //call trigger 929 AsyncPoolCallback(null, arr[0]); 930 }); 931 }, 932 option.cb, option.cbTarget); 933 asyncPool.flow(); 934 return asyncPool; 935 }, 936 937 _handleAliases: function (fileNames, cb) { 938 var self = this, aliases = self._aliases; 939 var resList = []; 940 for (var key in fileNames) { 941 var value = fileNames[key]; 942 aliases[key] = value; 943 resList.push(value); 944 } 945 this.load(resList, cb); 946 }, 947 948 /** 949 * <p> 950 * Loads alias map from the contents of a filename. <br/> 951 * <br/> 952 * @note The plist file name should follow the format below: <br/> 953 * <?xml version="1.0" encoding="UTF-8"?> <br/> 954 * <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <br/> 955 * <plist version="1.0"> <br/> 956 * <dict> <br/> 957 * <key>filenames</key> <br/> 958 * <dict> <br/> 959 * <key>sounds/click.wav</key> <br/> 960 * <string>sounds/click.caf</string> <br/> 961 * <key>sounds/endgame.wav</key> <br/> 962 * <string>sounds/endgame.caf</string> <br/> 963 * <key>sounds/gem-0.wav</key> <br/> 964 * <string>sounds/gem-0.caf</string> <br/> 965 * </dict> <br/> 966 * <key>metadata</key> <br/> 967 * <dict> <br/> 968 * <key>version</key> <br/> 969 * <integer>1</integer> <br/> 970 * </dict> <br/> 971 * </dict> <br/> 972 * </plist> <br/> 973 * </p> 974 * @param {String} url The plist file name. 975 * @param {Function} [callback] 976 */ 977 loadAliases: function (url, callback) { 978 var self = this, dict = self.getRes(url); 979 if (!dict) { 980 self.load(url, function (err, results) { 981 self._handleAliases(results[0]["filenames"], callback); 982 }); 983 } else 984 self._handleAliases(dict["filenames"], callback); 985 }, 986 987 /** 988 * Register a resource loader into loader. 989 * @param {string} extNames 990 * @param {function} loader 991 */ 992 register: function (extNames, loader) { 993 if (!extNames || !loader) return; 994 var self = this; 995 if (typeof extNames === "string") 996 return this._register[extNames.trim().toLowerCase()] = loader; 997 for (var i = 0, li = extNames.length; i < li; i++) { 998 self._register["." + extNames[i].trim().toLowerCase()] = loader; 999 } 1000 }, 1001 1002 /** 1003 * Get resource data by url. 1004 * @param url 1005 * @returns {*} 1006 */ 1007 getRes: function (url) { 1008 return this.cache[url] || this.cache[this._aliases[url]]; 1009 }, 1010 1011 /** 1012 * Release the cache of resource by url. 1013 * @param url 1014 */ 1015 release: function (url) { 1016 var cache = this.cache, aliases = this._aliases; 1017 delete cache[url]; 1018 delete cache[aliases[url]]; 1019 delete aliases[url]; 1020 }, 1021 1022 /** 1023 * Resource cache of all resources. 1024 */ 1025 releaseAll: function () { 1026 var locCache = this.cache, aliases = this._aliases; 1027 for (var key in locCache) 1028 delete locCache[key]; 1029 for (var key in aliases) 1030 delete aliases[key]; 1031 } 1032 }; 1033 //+++++++++++++++++++++++++something about loader end+++++++++++++++++++++++++++++ 1034 1035 /** 1036 * A string tool to construct a string with format string. 1037 * for example: 1038 * cc.formatStr("a: %d, b: %b", a, b); 1039 * cc.formatStr(a, b, c); 1040 * @returns {String} 1041 */ 1042 cc.formatStr = function(){ 1043 var args = arguments; 1044 var l = args.length; 1045 if(l < 1) 1046 return ""; 1047 1048 var str = args[0]; 1049 var needToFormat = true; 1050 if(typeof str === "object"){ 1051 needToFormat = false; 1052 } 1053 for(var i = 1; i < l; ++i){ 1054 var arg = args[i]; 1055 if(needToFormat){ 1056 while(true){ 1057 var result = null; 1058 if(typeof arg === "number"){ 1059 result = str.match(/(%d)|(%s)/); 1060 if(result){ 1061 str = str.replace(/(%d)|(%s)/, arg); 1062 break; 1063 } 1064 } 1065 result = str.match(/%s/); 1066 if(result) 1067 str = str.replace(/%s/, arg); 1068 else 1069 str += " " + arg; 1070 break; 1071 } 1072 }else 1073 str += " " + arg; 1074 } 1075 return str; 1076 }; 1077 1078 1079 //+++++++++++++++++++++++++something about window events begin+++++++++++++++++++++++++++ 1080 (function () { 1081 var win = window, hidden, visibilityChange, _undef = "undefined"; 1082 if (!cc.isUndefined(document.hidden)) { 1083 hidden = "hidden"; 1084 visibilityChange = "visibilitychange"; 1085 } else if (!cc.isUndefined(document.mozHidden)) { 1086 hidden = "mozHidden"; 1087 visibilityChange = "mozvisibilitychange"; 1088 } else if (!cc.isUndefined(document.msHidden)) { 1089 hidden = "msHidden"; 1090 visibilityChange = "msvisibilitychange"; 1091 } else if (!cc.isUndefined(document.webkitHidden)) { 1092 hidden = "webkitHidden"; 1093 visibilityChange = "webkitvisibilitychange"; 1094 } 1095 1096 var onHidden = function () { 1097 if (cc.eventManager && cc.game._eventHide) 1098 cc.eventManager.dispatchEvent(cc.game._eventHide); 1099 }; 1100 var onShow = function () { 1101 if (cc.eventManager && cc.game._eventShow) 1102 cc.eventManager.dispatchEvent(cc.game._eventShow); 1103 1104 if(cc.game._intervalId){ 1105 window.cancelAnimationFrame(cc.game._intervalId); 1106 1107 cc.game._runMainLoop(); 1108 } 1109 }; 1110 1111 if (hidden) { 1112 cc._addEventListener(document, visibilityChange, function () { 1113 if (document[hidden]) onHidden(); 1114 else onShow(); 1115 }, false); 1116 } else { 1117 cc._addEventListener(win, "blur", onHidden, false); 1118 cc._addEventListener(win, "focus", onShow, false); 1119 } 1120 1121 if(navigator.userAgent.indexOf("MicroMessenger") > -1){ 1122 win.onfocus = function(){ onShow() }; 1123 } 1124 1125 if ("onpageshow" in window && "onpagehide" in window) { 1126 cc._addEventListener(win, "pagehide", onHidden, false); 1127 cc._addEventListener(win, "pageshow", onShow, false); 1128 } 1129 win = null; 1130 visibilityChange = null; 1131 })(); 1132 //+++++++++++++++++++++++++something about window events end+++++++++++++++++++++++++++++ 1133 1134 //+++++++++++++++++++++++++something about log start++++++++++++++++++++++++++++ 1135 1136 //to make sure the cc.log, cc.warn, cc.error and cc.assert would not throw error before init by debugger mode. 1137 1138 cc.log = cc.warn = cc.error = cc.assert = function () { 1139 }; 1140 1141 //+++++++++++++++++++++++++something about log end+++++++++++++++++++++++++++++ 1142 1143 /** 1144 * create a webgl context 1145 * @param {HTMLCanvasElement} canvas 1146 * @param {Object} opt_attribs 1147 * @return {WebGLRenderingContext} 1148 */ 1149 cc.create3DContext = function (canvas, opt_attribs) { 1150 var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; 1151 var context = null; 1152 for (var ii = 0; ii < names.length; ++ii) { 1153 try { 1154 context = canvas.getContext(names[ii], opt_attribs); 1155 } catch (e) { 1156 } 1157 if (context) { 1158 break; 1159 } 1160 } 1161 return context; 1162 }; 1163 //+++++++++++++++++++++++++something about sys begin+++++++++++++++++++++++++++++ 1164 cc._initSys = function (config, CONFIG_KEY) { 1165 /** 1166 * Canvas of render type 1167 * @constant 1168 * @type {Number} 1169 */ 1170 cc._RENDER_TYPE_CANVAS = 0; 1171 1172 /** 1173 * WebGL of render type 1174 * @constant 1175 * @type {Number} 1176 */ 1177 cc._RENDER_TYPE_WEBGL = 1; 1178 1179 /** 1180 * System variables 1181 * @namespace 1182 * @name cc.sys 1183 */ 1184 cc.sys = {}; 1185 var sys = cc.sys; 1186 1187 /** 1188 * English language code 1189 * @memberof cc.sys 1190 * @name LANGUAGE_ENGLISH 1191 * @constant 1192 * @type {Number} 1193 */ 1194 sys.LANGUAGE_ENGLISH = "en"; 1195 1196 /** 1197 * Chinese language code 1198 * @memberof cc.sys 1199 * @name LANGUAGE_CHINESE 1200 * @constant 1201 * @type {Number} 1202 */ 1203 sys.LANGUAGE_CHINESE = "zh"; 1204 1205 /** 1206 * French language code 1207 * @memberof cc.sys 1208 * @name LANGUAGE_FRENCH 1209 * @constant 1210 * @type {Number} 1211 */ 1212 sys.LANGUAGE_FRENCH = "fr"; 1213 1214 /** 1215 * Italian language code 1216 * @memberof cc.sys 1217 * @name LANGUAGE_ITALIAN 1218 * @constant 1219 * @type {Number} 1220 */ 1221 sys.LANGUAGE_ITALIAN = "it"; 1222 1223 /** 1224 * German language code 1225 * @memberof cc.sys 1226 * @name LANGUAGE_GERMAN 1227 * @constant 1228 * @type {Number} 1229 */ 1230 sys.LANGUAGE_GERMAN = "de"; 1231 1232 /** 1233 * Spanish language code 1234 * @memberof cc.sys 1235 * @name LANGUAGE_SPANISH 1236 * @constant 1237 * @type {Number} 1238 */ 1239 sys.LANGUAGE_SPANISH = "es"; 1240 1241 /** 1242 * Spanish language code 1243 * @memberof cc.sys 1244 * @name LANGUAGE_DUTCH 1245 * @constant 1246 * @type {Number} 1247 */ 1248 sys.LANGUAGE_DUTCH = "du"; 1249 1250 /** 1251 * Russian language code 1252 * @memberof cc.sys 1253 * @name LANGUAGE_RUSSIAN 1254 * @constant 1255 * @type {Number} 1256 */ 1257 sys.LANGUAGE_RUSSIAN = "ru"; 1258 1259 /** 1260 * Korean language code 1261 * @memberof cc.sys 1262 * @name LANGUAGE_KOREAN 1263 * @constant 1264 * @type {Number} 1265 */ 1266 sys.LANGUAGE_KOREAN = "ko"; 1267 1268 /** 1269 * Japanese language code 1270 * @memberof cc.sys 1271 * @name LANGUAGE_JAPANESE 1272 * @constant 1273 * @type {Number} 1274 */ 1275 sys.LANGUAGE_JAPANESE = "ja"; 1276 1277 /** 1278 * Hungarian language code 1279 * @memberof cc.sys 1280 * @name LANGUAGE_HUNGARIAN 1281 * @constant 1282 * @type {Number} 1283 */ 1284 sys.LANGUAGE_HUNGARIAN = "hu"; 1285 1286 /** 1287 * Portuguese language code 1288 * @memberof cc.sys 1289 * @name LANGUAGE_PORTUGUESE 1290 * @constant 1291 * @type {Number} 1292 */ 1293 sys.LANGUAGE_PORTUGUESE = "pt"; 1294 1295 /** 1296 * Arabic language code 1297 * @memberof cc.sys 1298 * @name LANGUAGE_ARABIC 1299 * @constant 1300 * @type {Number} 1301 */ 1302 sys.LANGUAGE_ARABIC = "ar"; 1303 1304 /** 1305 * Norwegian language code 1306 * @memberof cc.sys 1307 * @name LANGUAGE_NORWEGIAN 1308 * @constant 1309 * @type {Number} 1310 */ 1311 sys.LANGUAGE_NORWEGIAN = "no"; 1312 1313 /** 1314 * Polish language code 1315 * @memberof cc.sys 1316 * @name LANGUAGE_POLISH 1317 * @constant 1318 * @type {Number} 1319 */ 1320 sys.LANGUAGE_POLISH = "pl"; 1321 1322 /** 1323 * @memberof cc.sys 1324 * @name OS_IOS 1325 * @constant 1326 * @type {string} 1327 */ 1328 sys.OS_IOS = "iOS"; 1329 /** 1330 * @memberof cc.sys 1331 * @name OS_ANDROID 1332 * @constant 1333 * @type {string} 1334 */ 1335 sys.OS_ANDROID = "Android"; 1336 /** 1337 * @memberof cc.sys 1338 * @name OS_WINDOWS 1339 * @constant 1340 * @type {string} 1341 */ 1342 sys.OS_WINDOWS = "Windows"; 1343 /** 1344 * @memberof cc.sys 1345 * @name OS_MARMALADE 1346 * @constant 1347 * @type {string} 1348 */ 1349 sys.OS_MARMALADE = "Marmalade"; 1350 /** 1351 * @memberof cc.sys 1352 * @name OS_LINUX 1353 * @constant 1354 * @type {string} 1355 */ 1356 sys.OS_LINUX = "Linux"; 1357 /** 1358 * @memberof cc.sys 1359 * @name OS_BADA 1360 * @constant 1361 * @type {string} 1362 */ 1363 sys.OS_BADA = "Bada"; 1364 /** 1365 * @memberof cc.sys 1366 * @name OS_BLACKBERRY 1367 * @constant 1368 * @type {string} 1369 */ 1370 sys.OS_BLACKBERRY = "Blackberry"; 1371 /** 1372 * @memberof cc.sys 1373 * @name OS_OSX 1374 * @constant 1375 * @type {string} 1376 */ 1377 sys.OS_OSX = "OS X"; 1378 /** 1379 * @memberof cc.sys 1380 * @name OS_WP8 1381 * @constant 1382 * @type {string} 1383 */ 1384 sys.OS_WP8 = "WP8"; 1385 /** 1386 * @memberof cc.sys 1387 * @name OS_WINRT 1388 * @constant 1389 * @type {string} 1390 */ 1391 sys.OS_WINRT = "WINRT"; 1392 /** 1393 * @memberof cc.sys 1394 * @name OS_UNKNOWN 1395 * @constant 1396 * @type {string} 1397 */ 1398 sys.OS_UNKNOWN = "Unknown"; 1399 1400 /** 1401 * @memberof cc.sys 1402 * @name UNKNOWN 1403 * @constant 1404 * @default 1405 * @type {Number} 1406 */ 1407 sys.UNKNOWN = 0; 1408 /** 1409 * @memberof cc.sys 1410 * @name IOS 1411 * @constant 1412 * @default 1413 * @type {Number} 1414 */ 1415 sys.IOS = 1; 1416 /** 1417 * @memberof cc.sys 1418 * @name ANDROID 1419 * @constant 1420 * @default 1421 * @type {Number} 1422 */ 1423 sys.ANDROID = 2; 1424 /** 1425 * @memberof cc.sys 1426 * @name WIN32 1427 * @constant 1428 * @default 1429 * @type {Number} 1430 */ 1431 sys.WIN32 = 3; 1432 /** 1433 * @memberof cc.sys 1434 * @name MARMALADE 1435 * @constant 1436 * @default 1437 * @type {Number} 1438 */ 1439 sys.MARMALADE = 4; 1440 /** 1441 * @memberof cc.sys 1442 * @name LINUX 1443 * @constant 1444 * @default 1445 * @type {Number} 1446 */ 1447 sys.LINUX = 5; 1448 /** 1449 * @memberof cc.sys 1450 * @name BADA 1451 * @constant 1452 * @default 1453 * @type {Number} 1454 */ 1455 sys.BADA = 6; 1456 /** 1457 * @memberof cc.sys 1458 * @name BLACKBERRY 1459 * @constant 1460 * @default 1461 * @type {Number} 1462 */ 1463 sys.BLACKBERRY = 7; 1464 /** 1465 * @memberof cc.sys 1466 * @name MACOS 1467 * @constant 1468 * @default 1469 * @type {Number} 1470 */ 1471 sys.MACOS = 8; 1472 /** 1473 * @memberof cc.sys 1474 * @name NACL 1475 * @constant 1476 * @default 1477 * @type {Number} 1478 */ 1479 sys.NACL = 9; 1480 /** 1481 * @memberof cc.sys 1482 * @name EMSCRIPTEN 1483 * @constant 1484 * @default 1485 * @type {Number} 1486 */ 1487 sys.EMSCRIPTEN = 10; 1488 /** 1489 * @memberof cc.sys 1490 * @name TIZEN 1491 * @constant 1492 * @default 1493 * @type {Number} 1494 */ 1495 sys.TIZEN = 11; 1496 /** 1497 * @memberof cc.sys 1498 * @name QT5 1499 * @constant 1500 * @default 1501 * @type {Number} 1502 */ 1503 sys.QT5 = 12; 1504 /** 1505 * @memberof cc.sys 1506 * @name WP8 1507 * @constant 1508 * @default 1509 * @type {Number} 1510 */ 1511 sys.WP8 = 13; 1512 /** 1513 * @memberof cc.sys 1514 * @name WINRT 1515 * @constant 1516 * @default 1517 * @type {Number} 1518 */ 1519 sys.WINRT = 14; 1520 /** 1521 * @memberof cc.sys 1522 * @name MOBILE_BROWSER 1523 * @constant 1524 * @default 1525 * @type {Number} 1526 */ 1527 sys.MOBILE_BROWSER = 100; 1528 /** 1529 * @memberof cc.sys 1530 * @name DESKTOP_BROWSER 1531 * @constant 1532 * @default 1533 * @type {Number} 1534 */ 1535 sys.DESKTOP_BROWSER = 101; 1536 1537 sys.BROWSER_TYPE_WECHAT = "wechat"; 1538 sys.BROWSER_TYPE_ANDROID = "androidbrowser"; 1539 sys.BROWSER_TYPE_IE = "ie"; 1540 sys.BROWSER_TYPE_QQ = "qqbrowser"; 1541 sys.BROWSER_TYPE_MOBILE_QQ = "mqqbrowser"; 1542 sys.BROWSER_TYPE_UC = "ucbrowser"; 1543 sys.BROWSER_TYPE_360 = "360browser"; 1544 sys.BROWSER_TYPE_BAIDU_APP = "baiduboxapp"; 1545 sys.BROWSER_TYPE_BAIDU = "baidubrowser"; 1546 sys.BROWSER_TYPE_MAXTHON = "maxthon"; 1547 sys.BROWSER_TYPE_OPERA = "opera"; 1548 sys.BROWSER_TYPE_OUPENG = "oupeng"; 1549 sys.BROWSER_TYPE_MIUI = "miuibrowser"; 1550 sys.BROWSER_TYPE_FIREFOX = "firefox"; 1551 sys.BROWSER_TYPE_SAFARI = "safari"; 1552 sys.BROWSER_TYPE_CHROME = "chrome"; 1553 sys.BROWSER_TYPE_LIEBAO = "liebao"; 1554 sys.BROWSER_TYPE_QZONE = "qzone"; 1555 sys.BROWSER_TYPE_SOUGOU = "sogou"; 1556 sys.BROWSER_TYPE_UNKNOWN = "unknown"; 1557 1558 /** 1559 * Is native ? This is set to be true in jsb auto. 1560 * @memberof cc.sys 1561 * @name isNative 1562 * @type {Boolean} 1563 */ 1564 sys.isNative = false; 1565 1566 var win = window, nav = win.navigator, doc = document, docEle = doc.documentElement; 1567 var ua = nav.userAgent.toLowerCase(); 1568 1569 /** 1570 * Indicate whether system is mobile system 1571 * @memberof cc.sys 1572 * @name isMobile 1573 * @type {Boolean} 1574 */ 1575 sys.isMobile = ua.indexOf('mobile') !== -1 || ua.indexOf('android') !== -1; 1576 1577 /** 1578 * Indicate the running platform 1579 * @memberof cc.sys 1580 * @name platform 1581 * @type {Number} 1582 */ 1583 sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER; 1584 1585 var currLanguage = nav.language; 1586 currLanguage = currLanguage ? currLanguage : nav.browserLanguage; 1587 currLanguage = currLanguage ? currLanguage.split("-")[0] : sys.LANGUAGE_ENGLISH; 1588 1589 /** 1590 * Indicate the current language of the running system 1591 * @memberof cc.sys 1592 * @name language 1593 * @type {String} 1594 */ 1595 sys.language = currLanguage; 1596 1597 var browserType = sys.BROWSER_TYPE_UNKNOWN; 1598 var browserTypes = ua.match(/sogou|qzone|liebao|micromessenger|qqbrowser|ucbrowser|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|trident|oupeng|opera|miuibrowser|firefox/i) 1599 || ua.match(/chrome|safari/i); 1600 if (browserTypes && browserTypes.length > 0) { 1601 browserType = browserTypes[0]; 1602 if (browserType === 'micromessenger') { 1603 browserType = sys.BROWSER_TYPE_WECHAT; 1604 } else if (browserType === "safari" && (ua.match(/android.*applewebkit/))) 1605 browserType = sys.BROWSER_TYPE_ANDROID; 1606 else if (browserType === "trident") browserType = sys.BROWSER_TYPE_IE; 1607 else if (browserType === "360 aphone") browserType = sys.BROWSER_TYPE_360; 1608 }else if(ua.indexOf("iphone") && ua.indexOf("mobile")){ 1609 browserType = "safari"; 1610 } 1611 /** 1612 * Indicate the running browser type 1613 * @memberof cc.sys 1614 * @name browserType 1615 * @type {String} 1616 */ 1617 sys.browserType = browserType; 1618 1619 // Get the os of system 1620 var iOS = ( ua.match(/(iPad|iPhone|iPod)/i) ? true : false ); 1621 var isAndroid = ua.match(/android/i) || nav.platform.match(/android/i) ? true : false; 1622 var osName = sys.OS_UNKNOWN; 1623 if (nav.appVersion.indexOf("Win") !== -1) osName = sys.OS_WINDOWS; 1624 else if (iOS) osName = sys.OS_IOS; 1625 else if (nav.appVersion.indexOf("Mac") !== -1) osName = sys.OS_OSX; 1626 else if (nav.appVersion.indexOf("X11") !== -1 && nav.appVersion.indexOf("Linux") === -1) osName = sys.OS_UNIX; 1627 else if (isAndroid) osName = sys.OS_ANDROID; 1628 else if (nav.appVersion.indexOf("Linux") !== -1) osName = sys.OS_LINUX; 1629 1630 /** 1631 * Indicate the running os name 1632 * @memberof cc.sys 1633 * @name os 1634 * @type {String} 1635 */ 1636 sys.os = osName; 1637 1638 var multipleAudioWhiteList = [ 1639 sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_BAIDU_APP, 1640 sys.BROWSER_TYPE_SAFARI, sys.BROWSER_TYPE_UC, sys.BROWSER_TYPE_QQ, sys.BROWSER_TYPE_MOBILE_QQ, sys.BROWSER_TYPE_IE 1641 ]; 1642 1643 sys._supportMultipleAudio = multipleAudioWhiteList.indexOf(sys.browserType) > -1; 1644 1645 1646 //++++++++++++++++++something about cc._renderTYpe and cc._supportRender begin++++++++++++++++++++++++++++ 1647 1648 (function(sys, config){ 1649 var userRenderMode = config[CONFIG_KEY.renderMode] - 0; 1650 if(isNaN(userRenderMode) || userRenderMode > 2 || userRenderMode < 0) 1651 userRenderMode = 0; 1652 var shieldOs = [sys.OS_ANDROID]; 1653 var shieldBrowser = []; 1654 var tmpCanvas = cc.newElement("canvas"); 1655 cc._renderType = cc._RENDER_TYPE_CANVAS; 1656 cc._supportRender = false; 1657 1658 var supportWebGL = win.WebGLRenderingContext; 1659 1660 if(userRenderMode === 2 || (userRenderMode === 0 && supportWebGL && shieldOs.indexOf(sys.os) === -1 && shieldBrowser.indexOf(sys.browserType) === -1)) 1661 try{ 1662 var context = cc.create3DContext(tmpCanvas, {'stencil': true, 'preserveDrawingBuffer': true }); 1663 if(context){ 1664 cc._renderType = cc._RENDER_TYPE_WEBGL; 1665 cc._supportRender = true; 1666 } 1667 }catch(e){} 1668 1669 if(userRenderMode === 1 || (userRenderMode === 0 && cc._supportRender === false)) 1670 try { 1671 tmpCanvas.getContext("2d"); 1672 cc._renderType = cc._RENDER_TYPE_CANVAS; 1673 cc._supportRender = true; 1674 } catch (e) {} 1675 })(sys, config); 1676 1677 sys._canUseCanvasNewBlendModes = function(){ 1678 var canvas = document.createElement('canvas'); 1679 canvas.width = 1; 1680 canvas.height = 1; 1681 var context = canvas.getContext('2d'); 1682 context.fillStyle = '#000'; 1683 context.fillRect(0,0,1,1); 1684 context.globalCompositeOperation = 'multiply'; 1685 1686 var canvas2 = document.createElement('canvas'); 1687 canvas2.width = 1; 1688 canvas2.height = 1; 1689 var context2 = canvas2.getContext('2d'); 1690 context2.fillStyle = '#fff'; 1691 context2.fillRect(0,0,1,1); 1692 1693 context.drawImage(canvas2, 0, 0, 1, 1); 1694 1695 return context.getImageData(0,0,1,1).data[0] === 0; 1696 }; 1697 1698 //Whether or not the Canvas BlendModes are supported. 1699 sys._supportCanvasNewBlendModes = sys._canUseCanvasNewBlendModes(); 1700 1701 //++++++++++++++++++something about cc._renderType and cc._supportRender end++++++++++++++++++++++++++++++ 1702 1703 // check if browser supports Web Audio 1704 // check Web Audio's context 1705 try { 1706 sys._supportWebAudio = !!(win.AudioContext || win.webkitAudioContext || win.mozAudioContext); 1707 } catch (e) { 1708 sys._supportWebAudio = false; 1709 } 1710 1711 /** 1712 * cc.sys.localStorage is a local storage component. 1713 * @memberof cc.sys 1714 * @name localStorage 1715 * @type {Object} 1716 */ 1717 try { 1718 var localStorage = sys.localStorage = win.localStorage; 1719 localStorage.setItem("storage", ""); 1720 localStorage.removeItem("storage"); 1721 localStorage = null; 1722 } catch (e) { 1723 if (e.name === "SECURITY_ERR" || e.name === "QuotaExceededError") { 1724 cc.warn("Warning: localStorage isn't enabled. Please confirm browser cookie or privacy option"); 1725 } 1726 sys.localStorage = function () { 1727 }; 1728 } 1729 1730 var capabilities = sys.capabilities = {"canvas": true}; 1731 if (cc._renderType === cc._RENDER_TYPE_WEBGL) 1732 capabilities["opengl"] = true; 1733 if (docEle['ontouchstart'] !== undefined || doc['ontouchstart'] !== undefined || nav.msPointerEnabled) 1734 capabilities["touches"] = true; 1735 if (docEle['onmouseup'] !== undefined) 1736 capabilities["mouse"] = true; 1737 if (docEle['onkeyup'] !== undefined) 1738 capabilities["keyboard"] = true; 1739 if (win.DeviceMotionEvent || win.DeviceOrientationEvent) 1740 capabilities["accelerometer"] = true; 1741 1742 /** 1743 * Forces the garbage collection, only available in JSB 1744 * @memberof cc.sys 1745 * @name garbageCollect 1746 * @function 1747 */ 1748 sys.garbageCollect = function () { 1749 // N/A in cocos2d-html5 1750 }; 1751 1752 /** 1753 * Dumps rooted objects, only available in JSB 1754 * @memberof cc.sys 1755 * @name dumpRoot 1756 * @function 1757 */ 1758 sys.dumpRoot = function () { 1759 // N/A in cocos2d-html5 1760 }; 1761 1762 /** 1763 * Restart the JS VM, only available in JSB 1764 * @memberof cc.sys 1765 * @name restartVM 1766 * @function 1767 */ 1768 sys.restartVM = function () { 1769 // N/A in cocos2d-html5 1770 }; 1771 1772 /** 1773 * Clean a script in the JS VM, only available in JSB 1774 * @memberof cc.sys 1775 * @name cleanScript 1776 * @param {String} jsfile 1777 * @function 1778 */ 1779 sys.cleanScript = function (jsfile) { 1780 // N/A in cocos2d-html5 1781 }; 1782 1783 /** 1784 * Check whether an object is valid, 1785 * In web engine, it will return true if the object exist 1786 * In native engine, it will return true if the JS object and the correspond native object are both valid 1787 * @memberof cc.sys 1788 * @name isObjectValid 1789 * @param {Object} obj 1790 * @return {boolean} Validity of the object 1791 * @function 1792 */ 1793 sys.isObjectValid = function (obj) { 1794 if (obj) return true; 1795 else return false; 1796 }; 1797 1798 /** 1799 * Dump system informations 1800 * @memberof cc.sys 1801 * @name dump 1802 * @function 1803 */ 1804 sys.dump = function () { 1805 var self = this; 1806 var str = ""; 1807 str += "isMobile : " + self.isMobile + "\r\n"; 1808 str += "language : " + self.language + "\r\n"; 1809 str += "browserType : " + self.browserType + "\r\n"; 1810 str += "capabilities : " + JSON.stringify(self.capabilities) + "\r\n"; 1811 str += "os : " + self.os + "\r\n"; 1812 str += "platform : " + self.platform + "\r\n"; 1813 cc.log(str); 1814 } 1815 1816 /** 1817 * Open a url in browser 1818 * @memberof cc.sys 1819 * @name openURL 1820 * @param {String} url 1821 */ 1822 sys.openURL = function(url){ 1823 window.open(url); 1824 } 1825 }; 1826 1827 //+++++++++++++++++++++++++something about sys end+++++++++++++++++++++++++++++ 1828 1829 //+++++++++++++++++++++++++something about CCGame begin+++++++++++++++++++++++++++ 1830 1831 /** 1832 * Device oriented vertically, home button on the bottom 1833 * @constant 1834 * @type {Number} 1835 */ 1836 cc.ORIENTATION_PORTRAIT = 0; 1837 1838 /** 1839 * Device oriented vertically, home button on the top 1840 * @constant 1841 * @type {Number} 1842 */ 1843 cc.ORIENTATION_PORTRAIT_UPSIDE_DOWN = 1; 1844 1845 /** 1846 * Device oriented horizontally, home button on the right 1847 * @constant 1848 * @type {Number} 1849 */ 1850 cc.ORIENTATION_LANDSCAPE_LEFT = 2; 1851 1852 /** 1853 * Device oriented horizontally, home button on the left 1854 * @constant 1855 * @type {Number} 1856 */ 1857 cc.ORIENTATION_LANDSCAPE_RIGHT = 3; 1858 1859 /** 1860 * drawing primitive of game engine 1861 * @type {cc.DrawingPrimitive} 1862 */ 1863 cc._drawingUtil = null; 1864 1865 /** 1866 * main Canvas 2D/3D Context of game engine 1867 * @type {CanvasRenderingContext2D|WebGLRenderingContext} 1868 */ 1869 cc._renderContext = null; 1870 1871 /** 1872 * main Canvas of game engine 1873 * @type {HTMLCanvasElement} 1874 */ 1875 cc._canvas = null; 1876 1877 /** 1878 * This Div element contain all game canvas 1879 * @type {HTMLDivElement} 1880 */ 1881 cc._gameDiv = null; 1882 1883 cc._rendererInitialized = false; 1884 /** 1885 * <p> 1886 * setup game main canvas,renderContext,gameDiv and drawingUtil with argument <br/> 1887 * <br/> 1888 * can receive follow type of arguemnt: <br/> 1889 * - empty: create a canvas append to document's body, and setup other option <br/> 1890 * - string: search the element by document.getElementById(), <br/> 1891 * if this element is HTMLCanvasElement, set this element as main canvas of engine, and set it's ParentNode as cc._gameDiv.<br/> 1892 * if this element is HTMLDivElement, set it's ParentNode to cc._gameDiv, and create a canvas as main canvas of engine. <br/> 1893 * </p> 1894 * @function 1895 * @example 1896 * //setup with null 1897 * cc._setup(); 1898 * 1899 * // setup with HTMLCanvasElement, gameCanvas is Canvas element 1900 * // declare like this: <canvas id="gameCanvas" width="800" height="450"></canvas> 1901 * cc._setup("gameCanvas"); 1902 * 1903 * //setup with HTMLDivElement, gameDiv is Div element 1904 * // declare like this: <div id="Cocos2dGameContainer" width="800" height="450"></div> 1905 * cc._setup("Cocos2dGameContainer"); 1906 */ 1907 cc._setupCalled = false; 1908 cc._setup = function (el, width, height) { 1909 // Avoid setup to be called twice. 1910 if (cc._setupCalled) return; 1911 else cc._setupCalled = true; 1912 var win = window; 1913 var element = cc.$(el) || cc.$('#' + el); 1914 var localCanvas, localContainer, localConStyle; 1915 1916 cc.game._setAnimFrame(); 1917 1918 if (element.tagName === "CANVAS") { 1919 width = width || element.width; 1920 height = height || element.height; 1921 1922 //it is already a canvas, we wrap it around with a div 1923 localContainer = cc.container = cc.newElement("DIV"); 1924 localCanvas = cc._canvas = element; 1925 localCanvas.parentNode.insertBefore(localContainer, localCanvas); 1926 localCanvas.appendTo(localContainer); 1927 localContainer.setAttribute('id', 'Cocos2dGameContainer'); 1928 } else {//we must make a new canvas and place into this element 1929 if (element.tagName !== "DIV") { 1930 cc.log("Warning: target element is not a DIV or CANVAS"); 1931 } 1932 width = width || element.clientWidth; 1933 height = height || element.clientHeight; 1934 localContainer = cc.container = element; 1935 localCanvas = cc._canvas = cc.$(cc.newElement("CANVAS")); 1936 element.appendChild(localCanvas); 1937 } 1938 1939 localCanvas.addClass("gameCanvas"); 1940 localCanvas.setAttribute("width", width || 480); 1941 localCanvas.setAttribute("height", height || 320); 1942 localCanvas.setAttribute("tabindex", 99); 1943 localCanvas.style.outline = "none"; 1944 localConStyle = localContainer.style; 1945 localConStyle.width = (width || 480) + "px"; 1946 localConStyle.height = (height || 320) + "px"; 1947 localConStyle.margin = "0 auto"; 1948 1949 localConStyle.position = 'relative'; 1950 localConStyle.overflow = 'hidden'; 1951 localContainer.top = '100%'; 1952 1953 if (cc._renderType === cc._RENDER_TYPE_WEBGL) 1954 cc._renderContext = cc.webglContext = cc.create3DContext(localCanvas, { 1955 'stencil': true, 1956 'preserveDrawingBuffer': true, 1957 'antialias': !cc.sys.isMobile, 1958 'alpha': false 1959 }); 1960 if (cc._renderContext) { 1961 win.gl = cc._renderContext; // global variable declared in CCMacro.js 1962 cc._drawingUtil = new cc.DrawingPrimitiveWebGL(cc._renderContext); 1963 cc._rendererInitialized = true; 1964 cc.textureCache._initializingRenderer(); 1965 cc.shaderCache._init(); 1966 } else { 1967 cc._renderContext = new cc.CanvasContextWrapper(localCanvas.getContext("2d")); 1968 cc._drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(cc._renderContext) : null; 1969 } 1970 1971 cc._gameDiv = localContainer; 1972 cc.log(cc.ENGINE_VERSION); 1973 cc._setContextMenuEnable(false); 1974 1975 if (cc.sys.isMobile) { 1976 var fontStyle = cc.newElement("style"); 1977 fontStyle.type = "text/css"; 1978 document.body.appendChild(fontStyle); 1979 1980 fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;" 1981 + "-webkit-tap-highlight-color:rgba(0,0,0,0);}"; 1982 } 1983 1984 // Init singletons 1985 1986 /** 1987 * @type {cc.EGLView} 1988 * @name cc.view 1989 * cc.view is the shared view object. 1990 */ 1991 cc.view = cc.EGLView._getInstance(); 1992 // register system events 1993 cc.inputManager.registerSystemEvent(cc._canvas); 1994 1995 /** 1996 * @type {cc.Director} 1997 * @name cc.director 1998 */ 1999 cc.director = cc.Director._getInstance(); 2000 if (cc.director.setOpenGLView) 2001 cc.director.setOpenGLView(cc.view); 2002 /** 2003 * @type {cc.Size} 2004 * @name cc.winSize 2005 * cc.winSize is the alias object for the size of the current game window. 2006 */ 2007 cc.winSize = cc.director.getWinSize(); 2008 2009 // Parsers 2010 cc.saxParser = new cc.SAXParser(); 2011 /** 2012 * @type {cc.PlistParser} 2013 * @name cc.plistParser 2014 * A Plist Parser 2015 */ 2016 cc.plistParser = new cc.PlistParser(); 2017 }; 2018 2019 cc._checkWebGLRenderMode = function () { 2020 if (cc._renderType !== cc._RENDER_TYPE_WEBGL) 2021 throw "This feature supports WebGL render mode only."; 2022 }; 2023 2024 cc._isContextMenuEnable = false; 2025 /** 2026 * enable/disable contextMenu for Canvas 2027 * @param {Boolean} enabled 2028 */ 2029 cc._setContextMenuEnable = function (enabled) { 2030 cc._isContextMenuEnable = enabled; 2031 cc._canvas.oncontextmenu = function () { 2032 if (!cc._isContextMenuEnable) return false; 2033 }; 2034 }; 2035 2036 /** 2037 * An object to boot the game. 2038 * @class 2039 * @name cc.game 2040 */ 2041 cc.game = /** @lends cc.game# */{ 2042 DEBUG_MODE_NONE: 0, 2043 DEBUG_MODE_INFO: 1, 2044 DEBUG_MODE_WARN: 2, 2045 DEBUG_MODE_ERROR: 3, 2046 DEBUG_MODE_INFO_FOR_WEB_PAGE: 4, 2047 DEBUG_MODE_WARN_FOR_WEB_PAGE: 5, 2048 DEBUG_MODE_ERROR_FOR_WEB_PAGE: 6, 2049 2050 EVENT_HIDE: "game_on_hide", 2051 EVENT_SHOW: "game_on_show", 2052 _eventHide: null, 2053 _eventShow: null, 2054 _onBeforeStartArr: [], 2055 2056 /** 2057 * Key of config 2058 * @constant 2059 * @type {Object} 2060 */ 2061 CONFIG_KEY: { 2062 engineDir: "engineDir", 2063 dependencies: "dependencies", 2064 debugMode: "debugMode", 2065 showFPS: "showFPS", 2066 frameRate: "frameRate", 2067 id: "id", 2068 renderMode: "renderMode", 2069 jsList: "jsList", 2070 classReleaseMode: "classReleaseMode" 2071 }, 2072 2073 _prepareCalled: false,//whether the prepare function has been called 2074 _prepared: false,//whether the engine has prepared 2075 _paused: true,//whether the game is paused 2076 2077 _intervalId: null,//interval target of main 2078 2079 _lastTime: null, 2080 _frameTime: null, 2081 2082 /** 2083 * Config of game 2084 * @type {Object} 2085 */ 2086 config: null, 2087 2088 /** 2089 * Callback when the scripts of engine have been load. 2090 * @type {Function} 2091 */ 2092 onStart: null, 2093 2094 /** 2095 * Callback when game exits. 2096 * @type {Function} 2097 */ 2098 onStop: null, 2099 2100 /** 2101 * Set frameRate of game. 2102 * @param frameRate 2103 */ 2104 setFrameRate: function (frameRate) { 2105 var self = this, config = self.config, CONFIG_KEY = self.CONFIG_KEY; 2106 config[CONFIG_KEY.frameRate] = frameRate; 2107 if (self._intervalId) 2108 window.cancelAnimationFrame(self._intervalId); 2109 self._paused = true; 2110 self._setAnimFrame(); 2111 self._runMainLoop(); 2112 }, 2113 _setAnimFrame: function () { 2114 this._lastTime = new Date(); 2115 this._frameTime = 1000 / cc.game.config[cc.game.CONFIG_KEY.frameRate]; 2116 if((cc.sys.os === cc.sys.OS_IOS && cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT) || cc.game.config[cc.game.CONFIG_KEY.frameRate] !== 60) { 2117 window.requestAnimFrame = this._stTime; 2118 window.cancelAnimationFrame = this._ctTime; 2119 } 2120 else { 2121 window.requestAnimFrame = window.requestAnimationFrame || 2122 window.webkitRequestAnimationFrame || 2123 window.mozRequestAnimationFrame || 2124 window.oRequestAnimationFrame || 2125 window.msRequestAnimationFrame || 2126 this._stTime; 2127 window.cancelAnimationFrame = window.cancelAnimationFrame || 2128 window.cancelRequestAnimationFrame || 2129 window.msCancelRequestAnimationFrame || 2130 window.mozCancelRequestAnimationFrame || 2131 window.oCancelRequestAnimationFrame || 2132 window.webkitCancelRequestAnimationFrame || 2133 window.msCancelAnimationFrame || 2134 window.mozCancelAnimationFrame || 2135 window.webkitCancelAnimationFrame || 2136 window.oCancelAnimationFrame || 2137 this._ctTime; 2138 } 2139 }, 2140 _stTime: function(callback){ 2141 var currTime = new Date().getTime(); 2142 var timeToCall = Math.max(0, cc.game._frameTime - (currTime - cc.game._lastTime)); 2143 var id = window.setTimeout(function() { callback(); }, 2144 timeToCall); 2145 cc.game._lastTime = currTime + timeToCall; 2146 return id; 2147 }, 2148 _ctTime: function(id){ 2149 window.clearTimeout(id); 2150 }, 2151 //Run game. 2152 _runMainLoop: function () { 2153 var self = this, callback, config = self.config, CONFIG_KEY = self.CONFIG_KEY, 2154 director = cc.director; 2155 2156 director.setDisplayStats(config[CONFIG_KEY.showFPS]); 2157 2158 callback = function () { 2159 if (!self._paused) { 2160 director.mainLoop(); 2161 if(self._intervalId) 2162 window.cancelAnimationFrame(self._intervalId); 2163 self._intervalId = window.requestAnimFrame(callback); 2164 } 2165 }; 2166 2167 window.requestAnimFrame(callback); 2168 self._paused = false; 2169 }, 2170 2171 /** 2172 * Restart game. 2173 */ 2174 restart: function () { 2175 cc.director.popToSceneStackLevel(0); 2176 // Clean up audio 2177 cc.audioEngine && cc.audioEngine.end(); 2178 2179 cc.game.onStart(); 2180 }, 2181 2182 /** 2183 * Run game. 2184 */ 2185 run: function (id) { 2186 var self = this; 2187 var _run = function () { 2188 if (id) { 2189 self.config[self.CONFIG_KEY.id] = id; 2190 } 2191 if (!self._prepareCalled) { 2192 self.prepare(function () { 2193 self._prepared = true; 2194 }); 2195 } 2196 if (cc._supportRender) { 2197 self._checkPrepare = setInterval(function () { 2198 if (self._prepared) { 2199 cc._setup(self.config[self.CONFIG_KEY.id]); 2200 self._runMainLoop(); 2201 self._eventHide = self._eventHide || new cc.EventCustom(self.EVENT_HIDE); 2202 self._eventHide.setUserData(self); 2203 self._eventShow = self._eventShow || new cc.EventCustom(self.EVENT_SHOW); 2204 self._eventShow.setUserData(self); 2205 self.onStart(); 2206 clearInterval(self._checkPrepare); 2207 } 2208 }, 10); 2209 } 2210 }; 2211 document.body ? 2212 _run() : 2213 cc._addEventListener(window, 'load', function () { 2214 this.removeEventListener('load', arguments.callee, false); 2215 _run(); 2216 }, false); 2217 }, 2218 2219 _initConfig: function () { 2220 var self = this, CONFIG_KEY = self.CONFIG_KEY; 2221 var _init = function (cfg) { 2222 cfg[CONFIG_KEY.engineDir] = cfg[CONFIG_KEY.engineDir] || "frameworks/cocos2d-html5"; 2223 if(cfg[CONFIG_KEY.debugMode] == null) 2224 cfg[CONFIG_KEY.debugMode] = 0; 2225 cfg[CONFIG_KEY.frameRate] = cfg[CONFIG_KEY.frameRate] || 60; 2226 if(cfg[CONFIG_KEY.renderMode] == null) 2227 cfg[CONFIG_KEY.renderMode] = 1; 2228 return cfg; 2229 }; 2230 if (document["ccConfig"]) { 2231 self.config = _init(document["ccConfig"]); 2232 } else { 2233 try { 2234 var cocos_script = document.getElementsByTagName('script'); 2235 for(var i=0;i<cocos_script.length;i++){ 2236 var _t = cocos_script[i].getAttribute('cocos'); 2237 if(_t === '' || _t){break;} 2238 } 2239 var _src, txt, _resPath; 2240 if(i < cocos_script.length){ 2241 _src = cocos_script[i].src; 2242 if(_src){ 2243 _resPath = /(.*)\//.exec(_src)[0]; 2244 cc.loader.resPath = _resPath; 2245 _src = cc.path.join(_resPath, 'project.json'); 2246 } 2247 txt = cc.loader._loadTxtSync(_src); 2248 } 2249 if(!txt){ 2250 txt = cc.loader._loadTxtSync("project.json"); 2251 } 2252 var data = JSON.parse(txt); 2253 self.config = _init(data || {}); 2254 } catch (e) { 2255 cc.log("Failed to read or parse project.json"); 2256 self.config = _init({}); 2257 } 2258 } 2259 //init debug move to CCDebugger 2260 cc._initSys(self.config, CONFIG_KEY); 2261 }, 2262 2263 //cache for js and module that has added into jsList to be loaded. 2264 _jsAddedCache: {}, 2265 _getJsListOfModule: function (moduleMap, moduleName, dir) { 2266 var jsAddedCache = this._jsAddedCache; 2267 if (jsAddedCache[moduleName]) return null; 2268 dir = dir || ""; 2269 var jsList = []; 2270 var tempList = moduleMap[moduleName]; 2271 if (!tempList) throw "can not find module [" + moduleName + "]"; 2272 var ccPath = cc.path; 2273 for (var i = 0, li = tempList.length; i < li; i++) { 2274 var item = tempList[i]; 2275 if (jsAddedCache[item]) continue; 2276 var extname = ccPath.extname(item); 2277 if (!extname) { 2278 var arr = this._getJsListOfModule(moduleMap, item, dir); 2279 if (arr) jsList = jsList.concat(arr); 2280 } else if (extname.toLowerCase() === ".js") jsList.push(ccPath.join(dir, item)); 2281 jsAddedCache[item] = 1; 2282 } 2283 return jsList; 2284 }, 2285 /** 2286 * Prepare game. 2287 * @param cb 2288 */ 2289 prepare: function (cb) { 2290 var self = this; 2291 var config = self.config, CONFIG_KEY = self.CONFIG_KEY, engineDir = config[CONFIG_KEY.engineDir], loader = cc.loader; 2292 if (!cc._supportRender) { 2293 throw "The renderer doesn't support the renderMode " + config[CONFIG_KEY.renderMode]; 2294 } 2295 self._prepareCalled = true; 2296 2297 var jsList = config[CONFIG_KEY.jsList] || []; 2298 if (cc.Class) {//is single file 2299 //load user's jsList only 2300 loader.loadJsWithImg("", jsList, function (err) { 2301 if (err) throw err; 2302 self._prepared = true; 2303 if (cb) cb(); 2304 }); 2305 } else { 2306 //load cc's jsList first 2307 var ccModulesPath = cc.path.join(engineDir, "moduleConfig.json"); 2308 loader.loadJson(ccModulesPath, function (err, modulesJson) { 2309 if (err) throw err; 2310 var modules = config["modules"] || []; 2311 var moduleMap = modulesJson["module"]; 2312 var newJsList = []; 2313 if (cc._renderType === cc._RENDER_TYPE_WEBGL) modules.splice(0, 0, "shaders"); 2314 else if (modules.indexOf("core") < 0) modules.splice(0, 0, "core"); 2315 for (var i = 0, li = modules.length; i < li; i++) { 2316 var arr = self._getJsListOfModule(moduleMap, modules[i], engineDir); 2317 if (arr) newJsList = newJsList.concat(arr); 2318 } 2319 newJsList = newJsList.concat(jsList); 2320 cc.loader.loadJsWithImg(newJsList, function (err) { 2321 if (err) throw err; 2322 self._prepared = true; 2323 if (cb) cb(); 2324 }); 2325 }); 2326 } 2327 } 2328 }; 2329 cc.game._initConfig(); 2330 //+++++++++++++++++++++++++something about CCGame end+++++++++++++++++++++++++++++ 2331 2332 Function.prototype.bind = Function.prototype.bind || function (oThis) { 2333 if (!cc.isFunction(this)) { 2334 // closest thing possible to the ECMAScript 5 2335 // internal IsCallable function 2336 throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); 2337 } 2338 2339 var aArgs = Array.prototype.slice.call(arguments, 1), 2340 fToBind = this, 2341 fNOP = function () {}, 2342 fBound = function () { 2343 return fToBind.apply(this instanceof fNOP && oThis 2344 ? this 2345 : oThis, 2346 aArgs.concat(Array.prototype.slice.call(arguments))); 2347 }; 2348 2349 fNOP.prototype = this.prototype; 2350 fBound.prototype = new fNOP(); 2351 2352 return fBound; 2353 }; 2354