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