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 * Resource loading management. Created by in CCBoot.js as a singleton 571 * cc.loader. 572 * @name cc.Loader 573 * @class 574 * @memberof cc 575 * @see cc.loader 576 */ 577 578 /** 579 * Singleton instance of cc.Loader. 580 * @name cc.loader 581 * @member {cc.Loader} 582 * @memberof cc 583 */ 584 cc.loader = (function () { 585 var _jsCache = {}, //cache for js 586 _register = {}, //register of loaders 587 _langPathCache = {}, //cache for lang path 588 _aliases = {}, //aliases for res url 589 _queue = {}, // Callback queue for resources already loading 590 _urlRegExp = new RegExp( 591 "^" + 592 // protocol identifier 593 "(?:(?:https?|ftp)://)" + 594 // user:pass authentication 595 "(?:\\S+(?::\\S*)?@)?" + 596 "(?:" + 597 // IP address dotted notation octets 598 // excludes loopback network 0.0.0.0 599 // excludes reserved space >= 224.0.0.0 600 // excludes network & broacast addresses 601 // (first & last IP address of each class) 602 "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" + 603 "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" + 604 "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" + 605 "|" + 606 // host name 607 "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" + 608 // domain name 609 "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" + 610 // TLD identifier 611 "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" + 612 "|" + 613 "(?:localhost)" + 614 ")" + 615 // port number 616 "(?::\\d{2,5})?" + 617 // resource path 618 "(?:/\\S*)?" + 619 "$", "i" 620 ); 621 622 return /** @lends cc.Loader# */{ 623 /** 624 * Root path of resources. 625 * @type {String} 626 */ 627 resPath: "", 628 629 /** 630 * Root path of audio resources 631 * @type {String} 632 */ 633 audioPath: "", 634 635 /** 636 * Cache for data loaded. 637 * @type {Object} 638 */ 639 cache: {}, 640 641 /** 642 * Get XMLHttpRequest. 643 * @returns {XMLHttpRequest} 644 */ 645 getXMLHttpRequest: function () { 646 return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP"); 647 }, 648 649 //@MODE_BEGIN DEV 650 651 _getArgs4Js: function (args) { 652 var a0 = args[0], a1 = args[1], a2 = args[2], results = ["", null, null]; 653 654 if (args.length === 1) { 655 results[1] = a0 instanceof Array ? a0 : [a0]; 656 } else if (args.length === 2) { 657 if (typeof a1 === "function") { 658 results[1] = a0 instanceof Array ? a0 : [a0]; 659 results[2] = a1; 660 } else { 661 results[0] = a0 || ""; 662 results[1] = a1 instanceof Array ? a1 : [a1]; 663 } 664 } else if (args.length === 3) { 665 results[0] = a0 || ""; 666 results[1] = a1 instanceof Array ? a1 : [a1]; 667 results[2] = a2; 668 } else throw new Error("arguments error to load js!"); 669 return results; 670 }, 671 672 isLoading: function (url) { 673 return (_queue[url] !== undefined); 674 }, 675 676 /** 677 * Load js files. 678 * If the third parameter doesn't exist, then the baseDir turns to be "". 679 * 680 * @param {string} [baseDir] The pre path for jsList or the list of js path. 681 * @param {array} jsList List of js path. 682 * @param {function} [cb] Callback function 683 * @returns {*} 684 */ 685 loadJs: function (baseDir, jsList, cb) { 686 var self = this, 687 args = self._getArgs4Js(arguments); 688 689 var preDir = args[0], list = args[1], callback = args[2]; 690 if (navigator.userAgent.indexOf("Trident/5") > -1) { 691 self._loadJs4Dependency(preDir, list, 0, callback); 692 } else { 693 cc.async.map(list, function (item, index, cb1) { 694 var jsPath = cc.path.join(preDir, item); 695 if (_jsCache[jsPath]) return cb1(null); 696 self._createScript(jsPath, false, cb1); 697 }, callback); 698 } 699 }, 700 /** 701 * Load js width loading image. 702 * 703 * @param {string} [baseDir] 704 * @param {array} jsList 705 * @param {function} [cb] 706 */ 707 loadJsWithImg: function (baseDir, jsList, cb) { 708 var self = this, jsLoadingImg = self._loadJsImg(), 709 args = self._getArgs4Js(arguments); 710 this.loadJs(args[0], args[1], function (err) { 711 if (err) throw new Error(err); 712 jsLoadingImg.parentNode.removeChild(jsLoadingImg);//remove loading gif 713 if (args[2]) args[2](); 714 }); 715 }, 716 _createScript: function (jsPath, isAsync, cb) { 717 var d = document, self = this, s = document.createElement('script'); 718 s.async = isAsync; 719 _jsCache[jsPath] = true; 720 if(cc.game.config["noCache"] && typeof jsPath === "string"){ 721 if(self._noCacheRex.test(jsPath)) 722 s.src = jsPath + "&_t=" + (new Date() - 0); 723 else 724 s.src = jsPath + "?_t=" + (new Date() - 0); 725 }else{ 726 s.src = jsPath; 727 } 728 s.addEventListener('load', function () { 729 s.parentNode.removeChild(s); 730 this.removeEventListener('load', arguments.callee, false); 731 cb(); 732 }, false); 733 s.addEventListener('error', function () { 734 s.parentNode.removeChild(s); 735 cb("Load " + jsPath + " failed!"); 736 }, false); 737 d.body.appendChild(s); 738 }, 739 _loadJs4Dependency: function (baseDir, jsList, index, cb) { 740 if (index >= jsList.length) { 741 if (cb) cb(); 742 return; 743 } 744 var self = this; 745 self._createScript(cc.path.join(baseDir, jsList[index]), false, function (err) { 746 if (err) return cb(err); 747 self._loadJs4Dependency(baseDir, jsList, index + 1, cb); 748 }); 749 }, 750 _loadJsImg: function () { 751 var d = document, jsLoadingImg = d.getElementById("cocos2d_loadJsImg"); 752 if (!jsLoadingImg) { 753 jsLoadingImg = document.createElement('img'); 754 755 if (cc._loadingImage) 756 jsLoadingImg.src = cc._loadingImage; 757 758 var canvasNode = d.getElementById(cc.game.config["id"]); 759 canvasNode.style.backgroundColor = "transparent"; 760 canvasNode.parentNode.appendChild(jsLoadingImg); 761 762 var canvasStyle = getComputedStyle ? getComputedStyle(canvasNode) : canvasNode.currentStyle; 763 if (!canvasStyle) 764 canvasStyle = {width: canvasNode.width, height: canvasNode.height}; 765 jsLoadingImg.style.left = canvasNode.offsetLeft + (parseFloat(canvasStyle.width) - jsLoadingImg.width) / 2 + "px"; 766 jsLoadingImg.style.top = canvasNode.offsetTop + (parseFloat(canvasStyle.height) - jsLoadingImg.height) / 2 + "px"; 767 jsLoadingImg.style.position = "absolute"; 768 } 769 return jsLoadingImg; 770 }, 771 //@MODE_END DEV 772 773 /** 774 * Load a single resource as txt. 775 * @param {string} url 776 * @param {function} [cb] arguments are : err, txt 777 */ 778 loadTxt: function (url, cb) { 779 if (!cc._isNodeJs) { 780 var xhr = this.getXMLHttpRequest(), 781 errInfo = "load " + url + " failed!"; 782 xhr.open("GET", url, true); 783 if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { 784 // IE-specific logic here 785 xhr.setRequestHeader("Accept-Charset", "utf-8"); 786 xhr.onreadystatechange = function () { 787 if(xhr.readyState === 4) 788 xhr.status === 200 ? cb(null, xhr.responseText) : cb({status:xhr.status, errorMessage:errInfo}, null); 789 }; 790 } else { 791 if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8"); 792 xhr.onload = function () { 793 if(xhr.readyState === 4) 794 xhr.status === 200 ? cb(null, xhr.responseText) : cb({status:xhr.status, errorMessage:errInfo}, null); 795 }; 796 xhr.onerror = function(){ 797 cb({status:xhr.status, errorMessage:errInfo}, null); 798 }; 799 } 800 xhr.send(null); 801 } else { 802 var fs = require("fs"); 803 fs.readFile(url, function (err, data) { 804 err ? cb(err) : cb(null, data.toString()); 805 }); 806 } 807 }, 808 _loadTxtSync: function (url) { 809 if (!cc._isNodeJs) { 810 var xhr = this.getXMLHttpRequest(); 811 xhr.open("GET", url, false); 812 if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { 813 // IE-specific logic here 814 xhr.setRequestHeader("Accept-Charset", "utf-8"); 815 } else { 816 if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8"); 817 } 818 xhr.send(null); 819 if (!xhr.readyState === 4 || xhr.status !== 200) { 820 return null; 821 } 822 return xhr.responseText; 823 } else { 824 var fs = require("fs"); 825 return fs.readFileSync(url).toString(); 826 } 827 }, 828 829 loadCsb: function(url, cb){ 830 var xhr = new XMLHttpRequest(), 831 errInfo = "load " + url + " failed!"; 832 xhr.open("GET", url, true); 833 xhr.responseType = "arraybuffer"; 834 835 xhr.onload = function () { 836 var arrayBuffer = xhr.response; // Note: not oReq.responseText 837 if (arrayBuffer) { 838 window.msg = arrayBuffer; 839 } 840 if(xhr.readyState === 4) 841 xhr.status === 200 ? cb(null, xhr.response) : cb({status:xhr.status, errorMessage:errInfo}, null); 842 }; 843 xhr.onerror = function(){ 844 cb({status:xhr.status, errorMessage:errInfo}, null); 845 }; 846 xhr.send(null); 847 }, 848 849 /** 850 * Load a single resource as json. 851 * @param {string} url 852 * @param {function} [cb] arguments are : err, json 853 */ 854 loadJson: function (url, cb) { 855 this.loadTxt(url, function (err, txt) { 856 if (err) { 857 cb(err); 858 } 859 else { 860 try { 861 var result = JSON.parse(txt); 862 } 863 catch (e) { 864 throw new Error("parse json [" + url + "] failed : " + e); 865 return; 866 } 867 cb(null, result); 868 } 869 }); 870 }, 871 872 _checkIsImageURL: function (url) { 873 var ext = /(\.png)|(\.jpg)|(\.bmp)|(\.jpeg)|(\.gif)/.exec(url); 874 return (ext != null); 875 }, 876 /** 877 * Load a single image. 878 * @param {!string} url 879 * @param {object} [option] 880 * @param {function} callback 881 * @returns {Image} 882 */ 883 loadImg: function (url, option, callback) { 884 var opt = { 885 isCrossOrigin: true 886 }; 887 if (callback !== undefined) 888 opt.isCrossOrigin = option.isCrossOrigin === undefined ? opt.isCrossOrigin : option.isCrossOrigin; 889 else if (option !== undefined) 890 callback = option; 891 892 var img = this.getRes(url); 893 if (img) { 894 callback && callback(null, img); 895 return img; 896 } 897 898 var queue = _queue[url]; 899 if (queue) { 900 queue.callbacks.push(callback); 901 return queue.img; 902 } 903 904 img = new Image(); 905 if (opt.isCrossOrigin && location.origin !== "file://") 906 img.crossOrigin = "Anonymous"; 907 908 var loadCallback = function () { 909 this.removeEventListener('load', loadCallback, false); 910 this.removeEventListener('error', errorCallback, false); 911 912 if (!_urlRegExp.test(url)) { 913 cc.loader.cache[url] = img; 914 } 915 916 var queue = _queue[url]; 917 if (queue) { 918 callbacks = queue.callbacks; 919 for (var i = 0; i < callbacks.length; ++i) { 920 var cb = callbacks[i]; 921 if (cb) { 922 cb(null, img); 923 } 924 } 925 queue.img = null; 926 delete _queue[url]; 927 } 928 }; 929 930 var self = this; 931 var errorCallback = function () { 932 this.removeEventListener('error', errorCallback, false); 933 934 if (img.crossOrigin && img.crossOrigin.toLowerCase() === "anonymous") { 935 opt.isCrossOrigin = false; 936 self.release(url); 937 cc.loader.loadImg(url, opt, callback); 938 } else { 939 var queue = _queue[url]; 940 if (queue) { 941 callbacks = queue.callbacks; 942 for (var i = 0; i < callbacks.length; ++i) { 943 var cb = callbacks[i]; 944 if (cb) { 945 cb("load image failed"); 946 } 947 } 948 queue.img = null; 949 delete _queue[url]; 950 } 951 } 952 }; 953 954 _queue[url] = { 955 img: img, 956 callbacks: callback ? [callback] : [] 957 }; 958 959 img.addEventListener("load", loadCallback); 960 img.addEventListener("error", errorCallback); 961 img.src = url; 962 return img; 963 }, 964 965 /** 966 * Iterator function to load res 967 * @param {object} item 968 * @param {number} index 969 * @param {function} [cb] 970 * @returns {*} 971 * @private 972 */ 973 _loadResIterator: function (item, index, cb) { 974 var self = this, url = null; 975 var type = item.type; 976 if (type) { 977 type = "." + type.toLowerCase(); 978 url = item.src ? item.src : item.name + type; 979 } else { 980 url = item; 981 type = cc.path.extname(url); 982 } 983 984 var obj = self.getRes(url); 985 if (obj) 986 return cb(null, obj); 987 var loader = null; 988 if (type) { 989 loader = _register[type.toLowerCase()]; 990 } 991 if (!loader) { 992 cc.error("loader for [" + type + "] not exists!"); 993 return cb(); 994 } 995 var realUrl = url; 996 if (!_urlRegExp.test(url)) 997 { 998 var basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; 999 realUrl = self.getUrl(basePath, url); 1000 } 1001 1002 if(cc.game.config["noCache"] && typeof realUrl === "string"){ 1003 if(self._noCacheRex.test(realUrl)) 1004 realUrl += "&_t=" + (new Date() - 0); 1005 else 1006 realUrl += "?_t=" + (new Date() - 0); 1007 } 1008 loader.load(realUrl, url, item, function (err, data) { 1009 if (err) { 1010 cc.log(err); 1011 self.cache[url] = null; 1012 delete self.cache[url]; 1013 cb({status:520, errorMessage:err}, null); 1014 } else { 1015 self.cache[url] = data; 1016 cb(null, data); 1017 } 1018 }); 1019 }, 1020 _noCacheRex: /\?/, 1021 1022 /** 1023 * Get url with basePath. 1024 * @param {string} basePath 1025 * @param {string} [url] 1026 * @returns {*} 1027 */ 1028 getUrl: function (basePath, url) { 1029 var self = this, path = cc.path; 1030 if (basePath !== undefined && url === undefined) { 1031 url = basePath; 1032 var type = path.extname(url); 1033 type = type ? type.toLowerCase() : ""; 1034 var loader = _register[type]; 1035 if (!loader) 1036 basePath = self.resPath; 1037 else 1038 basePath = loader.getBasePath ? loader.getBasePath() : self.resPath; 1039 } 1040 url = cc.path.join(basePath || "", url); 1041 if (url.match(/[\/(\\\\)]lang[\/(\\\\)]/i)) { 1042 if (_langPathCache[url]) 1043 return _langPathCache[url]; 1044 var extname = path.extname(url) || ""; 1045 url = _langPathCache[url] = url.substring(0, url.length - extname.length) + "_" + cc.sys.language + extname; 1046 } 1047 return url; 1048 }, 1049 1050 /** 1051 * Load resources then call the callback. 1052 * @param {string} resources 1053 * @param {function} [option] callback or trigger 1054 * @param {function|Object} [loadCallback] 1055 * @return {cc.AsyncPool} 1056 */ 1057 load : function(resources, option, loadCallback){ 1058 var self = this; 1059 var len = arguments.length; 1060 if(len === 0) 1061 throw new Error("arguments error!"); 1062 1063 if(len === 3){ 1064 if(typeof option === "function"){ 1065 if(typeof loadCallback === "function") 1066 option = {trigger : option, cb : loadCallback }; 1067 else 1068 option = { cb : option, cbTarget : loadCallback}; 1069 } 1070 }else if(len === 2){ 1071 if(typeof option === "function") 1072 option = {cb : option}; 1073 }else if(len === 1){ 1074 option = {}; 1075 } 1076 1077 if(!(resources instanceof Array)) 1078 resources = [resources]; 1079 var asyncPool = new cc.AsyncPool( 1080 resources, 0, 1081 function (value, index, AsyncPoolCallback, aPool) { 1082 self._loadResIterator(value, index, function (err) { 1083 var arr = Array.prototype.slice.call(arguments, 1); 1084 if (option.trigger) 1085 option.trigger.call(option.triggerTarget, arr[0], aPool.size, aPool.finishedSize); //call trigger 1086 AsyncPoolCallback(err, arr[0]); 1087 }); 1088 }, 1089 option.cb, option.cbTarget); 1090 asyncPool.flow(); 1091 return asyncPool; 1092 }, 1093 1094 _handleAliases: function (fileNames, cb) { 1095 var self = this; 1096 var resList = []; 1097 for (var key in fileNames) { 1098 var value = fileNames[key]; 1099 _aliases[key] = value; 1100 resList.push(value); 1101 } 1102 this.load(resList, cb); 1103 }, 1104 1105 /** 1106 * <p> 1107 * Loads alias map from the contents of a filename. <br/> 1108 * <br/> 1109 * @note The plist file name should follow the format below: <br/> 1110 * <?xml version="1.0" encoding="UTF-8"?> <br/> 1111 * <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <br/> 1112 * <plist version="1.0"> <br/> 1113 * <dict> <br/> 1114 * <key>filenames</key> <br/> 1115 * <dict> <br/> 1116 * <key>sounds/click.wav</key> <br/> 1117 * <string>sounds/click.caf</string> <br/> 1118 * <key>sounds/endgame.wav</key> <br/> 1119 * <string>sounds/endgame.caf</string> <br/> 1120 * <key>sounds/gem-0.wav</key> <br/> 1121 * <string>sounds/gem-0.caf</string> <br/> 1122 * </dict> <br/> 1123 * <key>metadata</key> <br/> 1124 * <dict> <br/> 1125 * <key>version</key> <br/> 1126 * <integer>1</integer> <br/> 1127 * </dict> <br/> 1128 * </dict> <br/> 1129 * </plist> <br/> 1130 * </p> 1131 * @param {String} url The plist file name. 1132 * @param {Function} [callback] 1133 */ 1134 loadAliases: function (url, callback) { 1135 var self = this, dict = self.getRes(url); 1136 if (!dict) { 1137 self.load(url, function (err, results) { 1138 self._handleAliases(results[0]["filenames"], callback); 1139 }); 1140 } else 1141 self._handleAliases(dict["filenames"], callback); 1142 }, 1143 1144 /** 1145 * Register a resource loader into loader. 1146 * @param {string} extNames 1147 * @param {function} loader 1148 */ 1149 register: function (extNames, loader) { 1150 if (!extNames || !loader) return; 1151 var self = this; 1152 if (typeof extNames === "string") 1153 return _register[extNames.trim().toLowerCase()] = loader; 1154 for (var i = 0, li = extNames.length; i < li; i++) { 1155 _register["." + extNames[i].trim().toLowerCase()] = loader; 1156 } 1157 }, 1158 1159 /** 1160 * Get resource data by url. 1161 * @param url 1162 * @returns {*} 1163 */ 1164 getRes: function (url) { 1165 return this.cache[url] || this.cache[_aliases[url]]; 1166 }, 1167 1168 /** 1169 * Get aliase by url. 1170 * @param url 1171 * @returns {*} 1172 */ 1173 _getAliase: function (url) { 1174 return _aliases[url]; 1175 }, 1176 1177 /** 1178 * Release the cache of resource by url. 1179 * @param url 1180 */ 1181 release: function (url) { 1182 var cache = this.cache; 1183 var queue = _queue[url]; 1184 if (queue) { 1185 queue.img = null; 1186 delete _queue[url]; 1187 } 1188 delete cache[url]; 1189 delete cache[_aliases[url]]; 1190 delete _aliases[url]; 1191 }, 1192 1193 /** 1194 * Resource cache of all resources. 1195 */ 1196 releaseAll: function () { 1197 var locCache = this.cache; 1198 for (var key in locCache) 1199 delete locCache[key]; 1200 for (var key in _aliases) 1201 delete _aliases[key]; 1202 } 1203 }; 1204 })(); 1205 //+++++++++++++++++++++++++something about loader end+++++++++++++++++++++++++++++ 1206 1207 /** 1208 * A string tool to construct a string with format string. 1209 * for example: 1210 * cc.formatStr("a: %d, b: %b", a, b); 1211 * cc.formatStr(a, b, c); 1212 * @returns {String} 1213 */ 1214 cc.formatStr = function(){ 1215 var args = arguments; 1216 var l = args.length; 1217 if(l < 1) 1218 return ""; 1219 1220 var str = args[0]; 1221 var needToFormat = true; 1222 if(typeof str === "object"){ 1223 needToFormat = false; 1224 } 1225 for(var i = 1; i < l; ++i){ 1226 var arg = args[i]; 1227 if(needToFormat){ 1228 while(true){ 1229 var result = null; 1230 if(typeof arg === "number"){ 1231 result = str.match(/(%d)|(%s)/); 1232 if(result){ 1233 str = str.replace(/(%d)|(%s)/, arg); 1234 break; 1235 } 1236 } 1237 result = str.match(/%s/); 1238 if(result) 1239 str = str.replace(/%s/, arg); 1240 else 1241 str += " " + arg; 1242 break; 1243 } 1244 }else 1245 str += " " + arg; 1246 } 1247 return str; 1248 }; 1249 1250 1251 //+++++++++++++++++++++++++Engine initialization function begin+++++++++++++++++++++++++++ 1252 (function () { 1253 1254 var _tmpCanvas1 = document.createElement("canvas"), 1255 _tmpCanvas2 = document.createElement("canvas"); 1256 1257 cc.create3DContext = function (canvas, opt_attribs) { 1258 var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"]; 1259 var context = null; 1260 for (var ii = 0; ii < names.length; ++ii) { 1261 try { 1262 context = canvas.getContext(names[ii], opt_attribs); 1263 } catch (e) { 1264 } 1265 if (context) { 1266 break; 1267 } 1268 } 1269 return context; 1270 }; 1271 1272 var _initSys = function () { 1273 /** 1274 * System variables 1275 * @namespace 1276 * @name cc.sys 1277 */ 1278 cc.sys = {}; 1279 var sys = cc.sys; 1280 1281 /** 1282 * English language code 1283 * @memberof cc.sys 1284 * @name LANGUAGE_ENGLISH 1285 * @constant 1286 * @type {Number} 1287 */ 1288 sys.LANGUAGE_ENGLISH = "en"; 1289 1290 /** 1291 * Chinese language code 1292 * @memberof cc.sys 1293 * @name LANGUAGE_CHINESE 1294 * @constant 1295 * @type {Number} 1296 */ 1297 sys.LANGUAGE_CHINESE = "zh"; 1298 1299 /** 1300 * French language code 1301 * @memberof cc.sys 1302 * @name LANGUAGE_FRENCH 1303 * @constant 1304 * @type {Number} 1305 */ 1306 sys.LANGUAGE_FRENCH = "fr"; 1307 1308 /** 1309 * Italian language code 1310 * @memberof cc.sys 1311 * @name LANGUAGE_ITALIAN 1312 * @constant 1313 * @type {Number} 1314 */ 1315 sys.LANGUAGE_ITALIAN = "it"; 1316 1317 /** 1318 * German language code 1319 * @memberof cc.sys 1320 * @name LANGUAGE_GERMAN 1321 * @constant 1322 * @type {Number} 1323 */ 1324 sys.LANGUAGE_GERMAN = "de"; 1325 1326 /** 1327 * Spanish language code 1328 * @memberof cc.sys 1329 * @name LANGUAGE_SPANISH 1330 * @constant 1331 * @type {Number} 1332 */ 1333 sys.LANGUAGE_SPANISH = "es"; 1334 1335 /** 1336 * Spanish language code 1337 * @memberof cc.sys 1338 * @name LANGUAGE_DUTCH 1339 * @constant 1340 * @type {Number} 1341 */ 1342 sys.LANGUAGE_DUTCH = "du"; 1343 1344 /** 1345 * Russian language code 1346 * @memberof cc.sys 1347 * @name LANGUAGE_RUSSIAN 1348 * @constant 1349 * @type {Number} 1350 */ 1351 sys.LANGUAGE_RUSSIAN = "ru"; 1352 1353 /** 1354 * Korean language code 1355 * @memberof cc.sys 1356 * @name LANGUAGE_KOREAN 1357 * @constant 1358 * @type {Number} 1359 */ 1360 sys.LANGUAGE_KOREAN = "ko"; 1361 1362 /** 1363 * Japanese language code 1364 * @memberof cc.sys 1365 * @name LANGUAGE_JAPANESE 1366 * @constant 1367 * @type {Number} 1368 */ 1369 sys.LANGUAGE_JAPANESE = "ja"; 1370 1371 /** 1372 * Hungarian language code 1373 * @memberof cc.sys 1374 * @name LANGUAGE_HUNGARIAN 1375 * @constant 1376 * @type {Number} 1377 */ 1378 sys.LANGUAGE_HUNGARIAN = "hu"; 1379 1380 /** 1381 * Portuguese language code 1382 * @memberof cc.sys 1383 * @name LANGUAGE_PORTUGUESE 1384 * @constant 1385 * @type {Number} 1386 */ 1387 sys.LANGUAGE_PORTUGUESE = "pt"; 1388 1389 /** 1390 * Arabic language code 1391 * @memberof cc.sys 1392 * @name LANGUAGE_ARABIC 1393 * @constant 1394 * @type {Number} 1395 */ 1396 sys.LANGUAGE_ARABIC = "ar"; 1397 1398 /** 1399 * Norwegian language code 1400 * @memberof cc.sys 1401 * @name LANGUAGE_NORWEGIAN 1402 * @constant 1403 * @type {Number} 1404 */ 1405 sys.LANGUAGE_NORWEGIAN = "no"; 1406 1407 /** 1408 * Polish language code 1409 * @memberof cc.sys 1410 * @name LANGUAGE_POLISH 1411 * @constant 1412 * @type {Number} 1413 */ 1414 sys.LANGUAGE_POLISH = "pl"; 1415 1416 /** 1417 * Unknown language code 1418 * @memberof cc.sys 1419 * @name LANGUAGE_UNKNOWN 1420 * @constant 1421 * @type {Number} 1422 */ 1423 sys.LANGUAGE_UNKNOWN = "unkonwn"; 1424 1425 /** 1426 * @memberof cc.sys 1427 * @name OS_IOS 1428 * @constant 1429 * @type {string} 1430 */ 1431 sys.OS_IOS = "iOS"; 1432 /** 1433 * @memberof cc.sys 1434 * @name OS_ANDROID 1435 * @constant 1436 * @type {string} 1437 */ 1438 sys.OS_ANDROID = "Android"; 1439 /** 1440 * @memberof cc.sys 1441 * @name OS_WINDOWS 1442 * @constant 1443 * @type {string} 1444 */ 1445 sys.OS_WINDOWS = "Windows"; 1446 /** 1447 * @memberof cc.sys 1448 * @name OS_MARMALADE 1449 * @constant 1450 * @type {string} 1451 */ 1452 sys.OS_MARMALADE = "Marmalade"; 1453 /** 1454 * @memberof cc.sys 1455 * @name OS_LINUX 1456 * @constant 1457 * @type {string} 1458 */ 1459 sys.OS_LINUX = "Linux"; 1460 /** 1461 * @memberof cc.sys 1462 * @name OS_BADA 1463 * @constant 1464 * @type {string} 1465 */ 1466 sys.OS_BADA = "Bada"; 1467 /** 1468 * @memberof cc.sys 1469 * @name OS_BLACKBERRY 1470 * @constant 1471 * @type {string} 1472 */ 1473 sys.OS_BLACKBERRY = "Blackberry"; 1474 /** 1475 * @memberof cc.sys 1476 * @name OS_OSX 1477 * @constant 1478 * @type {string} 1479 */ 1480 sys.OS_OSX = "OS X"; 1481 /** 1482 * @memberof cc.sys 1483 * @name OS_WP8 1484 * @constant 1485 * @type {string} 1486 */ 1487 sys.OS_WP8 = "WP8"; 1488 /** 1489 * @memberof cc.sys 1490 * @name OS_WINRT 1491 * @constant 1492 * @type {string} 1493 */ 1494 sys.OS_WINRT = "WINRT"; 1495 /** 1496 * @memberof cc.sys 1497 * @name OS_UNKNOWN 1498 * @constant 1499 * @type {string} 1500 */ 1501 sys.OS_UNKNOWN = "Unknown"; 1502 1503 /** 1504 * @memberof cc.sys 1505 * @name UNKNOWN 1506 * @constant 1507 * @default 1508 * @type {Number} 1509 */ 1510 sys.UNKNOWN = -1; 1511 /** 1512 * @memberof cc.sys 1513 * @name WIN32 1514 * @constant 1515 * @default 1516 * @type {Number} 1517 */ 1518 sys.WIN32 = 0; 1519 /** 1520 * @memberof cc.sys 1521 * @name LINUX 1522 * @constant 1523 * @default 1524 * @type {Number} 1525 */ 1526 sys.LINUX = 1; 1527 /** 1528 * @memberof cc.sys 1529 * @name MACOS 1530 * @constant 1531 * @default 1532 * @type {Number} 1533 */ 1534 sys.MACOS = 2; 1535 /** 1536 * @memberof cc.sys 1537 * @name ANDROID 1538 * @constant 1539 * @default 1540 * @type {Number} 1541 */ 1542 sys.ANDROID = 3; 1543 /** 1544 * @memberof cc.sys 1545 * @name IOS 1546 * @constant 1547 * @default 1548 * @type {Number} 1549 */ 1550 sys.IPHONE = 4; 1551 /** 1552 * @memberof cc.sys 1553 * @name IOS 1554 * @constant 1555 * @default 1556 * @type {Number} 1557 */ 1558 sys.IPAD = 5; 1559 /** 1560 * @memberof cc.sys 1561 * @name BLACKBERRY 1562 * @constant 1563 * @default 1564 * @type {Number} 1565 */ 1566 sys.BLACKBERRY = 6; 1567 /** 1568 * @memberof cc.sys 1569 * @name NACL 1570 * @constant 1571 * @default 1572 * @type {Number} 1573 */ 1574 sys.NACL = 7; 1575 /** 1576 * @memberof cc.sys 1577 * @name EMSCRIPTEN 1578 * @constant 1579 * @default 1580 * @type {Number} 1581 */ 1582 sys.EMSCRIPTEN = 8; 1583 /** 1584 * @memberof cc.sys 1585 * @name TIZEN 1586 * @constant 1587 * @default 1588 * @type {Number} 1589 */ 1590 sys.TIZEN = 9; 1591 /** 1592 * @memberof cc.sys 1593 * @name WINRT 1594 * @constant 1595 * @default 1596 * @type {Number} 1597 */ 1598 sys.WINRT = 10; 1599 /** 1600 * @memberof cc.sys 1601 * @name WP8 1602 * @constant 1603 * @default 1604 * @type {Number} 1605 */ 1606 sys.WP8 = 11; 1607 /** 1608 * @memberof cc.sys 1609 * @name MOBILE_BROWSER 1610 * @constant 1611 * @default 1612 * @type {Number} 1613 */ 1614 sys.MOBILE_BROWSER = 100; 1615 /** 1616 * @memberof cc.sys 1617 * @name DESKTOP_BROWSER 1618 * @constant 1619 * @default 1620 * @type {Number} 1621 */ 1622 sys.DESKTOP_BROWSER = 101; 1623 1624 sys.BROWSER_TYPE_WECHAT = "wechat"; 1625 sys.BROWSER_TYPE_ANDROID = "androidbrowser"; 1626 sys.BROWSER_TYPE_IE = "ie"; 1627 sys.BROWSER_TYPE_QQ = "qqbrowser"; 1628 sys.BROWSER_TYPE_MOBILE_QQ = "mqqbrowser"; 1629 sys.BROWSER_TYPE_UC = "ucbrowser"; 1630 sys.BROWSER_TYPE_360 = "360browser"; 1631 sys.BROWSER_TYPE_BAIDU_APP = "baiduboxapp"; 1632 sys.BROWSER_TYPE_BAIDU = "baidubrowser"; 1633 sys.BROWSER_TYPE_MAXTHON = "maxthon"; 1634 sys.BROWSER_TYPE_OPERA = "opera"; 1635 sys.BROWSER_TYPE_OUPENG = "oupeng"; 1636 sys.BROWSER_TYPE_MIUI = "miuibrowser"; 1637 sys.BROWSER_TYPE_FIREFOX = "firefox"; 1638 sys.BROWSER_TYPE_SAFARI = "safari"; 1639 sys.BROWSER_TYPE_CHROME = "chrome"; 1640 sys.BROWSER_TYPE_LIEBAO = "liebao"; 1641 sys.BROWSER_TYPE_QZONE = "qzone"; 1642 sys.BROWSER_TYPE_SOUGOU = "sogou"; 1643 sys.BROWSER_TYPE_UNKNOWN = "unknown"; 1644 1645 /** 1646 * Is native ? This is set to be true in jsb auto. 1647 * @memberof cc.sys 1648 * @name isNative 1649 * @type {Boolean} 1650 */ 1651 sys.isNative = false; 1652 1653 var win = window, nav = win.navigator, doc = document, docEle = doc.documentElement; 1654 var ua = nav.userAgent.toLowerCase(); 1655 1656 /** 1657 * Indicate whether system is mobile system 1658 * @memberof cc.sys 1659 * @name isMobile 1660 * @type {Boolean} 1661 */ 1662 sys.isMobile = ua.indexOf('mobile') !== -1 || ua.indexOf('android') !== -1; 1663 1664 /** 1665 * Indicate the running platform 1666 * @memberof cc.sys 1667 * @name platform 1668 * @type {Number} 1669 */ 1670 sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER; 1671 1672 var currLanguage = nav.language; 1673 currLanguage = currLanguage ? currLanguage : nav.browserLanguage; 1674 currLanguage = currLanguage ? currLanguage.split("-")[0] : sys.LANGUAGE_ENGLISH; 1675 1676 /** 1677 * Indicate the current language of the running system 1678 * @memberof cc.sys 1679 * @name language 1680 * @type {String} 1681 */ 1682 sys.language = currLanguage; 1683 1684 // Get the os of system 1685 var isAndroid = false, iOS = false, osVersion = '', osMainVersion = 0; 1686 var uaResult = /android (\d+(?:\.\d+)+)/i.exec(ua) || /android (\d+(?:\.\d+)+)/i.exec(nav.platform); 1687 if (uaResult) { 1688 isAndroid = true; 1689 osVersion = uaResult[1] || ''; 1690 osMainVersion = parseInt(osVersion) || 0; 1691 } 1692 uaResult = /(iPad|iPhone|iPod).*OS ((\d+_?){2,3})/i.exec(ua); 1693 if (uaResult) { 1694 iOS = true; 1695 osVersion = uaResult[2] || ''; 1696 osMainVersion = parseInt(osVersion) || 0; 1697 } 1698 1699 var osName = sys.OS_UNKNOWN; 1700 if (nav.appVersion.indexOf("Win") !== -1) osName = sys.OS_WINDOWS; 1701 else if (iOS) osName = sys.OS_IOS; 1702 else if (nav.appVersion.indexOf("Mac") !== -1) osName = sys.OS_OSX; 1703 else if (nav.appVersion.indexOf("X11") !== -1 && nav.appVersion.indexOf("Linux") === -1) osName = sys.OS_UNIX; 1704 else if (isAndroid) osName = sys.OS_ANDROID; 1705 else if (nav.appVersion.indexOf("Linux") !== -1) osName = sys.OS_LINUX; 1706 1707 /** 1708 * Indicate the running os name 1709 * @memberof cc.sys 1710 * @name os 1711 * @type {String} 1712 */ 1713 sys.os = osName; 1714 /** 1715 * Indicate the running os version string 1716 * @memberof cc.sys 1717 * @name osVersion 1718 * @type {String} 1719 */ 1720 sys.osVersion = osVersion; 1721 /** 1722 * Indicate the running os main version number 1723 * @memberof cc.sys 1724 * @name osMainVersion 1725 * @type {Number} 1726 */ 1727 sys.osMainVersion = osMainVersion; 1728 1729 /** 1730 * Indicate the running browser type 1731 * @memberof cc.sys 1732 * @name browserType 1733 * @type {String} 1734 */ 1735 sys.browserType = sys.BROWSER_TYPE_UNKNOWN; 1736 /* Determine the browser type */ 1737 (function(){ 1738 var typeReg1 = /mqqbrowser|sogou|qzone|liebao|micromessenger|ucbrowser|360 aphone|360browser|baiduboxapp|baidubrowser|maxthon|mxbrowser|trident|miuibrowser/i; 1739 var typeReg2 = /qqbrowser|chrome|safari|firefox|opr|oupeng|opera/i; 1740 var browserTypes = typeReg1.exec(ua); 1741 if(!browserTypes) browserTypes = typeReg2.exec(ua); 1742 var browserType = browserTypes ? browserTypes[0] : sys.BROWSER_TYPE_UNKNOWN; 1743 if (browserType === 'micromessenger') 1744 browserType = sys.BROWSER_TYPE_WECHAT; 1745 else if (browserType === "safari" && (ua.match(/android.*applewebkit/))) 1746 browserType = sys.BROWSER_TYPE_ANDROID; 1747 else if (browserType === "trident") 1748 browserType = sys.BROWSER_TYPE_IE; 1749 else if (browserType === "360 aphone") 1750 browserType = sys.BROWSER_TYPE_360; 1751 else if (browserType === "mxbrowser") 1752 browserType = sys.BROWSER_TYPE_MAXTHON; 1753 else if (browserType === "opr") 1754 browserType = sys.BROWSER_TYPE_OPERA; 1755 1756 sys.browserType = browserType; 1757 })(); 1758 1759 /** 1760 * Indicate the running browser version 1761 * @memberof cc.sys 1762 * @name browserVersion 1763 * @type {Number} 1764 */ 1765 sys.browserVersion = ""; 1766 /* Determine the browser version number */ 1767 (function(){ 1768 var versionReg1 = /(micromessenger|qq|mx|maxthon|baidu|sogou)(mobile)?(browser)?\/?([\d.]+)/i; 1769 var versionReg2 = /(msie |rv:|firefox|chrome|ucbrowser|oupeng|opera|opr|safari|miui)(mobile)?(browser)?\/?([\d.]+)/i; 1770 var tmp = ua.match(versionReg1); 1771 if(!tmp) tmp = ua.match(versionReg2); 1772 sys.browserVersion = tmp ? tmp[4] : ""; 1773 })(); 1774 1775 var w = window.innerWidth || document.documentElement.clientWidth; 1776 var h = window.innerHeight || document.documentElement.clientHeight; 1777 var ratio = window.devicePixelRatio || 1; 1778 1779 /** 1780 * Indicate the real pixel resolution of the whole game window 1781 * @memberof cc.sys 1782 * @name windowPixelResolution 1783 * @type {Number} 1784 */ 1785 sys.windowPixelResolution = { 1786 width: ratio * w, 1787 height: ratio * h 1788 }; 1789 1790 sys._checkWebGLRenderMode = function () { 1791 if (cc._renderType !== cc.game.RENDER_TYPE_WEBGL) 1792 throw new Error("This feature supports WebGL render mode only."); 1793 }; 1794 1795 //Whether or not the Canvas BlendModes are supported. 1796 sys._supportCanvasNewBlendModes = (function(){ 1797 var canvas = _tmpCanvas1; 1798 canvas.width = 1; 1799 canvas.height = 1; 1800 var context = canvas.getContext('2d'); 1801 context.fillStyle = '#000'; 1802 context.fillRect(0,0,1,1); 1803 context.globalCompositeOperation = 'multiply'; 1804 1805 var canvas2 = _tmpCanvas2; 1806 canvas2.width = 1; 1807 canvas2.height = 1; 1808 var context2 = canvas2.getContext('2d'); 1809 context2.fillStyle = '#fff'; 1810 context2.fillRect(0,0,1,1); 1811 context.drawImage(canvas2, 0, 0, 1, 1); 1812 1813 return context.getImageData(0,0,1,1).data[0] === 0; 1814 })(); 1815 1816 // Adjust mobile css settings 1817 if (cc.sys.isMobile) { 1818 var fontStyle = document.createElement("style"); 1819 fontStyle.type = "text/css"; 1820 document.body.appendChild(fontStyle); 1821 1822 fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;" 1823 + "-webkit-tap-highlight-color:rgba(0,0,0,0);}"; 1824 } 1825 1826 /** 1827 * cc.sys.localStorage is a local storage component. 1828 * @memberof cc.sys 1829 * @name localStorage 1830 * @type {Object} 1831 */ 1832 try { 1833 var localStorage = sys.localStorage = win.localStorage; 1834 localStorage.setItem("storage", ""); 1835 localStorage.removeItem("storage"); 1836 localStorage = null; 1837 } catch (e) { 1838 var warn = function () { 1839 cc.warn("Warning: localStorage isn't enabled. Please confirm browser cookie or privacy option"); 1840 }; 1841 sys.localStorage = { 1842 getItem : warn, 1843 setItem : warn, 1844 removeItem : warn, 1845 clear : warn 1846 }; 1847 } 1848 1849 var _supportCanvas = !!_tmpCanvas1.getContext("2d"); 1850 var _supportWebGL = false; 1851 if (win.WebGLRenderingContext) { 1852 var tmpCanvas = document.createElement("CANVAS"); 1853 try{ 1854 var context = cc.create3DContext(tmpCanvas, {'stencil': true, 'preserveDrawingBuffer': true }); 1855 if(context) { 1856 _supportWebGL = true; 1857 } 1858 1859 if (_supportWebGL && sys.os === sys.OS_ANDROID) { 1860 switch (sys.browserType) { 1861 case sys.BROWSER_TYPE_MOBILE_QQ: 1862 case sys.BROWSER_TYPE_BAIDU: 1863 case sys.BROWSER_TYPE_BAIDU_APP: 1864 // QQ & Baidu Brwoser 6.2+ (using blink kernel) 1865 var browserVer = parseFloat(sys.browserVersion); 1866 if (browserVer >= 6.2) { 1867 _supportWebGL = true; 1868 } 1869 else { 1870 _supportWebGL = false; 1871 } 1872 break; 1873 case sys.BROWSER_TYPE_ANDROID: 1874 // Android 5+ default browser 1875 if (sys.osMainVersion && sys.osMainVersion >= 5) { 1876 _supportWebGL = true; 1877 } 1878 break; 1879 case sys.BROWSER_TYPE_UNKNOWN: 1880 case sys.BROWSER_TYPE_360: 1881 case sys.BROWSER_TYPE_MIUI: 1882 _supportWebGL = false; 1883 } 1884 } 1885 } 1886 catch (e) {} 1887 tmpCanvas = null; 1888 } 1889 1890 /** 1891 * The capabilities of the current platform 1892 * @memberof cc.sys 1893 * @name capabilities 1894 * @type {Object} 1895 */ 1896 var capabilities = sys.capabilities = { 1897 "canvas": _supportCanvas, 1898 "opengl": _supportWebGL 1899 }; 1900 if (docEle['ontouchstart'] !== undefined || doc['ontouchstart'] !== undefined || nav.msPointerEnabled) 1901 capabilities["touches"] = true; 1902 if (docEle['onmouseup'] !== undefined) 1903 capabilities["mouse"] = true; 1904 if (docEle['onkeyup'] !== undefined) 1905 capabilities["keyboard"] = true; 1906 if (win.DeviceMotionEvent || win.DeviceOrientationEvent) 1907 capabilities["accelerometer"] = true; 1908 1909 /** 1910 * Forces the garbage collection, only available in JSB 1911 * @memberof cc.sys 1912 * @name garbageCollect 1913 * @function 1914 */ 1915 sys.garbageCollect = function () { 1916 // N/A in cocos2d-html5 1917 }; 1918 1919 /** 1920 * Dumps rooted objects, only available in JSB 1921 * @memberof cc.sys 1922 * @name dumpRoot 1923 * @function 1924 */ 1925 sys.dumpRoot = function () { 1926 // N/A in cocos2d-html5 1927 }; 1928 1929 /** 1930 * Restart the JS VM, only available in JSB 1931 * @memberof cc.sys 1932 * @name restartVM 1933 * @function 1934 */ 1935 sys.restartVM = function () { 1936 // N/A in cocos2d-html5 1937 }; 1938 1939 /** 1940 * Clean a script in the JS VM, only available in JSB 1941 * @memberof cc.sys 1942 * @name cleanScript 1943 * @param {String} jsfile 1944 * @function 1945 */ 1946 sys.cleanScript = function (jsfile) { 1947 // N/A in cocos2d-html5 1948 }; 1949 1950 /** 1951 * Check whether an object is valid, 1952 * In web engine, it will return true if the object exist 1953 * In native engine, it will return true if the JS object and the correspond native object are both valid 1954 * @memberof cc.sys 1955 * @name isObjectValid 1956 * @param {Object} obj 1957 * @return {boolean} Validity of the object 1958 * @function 1959 */ 1960 sys.isObjectValid = function (obj) { 1961 if (obj) return true; 1962 else return false; 1963 }; 1964 1965 /** 1966 * Dump system informations 1967 * @memberof cc.sys 1968 * @name dump 1969 * @function 1970 */ 1971 sys.dump = function () { 1972 var self = this; 1973 var str = ""; 1974 str += "isMobile : " + self.isMobile + "\r\n"; 1975 str += "language : " + self.language + "\r\n"; 1976 str += "browserType : " + self.browserType + "\r\n"; 1977 str += "browserVersion : " + self.browserVersion + "\r\n"; 1978 str += "capabilities : " + JSON.stringify(self.capabilities) + "\r\n"; 1979 str += "os : " + self.os + "\r\n"; 1980 str += "osVersion : " + self.osVersion + "\r\n"; 1981 str += "platform : " + self.platform + "\r\n"; 1982 str += "Using " + (cc._renderType === cc.game.RENDER_TYPE_WEBGL ? "WEBGL" : "CANVAS") + " renderer." + "\r\n"; 1983 cc.log(str); 1984 }; 1985 1986 /** 1987 * Open a url in browser 1988 * @memberof cc.sys 1989 * @name openURL 1990 * @param {String} url 1991 */ 1992 sys.openURL = function(url){ 1993 window.open(url); 1994 }; 1995 }; 1996 _initSys(); 1997 1998 _tmpCanvas1 = null; 1999 _tmpCanvas2 = null; 2000 2001 //to make sure the cc.log, cc.warn, cc.error and cc.assert would not throw error before init by debugger mode. 2002 cc.log = cc.warn = cc.error = cc.assert = function () { 2003 }; 2004 2005 var _config = null, 2006 //cache for js and module that has added into jsList to be loaded. 2007 _jsAddedCache = {}, 2008 _engineInitCalled = false, 2009 _engineLoadedCallback = null; 2010 2011 cc._engineLoaded = false; 2012 2013 function _determineRenderType(config) { 2014 var CONFIG_KEY = cc.game.CONFIG_KEY, 2015 userRenderMode = parseInt(config[CONFIG_KEY.renderMode]) || 0; 2016 2017 // Adjust RenderType 2018 if (isNaN(userRenderMode) || userRenderMode > 2 || userRenderMode < 0) 2019 config[CONFIG_KEY.renderMode] = 0; 2020 2021 // Determine RenderType 2022 cc._renderType = cc.game.RENDER_TYPE_CANVAS; 2023 cc._supportRender = false; 2024 2025 if (userRenderMode === 0) { 2026 if (cc.sys.capabilities["opengl"]) { 2027 cc._renderType = cc.game.RENDER_TYPE_WEBGL; 2028 cc._supportRender = true; 2029 } 2030 else if (cc.sys.capabilities["canvas"]) { 2031 cc._renderType = cc.game.RENDER_TYPE_CANVAS; 2032 cc._supportRender = true; 2033 } 2034 } 2035 else if (userRenderMode === 1 && cc.sys.capabilities["canvas"]) { 2036 cc._renderType = cc.game.RENDER_TYPE_CANVAS; 2037 cc._supportRender = true; 2038 } 2039 else if (userRenderMode === 2 && cc.sys.capabilities["opengl"]) { 2040 cc._renderType = cc.game.RENDER_TYPE_WEBGL; 2041 cc._supportRender = true; 2042 } 2043 } 2044 2045 function _getJsListOfModule(moduleMap, moduleName, dir) { 2046 if (_jsAddedCache[moduleName]) return null; 2047 dir = dir || ""; 2048 var jsList = []; 2049 var tempList = moduleMap[moduleName]; 2050 if (!tempList) throw new Error("can not find module [" + moduleName + "]"); 2051 var ccPath = cc.path; 2052 for (var i = 0, li = tempList.length; i < li; i++) { 2053 var item = tempList[i]; 2054 if (_jsAddedCache[item]) continue; 2055 var extname = ccPath.extname(item); 2056 if (!extname) { 2057 var arr = _getJsListOfModule(moduleMap, item, dir); 2058 if (arr) jsList = jsList.concat(arr); 2059 } else if (extname.toLowerCase() === ".js") jsList.push(ccPath.join(dir, item)); 2060 _jsAddedCache[item] = 1; 2061 } 2062 return jsList; 2063 } 2064 2065 function _afterEngineLoaded(config) { 2066 if (cc._initDebugSetting) 2067 cc._initDebugSetting(config[cc.game.CONFIG_KEY.debugMode]); 2068 cc._engineLoaded = true; 2069 cc.log(cc.ENGINE_VERSION); 2070 if (_engineLoadedCallback) _engineLoadedCallback(); 2071 } 2072 2073 function _load(config) { 2074 var self = this; 2075 var CONFIG_KEY = cc.game.CONFIG_KEY, engineDir = config[CONFIG_KEY.engineDir], loader = cc.loader; 2076 2077 if (cc.Class) { 2078 // Single file loaded 2079 _afterEngineLoaded(config); 2080 } else { 2081 // Load cocos modules 2082 var ccModulesPath = cc.path.join(engineDir, "moduleConfig.json"); 2083 loader.loadJson(ccModulesPath, function (err, modulesJson) { 2084 if (err) throw new Error(err); 2085 var modules = config["modules"] || []; 2086 var moduleMap = modulesJson["module"]; 2087 var jsList = []; 2088 if (cc.sys.capabilities["opengl"] && modules.indexOf("base4webgl") < 0) modules.splice(0, 0, "base4webgl"); 2089 else if (modules.indexOf("core") < 0) modules.splice(0, 0, "core"); 2090 for (var i = 0, li = modules.length; i < li; i++) { 2091 var arr = _getJsListOfModule(moduleMap, modules[i], engineDir); 2092 if (arr) jsList = jsList.concat(arr); 2093 } 2094 cc.loader.loadJsWithImg(jsList, function (err) { 2095 if (err) throw err; 2096 _afterEngineLoaded(config); 2097 }); 2098 }); 2099 } 2100 } 2101 2102 function _windowLoaded() { 2103 this.removeEventListener('load', _windowLoaded, false); 2104 _load(cc.game.config); 2105 } 2106 2107 cc.initEngine = function (config, cb) { 2108 if (_engineInitCalled) { 2109 var previousCallback = _engineLoadedCallback; 2110 _engineLoadedCallback = function () { 2111 previousCallback && previousCallback(); 2112 cb && cb(); 2113 } 2114 return; 2115 } 2116 2117 _engineLoadedCallback = cb; 2118 2119 // Config uninitialized and given, initialize with it 2120 if (!cc.game.config && config) { 2121 cc.game.config = config; 2122 } 2123 // No config given and no config set before, load it 2124 else if (!cc.game.config) { 2125 cc.game._loadConfig(); 2126 } 2127 config = cc.game.config; 2128 2129 _determineRenderType(config); 2130 2131 document.body ? _load(config) : cc._addEventListener(window, 'load', _windowLoaded, false); 2132 _engineInitCalled = true; 2133 }; 2134 2135 })(); 2136 //+++++++++++++++++++++++++Engine initialization function end+++++++++++++++++++++++++++++ 2137 2138 //+++++++++++++++++++++++++something about CCGame begin+++++++++++++++++++++++++++ 2139 /** 2140 * An object to boot the game. 2141 * @class 2142 * @name cc.game 2143 * 2144 */ 2145 cc.game = /** @lends cc.game# */{ 2146 /** 2147 * Debug mode: No debugging. {@static} 2148 * @const {Number} 2149 * @static 2150 */ 2151 DEBUG_MODE_NONE: 0, 2152 /** 2153 * Debug mode: Info, warning, error to console. 2154 * @const {Number} 2155 * @static 2156 */ 2157 DEBUG_MODE_INFO: 1, 2158 /** 2159 * Debug mode: Warning, error to console. 2160 * @const {Number} 2161 * @static 2162 */ 2163 DEBUG_MODE_WARN: 2, 2164 /** 2165 * Debug mode: Error to console. 2166 * @const {Number} 2167 * @static 2168 */ 2169 DEBUG_MODE_ERROR: 3, 2170 /** 2171 * Debug mode: Info, warning, error to web page. 2172 * @const {Number} 2173 * @static 2174 */ 2175 DEBUG_MODE_INFO_FOR_WEB_PAGE: 4, 2176 /** 2177 * Debug mode: Warning, error to web page. 2178 * @const {Number} 2179 * @static 2180 */ 2181 DEBUG_MODE_WARN_FOR_WEB_PAGE: 5, 2182 /** 2183 * Debug mode: Error to web page. 2184 * @const {Number} 2185 * @static 2186 */ 2187 DEBUG_MODE_ERROR_FOR_WEB_PAGE: 6, 2188 2189 /** 2190 * Event that is fired when the game is hidden. 2191 * @constant {String} 2192 */ 2193 EVENT_HIDE: "game_on_hide", 2194 /** 2195 * Event that is fired when the game is shown. 2196 * @constant {String} 2197 */ 2198 EVENT_SHOW: "game_on_show", 2199 /** 2200 * Event that is fired when the game is resized. 2201 * @constant {String} 2202 */ 2203 EVENT_RESIZE: "game_on_resize", 2204 /** 2205 * Event that is fired when the renderer is done being initialized. 2206 * @constant {String} 2207 */ 2208 EVENT_RENDERER_INITED: "renderer_inited", 2209 2210 /** @constant {Number} */ 2211 RENDER_TYPE_CANVAS: 0, 2212 /** @constant {Number} */ 2213 RENDER_TYPE_WEBGL: 1, 2214 /** @constant {Number} */ 2215 RENDER_TYPE_OPENGL: 2, 2216 2217 _eventHide: null, 2218 _eventShow: null, 2219 2220 /** 2221 * Keys found in project.json. 2222 * 2223 * @constant 2224 * @type {Object} 2225 * 2226 * @prop {String} engineDir - In debug mode, if you use the whole engine to develop your game, you should specify its relative path with "engineDir". 2227 * @prop {String} modules - Defines which modules you will need in your game, it's useful only on web 2228 * @prop {String} debugMode - Debug mode, see DEBUG_MODE_XXX constant definitions. 2229 * @prop {String} showFPS - Left bottom corner fps information will show when "showFPS" equals true, otherwise it will be hide. 2230 * @prop {String} frameRate - Sets the wanted frame rate for your game, but the real fps depends on your game implementation and the running environment. 2231 * @prop {String} id - Sets the id of your canvas element on the web page, it's useful only on web. 2232 * @prop {String} renderMode - Sets the renderer type, only useful on web, 0: Automatic, 1: Canvas, 2: WebGL 2233 * @prop {String} jsList - Sets the list of js files in your game. 2234 */ 2235 CONFIG_KEY: { 2236 width: "width", 2237 height: "height", 2238 engineDir: "engineDir", 2239 modules: "modules", 2240 debugMode: "debugMode", 2241 showFPS: "showFPS", 2242 frameRate: "frameRate", 2243 id: "id", 2244 renderMode: "renderMode", 2245 jsList: "jsList" 2246 }, 2247 2248 // states 2249 _paused: true,//whether the game is paused 2250 _prepareCalled: false,//whether the prepare function has been called 2251 _prepared: false,//whether the engine has prepared 2252 _rendererInitialized: false, 2253 2254 _renderContext: null, 2255 2256 _intervalId: null,//interval target of main 2257 2258 _lastTime: null, 2259 _frameTime: null, 2260 2261 /** 2262 * The outer frame of the game canvas, parent of cc.container 2263 * @type {Object} 2264 */ 2265 frame: null, 2266 /** 2267 * The container of game canvas, equals to cc.container 2268 * @type {Object} 2269 */ 2270 container: null, 2271 /** 2272 * The canvas of the game, equals to cc._canvas 2273 * @type {Object} 2274 */ 2275 canvas: null, 2276 2277 /** 2278 * Config of game 2279 * @type {Object} 2280 */ 2281 config: null, 2282 2283 /** 2284 * Callback when the scripts of engine have been load. 2285 * @type {Function|null} 2286 */ 2287 onStart: null, 2288 2289 /** 2290 * Callback when game exits. 2291 * @type {Function|null} 2292 */ 2293 onStop: null, 2294 2295 //@Public Methods 2296 2297 // @Game play control 2298 /** 2299 * Set frameRate of game. 2300 * @param frameRate 2301 */ 2302 setFrameRate: function (frameRate) { 2303 var self = this, config = self.config, CONFIG_KEY = self.CONFIG_KEY; 2304 config[CONFIG_KEY.frameRate] = frameRate; 2305 if (self._intervalId) 2306 window.cancelAnimationFrame(self._intervalId); 2307 self._paused = true; 2308 self._setAnimFrame(); 2309 self._runMainLoop(); 2310 }, 2311 2312 /** 2313 * Run the game frame by frame. 2314 */ 2315 step: function () { 2316 cc.director.mainLoop(); 2317 }, 2318 2319 /** 2320 * Pause the game. 2321 */ 2322 pause: function () { 2323 if (this._paused) return; 2324 this._paused = true; 2325 // Pause audio engine 2326 cc.audioEngine && cc.audioEngine._pausePlaying(); 2327 // Pause main loop 2328 if (this._intervalId) 2329 window.cancelAnimationFrame(this._intervalId); 2330 this._intervalId = 0; 2331 }, 2332 2333 /** 2334 * Resume the game from pause. 2335 */ 2336 resume: function () { 2337 if (!this._paused) return; 2338 this._paused = false; 2339 // Resume audio engine 2340 cc.audioEngine && cc.audioEngine._resumePlaying(); 2341 // Resume main loop 2342 this._runMainLoop(); 2343 }, 2344 2345 /** 2346 * Check whether the game is paused. 2347 */ 2348 isPaused: function () { 2349 return this._paused; 2350 }, 2351 2352 /** 2353 * Restart game. 2354 */ 2355 restart: function () { 2356 cc.director.popToSceneStackLevel(0); 2357 // Clean up audio 2358 cc.audioEngine && cc.audioEngine.end(); 2359 2360 cc.game.onStart(); 2361 }, 2362 2363 /** 2364 * End game, it will close the game window 2365 */ 2366 end: function () { 2367 close(); 2368 }, 2369 2370 // @Game loading 2371 /** 2372 * Prepare game. 2373 * @param cb 2374 */ 2375 prepare: function (cb) { 2376 var self = this, 2377 config = self.config, 2378 CONFIG_KEY = self.CONFIG_KEY; 2379 2380 this._loadConfig(); 2381 2382 // Already prepared 2383 if (this._prepared) { 2384 if (cb) cb(); 2385 return; 2386 } 2387 // Prepare called, but not done yet 2388 if (this._prepareCalled) { 2389 return; 2390 } 2391 // Prepare never called and engine ready 2392 if (cc._engineLoaded) { 2393 this._prepareCalled = true; 2394 2395 this._initRenderer(config[CONFIG_KEY.width], config[CONFIG_KEY.height]); 2396 2397 /** 2398 * cc.view is the shared view object. 2399 * @type {cc.EGLView} 2400 * @name cc.view 2401 * @memberof cc 2402 */ 2403 cc.view = cc.EGLView._getInstance(); 2404 2405 /** 2406 * @type {cc.Director} 2407 * @name cc.director 2408 * @memberof cc 2409 */ 2410 cc.director = cc.Director._getInstance(); 2411 if (cc.director.setOpenGLView) 2412 cc.director.setOpenGLView(cc.view); 2413 /** 2414 * cc.winSize is the alias object for the size of the current game window. 2415 * @type {cc.Size} 2416 * @name cc.winSize 2417 * @memberof cc 2418 */ 2419 cc.winSize = cc.director.getWinSize(); 2420 2421 this._initEvents(); 2422 2423 this._setAnimFrame(); 2424 this._runMainLoop(); 2425 2426 // Load game scripts 2427 var jsList = config[CONFIG_KEY.jsList]; 2428 if (jsList) { 2429 cc.loader.loadJsWithImg(jsList, function (err) { 2430 if (err) throw new Error(err); 2431 self._prepared = true; 2432 if (cb) cb(); 2433 }); 2434 } 2435 else { 2436 if (cb) cb(); 2437 } 2438 2439 return; 2440 } 2441 2442 // Engine not loaded yet 2443 cc.initEngine(this.config, function () { 2444 self.prepare(cb); 2445 }); 2446 }, 2447 2448 /** 2449 * Run game with configuration object and onStart function. 2450 * @param {Object|Function} [config] Pass configuration object or onStart function 2451 * @param {onStart} [onStart] onStart function to be executed after game initialized 2452 */ 2453 run: function (config, onStart) { 2454 if (typeof config === 'function') { 2455 cc.game.onStart = config; 2456 } 2457 else { 2458 if (config) { 2459 if (typeof config === 'string') { 2460 if (!cc.game.config) this._loadConfig(); 2461 cc.game.config[cc.game.CONFIG_KEY.id] = config; 2462 } else { 2463 cc.game.config = config; 2464 } 2465 } 2466 if (typeof onStart === 'function') { 2467 cc.game.onStart = onStart; 2468 } 2469 } 2470 2471 this.prepare(cc.game.onStart && cc.game.onStart.bind(cc.game)); 2472 }, 2473 2474 //@Private Methods 2475 2476 // @Time ticker section 2477 _setAnimFrame: function () { 2478 this._lastTime = new Date(); 2479 this._frameTime = 1000 / cc.game.config[cc.game.CONFIG_KEY.frameRate]; 2480 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) { 2481 window.requestAnimFrame = this._stTime; 2482 window.cancelAnimationFrame = this._ctTime; 2483 } 2484 else { 2485 window.requestAnimFrame = window.requestAnimationFrame || 2486 window.webkitRequestAnimationFrame || 2487 window.mozRequestAnimationFrame || 2488 window.oRequestAnimationFrame || 2489 window.msRequestAnimationFrame || 2490 this._stTime; 2491 window.cancelAnimationFrame = window.cancelAnimationFrame || 2492 window.cancelRequestAnimationFrame || 2493 window.msCancelRequestAnimationFrame || 2494 window.mozCancelRequestAnimationFrame || 2495 window.oCancelRequestAnimationFrame || 2496 window.webkitCancelRequestAnimationFrame || 2497 window.msCancelAnimationFrame || 2498 window.mozCancelAnimationFrame || 2499 window.webkitCancelAnimationFrame || 2500 window.oCancelAnimationFrame || 2501 this._ctTime; 2502 } 2503 }, 2504 _stTime: function(callback){ 2505 var currTime = new Date().getTime(); 2506 var timeToCall = Math.max(0, cc.game._frameTime - (currTime - cc.game._lastTime)); 2507 var id = window.setTimeout(function() { callback(); }, 2508 timeToCall); 2509 cc.game._lastTime = currTime + timeToCall; 2510 return id; 2511 }, 2512 _ctTime: function(id){ 2513 window.clearTimeout(id); 2514 }, 2515 //Run game. 2516 _runMainLoop: function () { 2517 var self = this, callback, config = self.config, CONFIG_KEY = self.CONFIG_KEY, 2518 director = cc.director; 2519 2520 director.setDisplayStats(config[CONFIG_KEY.showFPS]); 2521 2522 callback = function () { 2523 if (!self._paused) { 2524 director.mainLoop(); 2525 if(self._intervalId) 2526 window.cancelAnimationFrame(self._intervalId); 2527 self._intervalId = window.requestAnimFrame(callback); 2528 } 2529 }; 2530 2531 window.requestAnimFrame(callback); 2532 self._paused = false; 2533 }, 2534 2535 // @Game loading section 2536 _loadConfig: function () { 2537 // Load config 2538 // Already loaded 2539 if (this.config) { 2540 this._initConfig(this.config); 2541 return; 2542 } 2543 // Load from document.ccConfig 2544 if (document["ccConfig"]) { 2545 this._initConfig(document["ccConfig"]); 2546 } 2547 // Load from project.json 2548 else { 2549 var data = {}; 2550 try { 2551 var cocos_script = document.getElementsByTagName('script'); 2552 for(var i = 0; i < cocos_script.length; i++){ 2553 var _t = cocos_script[i].getAttribute('cocos'); 2554 if(_t === '' || _t) { 2555 break; 2556 } 2557 } 2558 var _src, txt, _resPath; 2559 if(i < cocos_script.length){ 2560 _src = cocos_script[i].src; 2561 if(_src){ 2562 _resPath = /(.*)\//.exec(_src)[0]; 2563 cc.loader.resPath = _resPath; 2564 _src = cc.path.join(_resPath, 'project.json'); 2565 } 2566 txt = cc.loader._loadTxtSync(_src); 2567 } 2568 if(!txt){ 2569 txt = cc.loader._loadTxtSync("project.json"); 2570 } 2571 data = JSON.parse(txt); 2572 } catch (e) { 2573 cc.log("Failed to read or parse project.json"); 2574 } 2575 this._initConfig(data); 2576 } 2577 }, 2578 2579 _initConfig: function (config) { 2580 var CONFIG_KEY = this.CONFIG_KEY, 2581 modules = config[CONFIG_KEY.modules]; 2582 2583 // Configs adjustment 2584 config[CONFIG_KEY.showFPS] = typeof config[CONFIG_KEY.showFPS] === 'undefined' ? true : config[CONFIG_KEY.showFPS]; 2585 config[CONFIG_KEY.engineDir] = config[CONFIG_KEY.engineDir] || "frameworks/cocos2d-html5"; 2586 if (config[CONFIG_KEY.debugMode] == null) 2587 config[CONFIG_KEY.debugMode] = 0; 2588 config[CONFIG_KEY.frameRate] = config[CONFIG_KEY.frameRate] || 60; 2589 if (config[CONFIG_KEY.renderMode] == null) 2590 config[CONFIG_KEY.renderMode] = 0; 2591 if (config[CONFIG_KEY.registerSystemEvent] == null) 2592 config[CONFIG_KEY.registerSystemEvent] = true; 2593 2594 // Modules adjustment 2595 if (modules && modules.indexOf("core") < 0) modules.splice(0, 0, "core"); 2596 modules && (config[CONFIG_KEY.modules] = modules); 2597 this.config = config; 2598 }, 2599 2600 _initRenderer: function (width, height) { 2601 // Avoid setup to be called twice. 2602 if (this._rendererInitialized) return; 2603 2604 if (!cc._supportRender) { 2605 throw new Error("The renderer doesn't support the renderMode " + this.config[this.CONFIG_KEY.renderMode]); 2606 } 2607 2608 var el = this.config[cc.game.CONFIG_KEY.id], 2609 win = window, 2610 element = cc.$(el) || cc.$('#' + el), 2611 localCanvas, localContainer, localConStyle; 2612 2613 if (element.tagName === "CANVAS") { 2614 width = width || element.width; 2615 height = height || element.height; 2616 2617 //it is already a canvas, we wrap it around with a div 2618 this.canvas = cc._canvas = localCanvas = element; 2619 this.container = cc.container = localContainer = document.createElement("DIV"); 2620 if (localCanvas.parentNode) 2621 localCanvas.parentNode.insertBefore(localContainer, localCanvas); 2622 } else { 2623 //we must make a new canvas and place into this element 2624 if (element.tagName !== "DIV") { 2625 cc.log("Warning: target element is not a DIV or CANVAS"); 2626 } 2627 width = width || element.clientWidth; 2628 height = height || element.clientHeight; 2629 this.canvas = cc._canvas = localCanvas = document.createElement("CANVAS"); 2630 this.container = cc.container = localContainer = document.createElement("DIV"); 2631 element.appendChild(localContainer); 2632 } 2633 localContainer.setAttribute('id', 'Cocos2dGameContainer'); 2634 localContainer.appendChild(localCanvas); 2635 this.frame = (localContainer.parentNode === document.body) ? document.documentElement : localContainer.parentNode; 2636 2637 localCanvas.addClass("gameCanvas"); 2638 localCanvas.setAttribute("width", width || 480); 2639 localCanvas.setAttribute("height", height || 320); 2640 localCanvas.setAttribute("tabindex", 99); 2641 localCanvas.style.outline = "none"; 2642 localConStyle = localContainer.style; 2643 localConStyle.width = (width || 480) + "px"; 2644 localConStyle.height = (height || 320) + "px"; 2645 localConStyle.margin = "0 auto"; 2646 2647 localConStyle.position = 'relative'; 2648 localConStyle.overflow = 'hidden'; 2649 localContainer.top = '100%'; 2650 2651 if (cc._renderType === cc.game.RENDER_TYPE_WEBGL) { 2652 this._renderContext = cc._renderContext = cc.webglContext 2653 = cc.create3DContext(localCanvas, { 2654 'stencil': true, 2655 'preserveDrawingBuffer': true, 2656 'antialias': !cc.sys.isMobile, 2657 'alpha': true 2658 }); 2659 } 2660 // WebGL context created successfully 2661 if (this._renderContext) { 2662 cc.renderer = cc.rendererWebGL; 2663 win.gl = this._renderContext; // global variable declared in CCMacro.js 2664 cc.renderer.init(); 2665 cc.shaderCache._init(); 2666 cc._drawingUtil = new cc.DrawingPrimitiveWebGL(this._renderContext); 2667 cc.textureCache._initializingRenderer(); 2668 cc.glExt = {}; 2669 cc.glExt.instanced_arrays = gl.getExtension("ANGLE_instanced_arrays"); 2670 cc.glExt.element_uint = gl.getExtension("OES_element_index_uint"); 2671 } else { 2672 cc.renderer = cc.rendererCanvas; 2673 this._renderContext = cc._renderContext = new cc.CanvasContextWrapper(localCanvas.getContext("2d")); 2674 cc._drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(this._renderContext) : null; 2675 } 2676 2677 cc._gameDiv = localContainer; 2678 cc.game.canvas.oncontextmenu = function () { 2679 if (!cc._isContextMenuEnable) return false; 2680 }; 2681 2682 this.dispatchEvent(this.EVENT_RENDERER_INITED, true); 2683 2684 this._rendererInitialized = true; 2685 }, 2686 2687 _initEvents: function () { 2688 var win = window, self = this, hidden, visibilityChange, _undef = "undefined"; 2689 2690 this._eventHide = this._eventHide || new cc.EventCustom(this.EVENT_HIDE); 2691 this._eventHide.setUserData(this); 2692 this._eventShow = this._eventShow || new cc.EventCustom(this.EVENT_SHOW); 2693 this._eventShow.setUserData(this); 2694 2695 // register system events 2696 if (this.config[this.CONFIG_KEY.registerSystemEvent]) 2697 cc.inputManager.registerSystemEvent(this.canvas); 2698 2699 if (!cc.isUndefined(document.hidden)) { 2700 hidden = "hidden"; 2701 visibilityChange = "visibilitychange"; 2702 } else if (!cc.isUndefined(document.mozHidden)) { 2703 hidden = "mozHidden"; 2704 visibilityChange = "mozvisibilitychange"; 2705 } else if (!cc.isUndefined(document.msHidden)) { 2706 hidden = "msHidden"; 2707 visibilityChange = "msvisibilitychange"; 2708 } else if (!cc.isUndefined(document.webkitHidden)) { 2709 hidden = "webkitHidden"; 2710 visibilityChange = "webkitvisibilitychange"; 2711 } 2712 2713 var onHidden = function () { 2714 if (cc.eventManager && cc.game._eventHide) 2715 cc.eventManager.dispatchEvent(cc.game._eventHide); 2716 }; 2717 var onShow = function () { 2718 if (cc.eventManager && cc.game._eventShow) 2719 cc.eventManager.dispatchEvent(cc.game._eventShow); 2720 }; 2721 2722 if (hidden) { 2723 document.addEventListener(visibilityChange, function () { 2724 if (document[hidden]) onHidden(); 2725 else onShow(); 2726 }, false); 2727 } else { 2728 win.addEventListener("blur", onHidden, false); 2729 win.addEventListener("focus", onShow, false); 2730 } 2731 2732 if(navigator.userAgent.indexOf("MicroMessenger") > -1){ 2733 win.onfocus = function(){ onShow() }; 2734 } 2735 2736 if ("onpageshow" in window && "onpagehide" in window) { 2737 win.addEventListener("pagehide", onHidden, false); 2738 win.addEventListener("pageshow", onShow, false); 2739 } 2740 2741 cc.eventManager.addCustomListener(cc.game.EVENT_HIDE, function () { 2742 cc.game.pause(); 2743 }); 2744 cc.eventManager.addCustomListener(cc.game.EVENT_SHOW, function () { 2745 cc.game.resume(); 2746 }); 2747 } 2748 }; 2749 //+++++++++++++++++++++++++something about CCGame end+++++++++++++++++++++++++++++ 2750 2751 Function.prototype.bind = Function.prototype.bind || function (oThis) { 2752 if (!cc.isFunction(this)) { 2753 // closest thing possible to the ECMAScript 5 2754 // internal IsCallable function 2755 throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); 2756 } 2757 2758 var aArgs = Array.prototype.slice.call(arguments, 1), 2759 fToBind = this, 2760 fNOP = function () {}, 2761 fBound = function () { 2762 return fToBind.apply(this instanceof fNOP && oThis 2763 ? this 2764 : oThis, 2765 aArgs.concat(Array.prototype.slice.call(arguments))); 2766 }; 2767 2768 fNOP.prototype = this.prototype; 2769 fBound.prototype = new fNOP(); 2770 2771 return fBound; 2772 }; 2773 2774 cc._urlRegExp = new RegExp( 2775 "^" + 2776 // protocol identifier 2777 "(?:(?:https?|ftp)://)" + 2778 // user:pass authentication 2779 "(?:\\S+(?::\\S*)?@)?" + 2780 "(?:" + 2781 // IP address dotted notation octets 2782 // excludes loopback network 0.0.0.0 2783 // excludes reserved space >= 224.0.0.0 2784 // excludes network & broacast addresses 2785 // (first & last IP address of each class) 2786 "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" + 2787 "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" + 2788 "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" + 2789 "|" + 2790 // host name 2791 "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" + 2792 // domain name 2793 "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" + 2794 // TLD identifier 2795 "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" + 2796 "|" + 2797 "(?:localhost)" + 2798 ")" + 2799 // port number 2800 "(?::\\d{2,5})?" + 2801 // resource path 2802 "(?:/\\S*)?" + 2803 "$", "i" 2804 ); 2805