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 browserSupportWebGL = [sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_SAFARI]; 1567 var osSupportWebGL = [sys.OS_IOS, sys.OS_WINDOWS, sys.OS_OSX, sys.OS_LINUX]; 1568 var multipleAudioWhiteList = [ 1569 sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_BAIDU_APP, 1570 sys.BROWSER_TYPE_SAFARI, sys.BROWSER_TYPE_UC, sys.BROWSER_TYPE_QQ, sys.BROWSER_TYPE_MOBILE_QQ, sys.BROWSER_TYPE_IE 1571 ]; 1572 1573 var win = window, nav = win.navigator, doc = document, docEle = doc.documentElement; 1574 var ua = nav.userAgent.toLowerCase(); 1575 1576 /** 1577 * Indicate whether system is mobile system 1578 * @memberof cc.sys 1579 * @name isMobile 1580 * @type {Boolean} 1581 */ 1582 sys.isMobile = ua.indexOf('mobile') !== -1 || ua.indexOf('android') !== -1; 1583 1584 /** 1585 * Indicate the running platform 1586 * @memberof cc.sys 1587 * @name platform 1588 * @type {Number} 1589 */ 1590 sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER; 1591 1592 var currLanguage = nav.language; 1593 currLanguage = currLanguage ? currLanguage : nav.browserLanguage; 1594 currLanguage = currLanguage ? currLanguage.split("-")[0] : sys.LANGUAGE_ENGLISH; 1595 1596 /** 1597 * Indicate the current language of the running system 1598 * @memberof cc.sys 1599 * @name language 1600 * @type {String} 1601 */ 1602 sys.language = currLanguage; 1603 1604 var browserType = sys.BROWSER_TYPE_UNKNOWN; 1605 var browserTypes = ua.match(/sogou|qzone|liebao|micromessenger|qqbrowser|ucbrowser|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|trident|oupeng|opera|miuibrowser|firefox/i) 1606 || ua.match(/chrome|safari/i); 1607 if (browserTypes && browserTypes.length > 0) { 1608 browserType = browserTypes[0]; 1609 if (browserType === 'micromessenger') { 1610 browserType = sys.BROWSER_TYPE_WECHAT; 1611 } else if (browserType === "safari" && (ua.match(/android.*applewebkit/))) 1612 browserType = sys.BROWSER_TYPE_ANDROID; 1613 else if (browserType === "trident") browserType = sys.BROWSER_TYPE_IE; 1614 else if (browserType === "360 aphone") browserType = sys.BROWSER_TYPE_360; 1615 }else if(ua.indexOf("iphone") && ua.indexOf("mobile")){ 1616 browserType = "safari"; 1617 } 1618 /** 1619 * Indicate the running browser type 1620 * @memberof cc.sys 1621 * @name browserType 1622 * @type {String} 1623 */ 1624 sys.browserType = browserType; 1625 1626 // Get the os of system 1627 var iOS = ( ua.match(/(iPad|iPhone|iPod)/i) ? true : false ); 1628 var isAndroid = ua.match(/android/i) || nav.platform.match(/android/i) ? true : false; 1629 var osName = sys.OS_UNKNOWN; 1630 if (nav.appVersion.indexOf("Win") !== -1) osName = sys.OS_WINDOWS; 1631 else if (iOS) osName = sys.OS_IOS; 1632 else if (nav.appVersion.indexOf("Mac") !== -1) osName = sys.OS_OSX; 1633 else if (nav.appVersion.indexOf("X11") !== -1 && nav.appVersion.indexOf("Linux") === -1) osName = sys.OS_UNIX; 1634 else if (isAndroid) osName = sys.OS_ANDROID; 1635 else if (nav.appVersion.indexOf("Linux") !== -1) osName = sys.OS_LINUX; 1636 1637 /** 1638 * Indicate the running os name 1639 * @memberof cc.sys 1640 * @name os 1641 * @type {String} 1642 */ 1643 sys.os = osName; 1644 1645 sys._supportMultipleAudio = multipleAudioWhiteList.indexOf(sys.browserType) > -1; 1646 1647 1648 //++++++++++++++++++something about cc._renderTYpe and cc._supportRender begin++++++++++++++++++++++++++++ 1649 var userRenderMode = parseInt(config[CONFIG_KEY.renderMode]); 1650 var renderType = cc._RENDER_TYPE_WEBGL; 1651 var tempCanvas = cc.newElement("Canvas"); 1652 cc._supportRender = true; 1653 var notSupportGL = true; 1654 if(iOS) 1655 notSupportGL = !window.WebGLRenderingContext || osSupportWebGL.indexOf(sys.os) === -1; 1656 else 1657 notSupportGL = !window.WebGLRenderingContext || browserSupportWebGL.indexOf(sys.browserType) === -1 || osSupportWebGL.indexOf(sys.os) === -1; 1658 if (userRenderMode === 1 || (userRenderMode === 0 && notSupportGL) || (location.origin === "file://")) 1659 renderType = cc._RENDER_TYPE_CANVAS; 1660 1661 sys._canUseCanvasNewBlendModes = function(){ 1662 var canvas = document.createElement('canvas'); 1663 canvas.width = 1; 1664 canvas.height = 1; 1665 var context = canvas.getContext('2d'); 1666 context.fillStyle = '#000'; 1667 context.fillRect(0,0,1,1); 1668 context.globalCompositeOperation = 'multiply'; 1669 1670 var canvas2 = document.createElement('canvas'); 1671 canvas2.width = 1; 1672 canvas2.height = 1; 1673 var context2 = canvas2.getContext('2d'); 1674 context2.fillStyle = '#fff'; 1675 context2.fillRect(0,0,1,1); 1676 1677 context.drawImage(canvas2, 0, 0, 1, 1); 1678 1679 return context.getImageData(0,0,1,1).data[0] === 0; 1680 }; 1681 1682 //Whether or not the Canvas BlendModes are supported. 1683 sys._supportCanvasNewBlendModes = sys._canUseCanvasNewBlendModes(); 1684 1685 if (renderType === cc._RENDER_TYPE_WEBGL) { 1686 if (!win.WebGLRenderingContext 1687 || !cc.create3DContext(tempCanvas, {'stencil': true, 'preserveDrawingBuffer': true })) { 1688 if (userRenderMode === 0) renderType = cc._RENDER_TYPE_CANVAS; 1689 else cc._supportRender = false; 1690 } 1691 } 1692 1693 if (renderType === cc._RENDER_TYPE_CANVAS) { 1694 try { 1695 tempCanvas.getContext("2d"); 1696 } catch (e) { 1697 cc._supportRender = false; 1698 } 1699 } 1700 cc._renderType = renderType; 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 * Dump system informations 1785 * @memberof cc.sys 1786 * @name dump 1787 * @function 1788 */ 1789 sys.dump = function () { 1790 var self = this; 1791 var str = ""; 1792 str += "isMobile : " + self.isMobile + "\r\n"; 1793 str += "language : " + self.language + "\r\n"; 1794 str += "browserType : " + self.browserType + "\r\n"; 1795 str += "capabilities : " + JSON.stringify(self.capabilities) + "\r\n"; 1796 str += "os : " + self.os + "\r\n"; 1797 str += "platform : " + self.platform + "\r\n"; 1798 cc.log(str); 1799 } 1800 1801 /** 1802 * Open a url in browser 1803 * @memberof cc.sys 1804 * @name openURL 1805 * @param {String} url 1806 */ 1807 sys.openURL = function(url){ 1808 window.open(url); 1809 } 1810 }; 1811 1812 //+++++++++++++++++++++++++something about sys end+++++++++++++++++++++++++++++ 1813 1814 //+++++++++++++++++++++++++something about CCGame begin+++++++++++++++++++++++++++ 1815 1816 /** 1817 * Device oriented vertically, home button on the bottom 1818 * @constant 1819 * @type {Number} 1820 */ 1821 cc.ORIENTATION_PORTRAIT = 0; 1822 1823 /** 1824 * Device oriented vertically, home button on the top 1825 * @constant 1826 * @type {Number} 1827 */ 1828 cc.ORIENTATION_PORTRAIT_UPSIDE_DOWN = 1; 1829 1830 /** 1831 * Device oriented horizontally, home button on the right 1832 * @constant 1833 * @type {Number} 1834 */ 1835 cc.ORIENTATION_LANDSCAPE_LEFT = 2; 1836 1837 /** 1838 * Device oriented horizontally, home button on the left 1839 * @constant 1840 * @type {Number} 1841 */ 1842 cc.ORIENTATION_LANDSCAPE_RIGHT = 3; 1843 1844 /** 1845 * drawing primitive of game engine 1846 * @type {cc.DrawingPrimitive} 1847 */ 1848 cc._drawingUtil = null; 1849 1850 /** 1851 * main Canvas 2D/3D Context of game engine 1852 * @type {CanvasRenderingContext2D|WebGLRenderingContext} 1853 */ 1854 cc._renderContext = null; 1855 1856 /** 1857 * main Canvas of game engine 1858 * @type {HTMLCanvasElement} 1859 */ 1860 cc._canvas = null; 1861 1862 /** 1863 * This Div element contain all game canvas 1864 * @type {HTMLDivElement} 1865 */ 1866 cc._gameDiv = null; 1867 1868 cc._rendererInitialized = false; 1869 /** 1870 * <p> 1871 * setup game main canvas,renderContext,gameDiv and drawingUtil with argument <br/> 1872 * <br/> 1873 * can receive follow type of arguemnt: <br/> 1874 * - empty: create a canvas append to document's body, and setup other option <br/> 1875 * - string: search the element by document.getElementById(), <br/> 1876 * if this element is HTMLCanvasElement, set this element as main canvas of engine, and set it's ParentNode as cc._gameDiv.<br/> 1877 * if this element is HTMLDivElement, set it's ParentNode to cc._gameDiv, and create a canvas as main canvas of engine. <br/> 1878 * </p> 1879 * @function 1880 * @example 1881 * //setup with null 1882 * cc._setup(); 1883 * 1884 * // setup with HTMLCanvasElement, gameCanvas is Canvas element 1885 * // declare like this: <canvas id="gameCanvas" width="800" height="450"></canvas> 1886 * cc._setup("gameCanvas"); 1887 * 1888 * //setup with HTMLDivElement, gameDiv is Div element 1889 * // declare like this: <div id="Cocos2dGameContainer" width="800" height="450"></div> 1890 * cc._setup("Cocos2dGameContainer"); 1891 */ 1892 cc._setupCalled = false; 1893 cc._setup = function (el, width, height) { 1894 // Avoid setup to be called twice. 1895 if (cc._setupCalled) return; 1896 else cc._setupCalled = true; 1897 var win = window; 1898 var element = cc.$(el) || cc.$('#' + el); 1899 var localCanvas, localContainer, localConStyle; 1900 1901 cc.game._setAnimFrame(); 1902 1903 if (element.tagName === "CANVAS") { 1904 width = width || element.width; 1905 height = height || element.height; 1906 1907 //it is already a canvas, we wrap it around with a div 1908 localContainer = cc.container = cc.newElement("DIV"); 1909 localCanvas = cc._canvas = element; 1910 localCanvas.parentNode.insertBefore(localContainer, localCanvas); 1911 localCanvas.appendTo(localContainer); 1912 localContainer.setAttribute('id', 'Cocos2dGameContainer'); 1913 } else {//we must make a new canvas and place into this element 1914 if (element.tagName !== "DIV") { 1915 cc.log("Warning: target element is not a DIV or CANVAS"); 1916 } 1917 width = width || element.clientWidth; 1918 height = height || element.clientHeight; 1919 localContainer = cc.container = element; 1920 localCanvas = cc._canvas = cc.$(cc.newElement("CANVAS")); 1921 element.appendChild(localCanvas); 1922 } 1923 1924 localCanvas.addClass("gameCanvas"); 1925 localCanvas.setAttribute("width", width || 480); 1926 localCanvas.setAttribute("height", height || 320); 1927 localCanvas.setAttribute("tabindex", 99); 1928 localCanvas.style.outline = "none"; 1929 localConStyle = localContainer.style; 1930 localConStyle.width = (width || 480) + "px"; 1931 localConStyle.height = (height || 320) + "px"; 1932 localConStyle.margin = "0 auto"; 1933 1934 localConStyle.position = 'relative'; 1935 localConStyle.overflow = 'hidden'; 1936 localContainer.top = '100%'; 1937 1938 if (cc._renderType === cc._RENDER_TYPE_WEBGL) 1939 cc._renderContext = cc.webglContext = cc.create3DContext(localCanvas, { 1940 'stencil': true, 1941 'preserveDrawingBuffer': true, 1942 'antialias': !cc.sys.isMobile, 1943 'alpha': false 1944 }); 1945 if (cc._renderContext) { 1946 win.gl = cc._renderContext; // global variable declared in CCMacro.js 1947 cc._drawingUtil = new cc.DrawingPrimitiveWebGL(cc._renderContext); 1948 cc._rendererInitialized = true; 1949 cc.textureCache._initializingRenderer(); 1950 cc.shaderCache._init(); 1951 } else { 1952 cc._renderContext = new cc.CanvasContextWrapper(localCanvas.getContext("2d")); 1953 cc._drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(cc._renderContext) : null; 1954 } 1955 1956 cc._gameDiv = localContainer; 1957 cc.log(cc.ENGINE_VERSION); 1958 cc._setContextMenuEnable(false); 1959 1960 if (cc.sys.isMobile) { 1961 var fontStyle = cc.newElement("style"); 1962 fontStyle.type = "text/css"; 1963 document.body.appendChild(fontStyle); 1964 1965 fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;" 1966 + "-webkit-tap-highlight-color:rgba(0,0,0,0);}"; 1967 } 1968 1969 // Init singletons 1970 1971 /** 1972 * @type {cc.EGLView} 1973 * @name cc.view 1974 * cc.view is the shared view object. 1975 */ 1976 cc.view = cc.EGLView._getInstance(); 1977 // register system events 1978 cc.inputManager.registerSystemEvent(cc._canvas); 1979 1980 /** 1981 * @type {cc.Director} 1982 * @name cc.director 1983 */ 1984 cc.director = cc.Director._getInstance(); 1985 if (cc.director.setOpenGLView) 1986 cc.director.setOpenGLView(cc.view); 1987 /** 1988 * @type {cc.Size} 1989 * @name cc.winSize 1990 * cc.winSize is the alias object for the size of the current game window. 1991 */ 1992 cc.winSize = cc.director.getWinSize(); 1993 1994 // Parsers 1995 cc.saxParser = new cc.SAXParser(); 1996 /** 1997 * @type {cc.PlistParser} 1998 * @name cc.plistParser 1999 * A Plist Parser 2000 */ 2001 cc.plistParser = new cc.PlistParser(); 2002 }; 2003 2004 cc._checkWebGLRenderMode = function () { 2005 if (cc._renderType !== cc._RENDER_TYPE_WEBGL) 2006 throw "This feature supports WebGL render mode only."; 2007 }; 2008 2009 cc._isContextMenuEnable = false; 2010 /** 2011 * enable/disable contextMenu for Canvas 2012 * @param {Boolean} enabled 2013 */ 2014 cc._setContextMenuEnable = function (enabled) { 2015 cc._isContextMenuEnable = enabled; 2016 cc._canvas.oncontextmenu = function () { 2017 if (!cc._isContextMenuEnable) return false; 2018 }; 2019 }; 2020 2021 /** 2022 * An object to boot the game. 2023 * @class 2024 * @name cc.game 2025 */ 2026 cc.game = /** @lends cc.game# */{ 2027 DEBUG_MODE_NONE: 0, 2028 DEBUG_MODE_INFO: 1, 2029 DEBUG_MODE_WARN: 2, 2030 DEBUG_MODE_ERROR: 3, 2031 DEBUG_MODE_INFO_FOR_WEB_PAGE: 4, 2032 DEBUG_MODE_WARN_FOR_WEB_PAGE: 5, 2033 DEBUG_MODE_ERROR_FOR_WEB_PAGE: 6, 2034 2035 EVENT_HIDE: "game_on_hide", 2036 EVENT_SHOW: "game_on_show", 2037 _eventHide: null, 2038 _eventShow: null, 2039 _onBeforeStartArr: [], 2040 2041 /** 2042 * Key of config 2043 * @constant 2044 * @type {Object} 2045 */ 2046 CONFIG_KEY: { 2047 engineDir: "engineDir", 2048 dependencies: "dependencies", 2049 debugMode: "debugMode", 2050 showFPS: "showFPS", 2051 frameRate: "frameRate", 2052 id: "id", 2053 renderMode: "renderMode", 2054 jsList: "jsList", 2055 classReleaseMode: "classReleaseMode" 2056 }, 2057 2058 _prepareCalled: false,//whether the prepare function has been called 2059 _prepared: false,//whether the engine has prepared 2060 _paused: true,//whether the game is paused 2061 2062 _intervalId: null,//interval target of main 2063 2064 _lastTime: null, 2065 _frameTime: null, 2066 2067 /** 2068 * Config of game 2069 * @type {Object} 2070 */ 2071 config: null, 2072 2073 /** 2074 * Callback when the scripts of engine have been load. 2075 * @type {Function} 2076 */ 2077 onStart: null, 2078 2079 /** 2080 * Callback when game exits. 2081 * @type {Function} 2082 */ 2083 onStop: null, 2084 2085 /** 2086 * Set frameRate of game. 2087 * @param frameRate 2088 */ 2089 setFrameRate: function (frameRate) { 2090 var self = this, config = self.config, CONFIG_KEY = self.CONFIG_KEY; 2091 config[CONFIG_KEY.frameRate] = frameRate; 2092 if (self._intervalId) 2093 window.cancelAnimationFrame(self._intervalId); 2094 self._paused = true; 2095 self._setAnimFrame(); 2096 self._runMainLoop(); 2097 }, 2098 _setAnimFrame: function () { 2099 this._lastTime = new Date(); 2100 this._frameTime = 1000 / cc.game.config[cc.game.CONFIG_KEY.frameRate]; 2101 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) { 2102 window.requestAnimFrame = this._stTime; 2103 window.cancelAnimationFrame = this._ctTime; 2104 } 2105 else { 2106 window.requestAnimFrame = window.requestAnimationFrame || 2107 window.webkitRequestAnimationFrame || 2108 window.mozRequestAnimationFrame || 2109 window.oRequestAnimationFrame || 2110 window.msRequestAnimationFrame || 2111 this._stTime; 2112 window.cancelAnimationFrame = window.cancelAnimationFrame || 2113 window.cancelRequestAnimationFrame || 2114 window.msCancelRequestAnimationFrame || 2115 window.mozCancelRequestAnimationFrame || 2116 window.oCancelRequestAnimationFrame || 2117 window.webkitCancelRequestAnimationFrame || 2118 window.msCancelAnimationFrame || 2119 window.mozCancelAnimationFrame || 2120 window.webkitCancelAnimationFrame || 2121 window.oCancelAnimationFrame || 2122 this._ctTime; 2123 } 2124 }, 2125 _stTime: function(callback){ 2126 var currTime = new Date().getTime(); 2127 var timeToCall = Math.max(0, cc.game._frameTime - (currTime - cc.game._lastTime)); 2128 var id = window.setTimeout(function() { callback(); }, 2129 timeToCall); 2130 cc.game._lastTime = currTime + timeToCall; 2131 return id; 2132 }, 2133 _ctTime: function(id){ 2134 window.clearTimeout(id); 2135 }, 2136 //Run game. 2137 _runMainLoop: function () { 2138 var self = this, callback, config = self.config, CONFIG_KEY = self.CONFIG_KEY, 2139 director = cc.director; 2140 2141 director.setDisplayStats(config[CONFIG_KEY.showFPS]); 2142 2143 callback = function () { 2144 if (!self._paused) { 2145 director.mainLoop(); 2146 if(self._intervalId) 2147 window.cancelAnimationFrame(self._intervalId); 2148 self._intervalId = window.requestAnimFrame(callback); 2149 } 2150 }; 2151 2152 window.requestAnimFrame(callback); 2153 self._paused = false; 2154 }, 2155 2156 /** 2157 * Restart game. 2158 */ 2159 restart: function () { 2160 cc.director.popToSceneStackLevel(0); 2161 // Clean up audio 2162 cc.audioEngine && cc.audioEngine.end(); 2163 2164 cc.game.onStart(); 2165 }, 2166 2167 /** 2168 * Run game. 2169 */ 2170 run: function (id) { 2171 var self = this; 2172 var _run = function () { 2173 if (id) { 2174 self.config[self.CONFIG_KEY.id] = id; 2175 } 2176 if (!self._prepareCalled) { 2177 self.prepare(function () { 2178 self._prepared = true; 2179 }); 2180 } 2181 if (cc._supportRender) { 2182 self._checkPrepare = setInterval(function () { 2183 if (self._prepared) { 2184 cc._setup(self.config[self.CONFIG_KEY.id]); 2185 self._runMainLoop(); 2186 self._eventHide = self._eventHide || new cc.EventCustom(self.EVENT_HIDE); 2187 self._eventHide.setUserData(self); 2188 self._eventShow = self._eventShow || new cc.EventCustom(self.EVENT_SHOW); 2189 self._eventShow.setUserData(self); 2190 self.onStart(); 2191 clearInterval(self._checkPrepare); 2192 } 2193 }, 10); 2194 } 2195 }; 2196 document.body ? 2197 _run() : 2198 cc._addEventListener(window, 'load', function () { 2199 this.removeEventListener('load', arguments.callee, false); 2200 _run(); 2201 }, false); 2202 }, 2203 2204 _initConfig: function () { 2205 var self = this, CONFIG_KEY = self.CONFIG_KEY; 2206 var _init = function (cfg) { 2207 cfg[CONFIG_KEY.engineDir] = cfg[CONFIG_KEY.engineDir] || "frameworks/cocos2d-html5"; 2208 if(cfg[CONFIG_KEY.debugMode] == null) 2209 cfg[CONFIG_KEY.debugMode] = 0; 2210 cfg[CONFIG_KEY.frameRate] = cfg[CONFIG_KEY.frameRate] || 60; 2211 if(cfg[CONFIG_KEY.renderMode] == null) 2212 cfg[CONFIG_KEY.renderMode] = 1; 2213 return cfg; 2214 }; 2215 if (document["ccConfig"]) { 2216 self.config = _init(document["ccConfig"]); 2217 } else { 2218 try { 2219 var cocos_script = document.getElementsByTagName('script'); 2220 for(var i=0;i<cocos_script.length;i++){ 2221 var _t = cocos_script[i].getAttribute('cocos'); 2222 if(_t === '' || _t){break;} 2223 } 2224 var _src, txt, _resPath; 2225 if(i < cocos_script.length){ 2226 _src = cocos_script[i].src; 2227 if(_src){ 2228 _resPath = /(.*)\//.exec(_src)[0]; 2229 cc.loader.resPath = _resPath; 2230 _src = cc.path.join(_resPath, 'project.json'); 2231 } 2232 txt = cc.loader._loadTxtSync(_src); 2233 } 2234 if(!txt){ 2235 txt = cc.loader._loadTxtSync("project.json"); 2236 } 2237 var data = JSON.parse(txt); 2238 self.config = _init(data || {}); 2239 } catch (e) { 2240 cc.log("Failed to read or parse project.json"); 2241 self.config = _init({}); 2242 } 2243 } 2244 //init debug move to CCDebugger 2245 cc._initSys(self.config, CONFIG_KEY); 2246 }, 2247 2248 //cache for js and module that has added into jsList to be loaded. 2249 _jsAddedCache: {}, 2250 _getJsListOfModule: function (moduleMap, moduleName, dir) { 2251 var jsAddedCache = this._jsAddedCache; 2252 if (jsAddedCache[moduleName]) return null; 2253 dir = dir || ""; 2254 var jsList = []; 2255 var tempList = moduleMap[moduleName]; 2256 if (!tempList) throw "can not find module [" + moduleName + "]"; 2257 var ccPath = cc.path; 2258 for (var i = 0, li = tempList.length; i < li; i++) { 2259 var item = tempList[i]; 2260 if (jsAddedCache[item]) continue; 2261 var extname = ccPath.extname(item); 2262 if (!extname) { 2263 var arr = this._getJsListOfModule(moduleMap, item, dir); 2264 if (arr) jsList = jsList.concat(arr); 2265 } else if (extname.toLowerCase() === ".js") jsList.push(ccPath.join(dir, item)); 2266 jsAddedCache[item] = 1; 2267 } 2268 return jsList; 2269 }, 2270 /** 2271 * Prepare game. 2272 * @param cb 2273 */ 2274 prepare: function (cb) { 2275 var self = this; 2276 var config = self.config, CONFIG_KEY = self.CONFIG_KEY, engineDir = config[CONFIG_KEY.engineDir], loader = cc.loader; 2277 if (!cc._supportRender) { 2278 throw "The renderer doesn't support the renderMode " + config[CONFIG_KEY.renderMode]; 2279 } 2280 self._prepareCalled = true; 2281 2282 var jsList = config[CONFIG_KEY.jsList] || []; 2283 if (cc.Class) {//is single file 2284 //load user's jsList only 2285 loader.loadJsWithImg("", jsList, function (err) { 2286 if (err) throw err; 2287 self._prepared = true; 2288 if (cb) cb(); 2289 }); 2290 } else { 2291 //load cc's jsList first 2292 var ccModulesPath = cc.path.join(engineDir, "moduleConfig.json"); 2293 loader.loadJson(ccModulesPath, function (err, modulesJson) { 2294 if (err) throw err; 2295 var modules = config["modules"] || []; 2296 var moduleMap = modulesJson["module"]; 2297 var newJsList = []; 2298 if (cc._renderType === cc._RENDER_TYPE_WEBGL) modules.splice(0, 0, "shaders"); 2299 else if (modules.indexOf("core") < 0) modules.splice(0, 0, "core"); 2300 for (var i = 0, li = modules.length; i < li; i++) { 2301 var arr = self._getJsListOfModule(moduleMap, modules[i], engineDir); 2302 if (arr) newJsList = newJsList.concat(arr); 2303 } 2304 newJsList = newJsList.concat(jsList); 2305 cc.loader.loadJsWithImg(newJsList, function (err) { 2306 if (err) throw err; 2307 self._prepared = true; 2308 if (cb) cb(); 2309 }); 2310 }); 2311 } 2312 } 2313 }; 2314 cc.game._initConfig(); 2315 //+++++++++++++++++++++++++something about CCGame end+++++++++++++++++++++++++++++ 2316 2317 Function.prototype.bind = Function.prototype.bind || function (oThis) { 2318 if (!cc.isFunction(this)) { 2319 // closest thing possible to the ECMAScript 5 2320 // internal IsCallable function 2321 throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); 2322 } 2323 2324 var aArgs = Array.prototype.slice.call(arguments, 1), 2325 fToBind = this, 2326 fNOP = function () {}, 2327 fBound = function () { 2328 return fToBind.apply(this instanceof fNOP && oThis 2329 ? this 2330 : oThis, 2331 aArgs.concat(Array.prototype.slice.call(arguments))); 2332 }; 2333 2334 fNOP.prototype = this.prototype; 2335 fBound.prototype = new fNOP(); 2336 2337 return fBound; 2338 }; 2339