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