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