/****************************************************************************
Copyright (c) 2011-2012 cocos2d-x.org
Copyright (c) 2013-2014 Chukong Technologies Inc.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
/**
* The main namespace of Cocos2d-JS, all engine core classes, functions, properties and constants are defined in this namespace
* @namespace
* @name cc
*/
var cc = cc || {};
cc._tmp = cc._tmp || {};
cc._LogInfos = {};
/** @expose */
window._p;
_p = window;
/** @expose */
_p.gl;
/** @expose */
_p.WebGLRenderingContext;
/** @expose */
_p.DeviceOrientationEvent;
/** @expose */
_p.DeviceMotionEvent;
/** @expose */
_p.AudioContext;
/** @expose */
_p.webkitAudioContext;
/** @expose */
_p.mozAudioContext;
_p = Object.prototype;
/** @expose */
_p._super;
/** @expose */
_p.ctor;
delete window._p;
cc.newElement = function (x) {
return document.createElement(x);
};
cc._addEventListener = function (element, type, listener, useCapture) {
element.addEventListener(type, listener, useCapture);
};
//is nodejs ? Used to support node-webkit.
cc._isNodeJs = typeof require !== 'undefined' && require("fs");
/**
* Iterate over an object or an array, executing a function for each matched element.
* @param {object|array} obj
* @param {function} iterator
* @param {object} [context]
*/
cc.each = function (obj, iterator, context) {
if (!obj)
return;
if (obj instanceof Array) {
for (var i = 0, li = obj.length; i < li; i++) {
if (iterator.call(context, obj[i], i) === false)
return;
}
} else {
for (var key in obj) {
if (iterator.call(context, obj[key], key) === false)
return;
}
}
};
/**
* Copy all of the properties in source objects to target object and return the target object.
* @param {object} target
* @param {object} *sources
* @returns {object}
*/
cc.extend = function(target) {
var sources = arguments.length >= 2 ? Array.prototype.slice.call(arguments, 1) : [];
cc.each(sources, function(src) {
for(var key in src) {
if (src.hasOwnProperty(key)) {
target[key] = src[key];
}
}
});
return target;
};
/**
* Check the obj whether is function or not
* @param {*} obj
* @returns {boolean}
*/
cc.isFunction = function(obj) {
return typeof obj == 'function';
};
/**
* Check the obj whether is number or not
* @param {*} obj
* @returns {boolean}
*/
cc.isNumber = function(obj) {
return typeof obj == 'number' || Object.prototype.toString.call(obj) == '[object Number]';
};
/**
* Check the obj whether is string or not
* @param {*} obj
* @returns {boolean}
*/
cc.isString = function(obj) {
return typeof obj == 'string' || Object.prototype.toString.call(obj) == '[object String]';
};
/**
* Check the obj whether is array or not
* @param {*} obj
* @returns {boolean}
*/
cc.isArray = function(obj) {
return Object.prototype.toString.call(obj) == '[object Array]';
};
/**
* Check the obj whether is undefined or not
* @param {*} obj
* @returns {boolean}
*/
cc.isUndefined = function(obj) {
return typeof obj == 'undefined';
};
/**
* Check the obj whether is object or not
* @param {*} obj
* @returns {boolean}
*/
cc.isObject = function(obj) {
var type = typeof obj;
return type == 'function' || (obj && type == 'object');
};
/**
* Check the url whether cross origin
* @param {String} url
* @returns {boolean}
*/
cc.isCrossOrigin = function (url) {
if (!url) {
cc.log("invalid URL");
return false;
}
var startIndex = url.indexOf("://");
if (startIndex == -1)
return false;
var endIndex = url.indexOf("/", startIndex + 3);
var urlOrigin = (endIndex == -1) ? url : url.substring(0, endIndex);
return urlOrigin != location.origin;
};
//+++++++++++++++++++++++++something about async begin+++++++++++++++++++++++++++++++
/**
* Async Pool class, a helper of cc.async
* @param {Object|Array} srcObj
* @param {Number} limit the limit of parallel number
* @param {function} iterator
* @param {function} onEnd
* @param {object} target
* @constructor
*/
cc.AsyncPool = function(srcObj, limit, iterator, onEnd, target){
var self = this;
self._srcObj = srcObj;
self._limit = limit;
self._pool = [];
self._iterator = iterator;
self._iteratorTarget = target;
self._onEnd = onEnd;
self._onEndTarget = target;
self._results = srcObj instanceof Array ? [] : {};
self._isErr = false;
cc.each(srcObj, function(value, index){
self._pool.push({index : index, value : value});
});
self.size = self._pool.length;
self.finishedSize = 0;
self._workingSize = 0;
self._limit = self._limit || self.size;
self.onIterator = function(iterator, target){
self._iterator = iterator;
self._iteratorTarget = target;
};
self.onEnd = function(endCb, endCbTarget){
self._onEnd = endCb;
self._onEndTarget = endCbTarget;
};
self._handleItem = function(){
var self = this;
if(self._pool.length == 0)
return; //return directly if the array's length = 0
if(self._workingSize >= self._limit)
return; //return directly if the working size great equal limit number
var item = self._pool.shift();
var value = item.value, index = item.index;
self._workingSize++;
self._iterator.call(self._iteratorTarget, value, index, function(err){
if(self._isErr)
return;
self.finishedSize++;
self._workingSize--;
if(err) {
self._isErr = true;
if(self._onEnd)
self._onEnd.call(self._onEndTarget, err);
return
}
var arr = Array.prototype.slice.call(arguments, 1);
self._results[this.index] = arr[0];
if(self.finishedSize == self.size) {
if(self._onEnd)
self._onEnd.call(self._onEndTarget, null, self._results);
return
}
self._handleItem();
}.bind(item), self);
};
self.flow = function(){
var self = this;
if(self._pool.length == 0) {
if(self._onEnd)
self._onEnd.call(self._onEndTarget, null, []);
return;
}
for(var i = 0; i < self._limit; i++)
self._handleItem();
}
};
/**
* @class
*/
cc.async = /** @lends cc.async# */{
/**
* Do tasks series.
* @param {Array|Object} tasks
* @param {function} [cb] callback
* @param {Object} [target]
* @return {cc.AsyncPool}
*/
series : function(tasks, cb, target){
var asyncPool = new cc.AsyncPool(tasks, 1, function(func, index, cb1){
func.call(target, cb1);
}, cb, target);
asyncPool.flow();
return asyncPool;
},
/**
* Do tasks parallel.
* @param {Array|Object} tasks
* @param {function} cb callback
* @param {Object} [target]
* @return {cc.AsyncPool}
*/
parallel : function(tasks, cb, target){
var asyncPool = new cc.AsyncPool(tasks, 0, function(func, index, cb1){
func.call(target, cb1);
}, cb, target);
asyncPool.flow();
return asyncPool;
},
/**
* Do tasks waterfall.
* @param {Array|Object} tasks
* @param {function} cb callback
* @param {Object} [target]
* @return {cc.AsyncPool}
*/
waterfall : function(tasks, cb, target){
var args = [];
var asyncPool = new cc.AsyncPool(tasks, 1,
function (func, index, cb1) {
args.push(function (err) {
args = Array.prototype.slice.call(arguments, 1);
cb1.apply(null, arguments);
});
func.apply(target, args);
}, function (err, results) {
if (!cb)
return;
if (err)
return cb.call(target, err);
cb.call(target, null, results[results.length - 1]);
});
asyncPool.flow();
return asyncPool;
},
/**
* Do tasks by iterator.
* @param {Array|Object} tasks
* @param {function|Object} iterator
* @param {function} cb callback
* @param {Object} [target]
* @return {cc.AsyncPool}
*/
map : function(tasks, iterator, cb, target){
var locIterator = iterator;
if(typeof(iterator) == "object"){
cb = iterator.cb;
target = iterator.iteratorTarget;
locIterator = iterator.iterator;
}
var asyncPool = new cc.AsyncPool(tasks, 0, locIterator, cb, target);
asyncPool.flow();
return asyncPool;
},
/**
* Do tasks by iterator limit.
* @param {Array|Object} tasks
* @param {Number} limit
* @param {function} iterator
* @param {function} cb callback
* @param {Object} [target]
*/
mapLimit : function(tasks, limit, iterator, cb, target){
var asyncPool = new cc.AsyncPool(tasks, limit, iterator, cb, target);
asyncPool.flow();
return asyncPool;
}
};
//+++++++++++++++++++++++++something about async end+++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++something about path begin++++++++++++++++++++++++++++++++
/**
* @class
*/
cc.path = /** @lends cc.path# */{
/**
* Join strings to be a path.
* @example
cc.path.join("a", "b.png");//-->"a/b.png"
cc.path.join("a", "b", "c.png");//-->"a/b/c.png"
cc.path.join("a", "b");//-->"a/b"
cc.path.join("a", "b", "/");//-->"a/b/"
cc.path.join("a", "b/", "/");//-->"a/b/"
* @returns {string}
*/
join: function () {
var l = arguments.length;
var result = "";
for (var i = 0; i < l; i++) {
result = (result + (result == "" ? "" : "/") + arguments[i]).replace(/(\/|\\\\)$/, "");
}
return result;
},
/**
* Get the ext name of a path.
* @example
cc.path.extname("a/b.png");//-->".png"
cc.path.extname("a/b.png?a=1&b=2");//-->".png"
cc.path.extname("a/b");//-->null
cc.path.extname("a/b?a=1&b=2");//-->null
* @param {string} pathStr
* @returns {*}
*/
extname: function (pathStr) {
var temp = /(\.[^\.\/\?\\]*)(\?.*)?$/.exec(pathStr);
return temp ? temp[1] : null;
},
/**
* Get the main name of a file name
* @param {string} fileName
* @returns {string}
*/
mainFileName: function(fileName){
if(fileName){
var idx = fileName.lastIndexOf(".");
if(idx !== -1)
return fileName.substring(0,idx);
}
return fileName
},
/**
* Get the file name of a file path.
* @example
cc.path.basename("a/b.png");//-->"b.png"
cc.path.basename("a/b.png?a=1&b=2");//-->"b.png"
cc.path.basename("a/b.png", ".png");//-->"b"
cc.path.basename("a/b.png?a=1&b=2", ".png");//-->"b"
cc.path.basename("a/b.png", ".txt");//-->"b.png"
* @param {string} pathStr
* @param {string} [extname]
* @returns {*}
*/
basename: function (pathStr, extname) {
var index = pathStr.indexOf("?");
if (index > 0) pathStr = pathStr.substring(0, index);
var reg = /(\/|\\\\)([^(\/|\\\\)]+)$/g;
var result = reg.exec(pathStr.replace(/(\/|\\\\)$/, ""));
if (!result) return null;
var baseName = result[2];
if (extname && pathStr.substring(pathStr.length - extname.length).toLowerCase() == extname.toLowerCase())
return baseName.substring(0, baseName.length - extname.length);
return baseName;
},
/**
* Get dirname of a file path.
* @example
* unix
cc.path.driname("a/b/c.png");//-->"a/b"
cc.path.driname("a/b/c.png?a=1&b=2");//-->"a/b"
cc.path.dirname("a/b/");//-->"a/b"
cc.path.dirname("c.png");//-->""
* windows
cc.path.driname("a\\b\\c.png");//-->"a\b"
cc.path.driname("a\\b\\c.png?a=1&b=2");//-->"a\b"
* @param {string} pathStr
* @returns {*}
*/
dirname: function (pathStr) {
return pathStr.replace(/((.*)(\/|\\|\\\\))?(.*?\..*$)?/, '$2');
},
/**
* Change extname of a file path.
* @example
cc.path.changeExtname("a/b.png", ".plist");//-->"a/b.plist"
cc.path.changeExtname("a/b.png?a=1&b=2", ".plist");//-->"a/b.plist?a=1&b=2"
* @param {string} pathStr
* @param {string} [extname]
* @returns {string}
*/
changeExtname: function (pathStr, extname) {
extname = extname || "";
var index = pathStr.indexOf("?");
var tempStr = "";
if (index > 0) {
tempStr = pathStr.substring(index);
pathStr = pathStr.substring(0, index);
}
index = pathStr.lastIndexOf(".");
if (index < 0) return pathStr + extname + tempStr;
return pathStr.substring(0, index) + extname + tempStr;
},
/**
* Change file name of a file path.
* @example
cc.path.changeBasename("a/b/c.plist", "b.plist");//-->"a/b/b.plist"
cc.path.changeBasename("a/b/c.plist?a=1&b=2", "b.plist");//-->"a/b/b.plist?a=1&b=2"
cc.path.changeBasename("a/b/c.plist", ".png");//-->"a/b/c.png"
cc.path.changeBasename("a/b/c.plist", "b");//-->"a/b/b"
cc.path.changeBasename("a/b/c.plist", "b", true);//-->"a/b/b.plist"
* @param {String} pathStr
* @param {String} basename
* @param {Boolean} [isSameExt]
* @returns {string}
*/
changeBasename: function (pathStr, basename, isSameExt) {
if (basename.indexOf(".") == 0) return this.changeExtname(pathStr, basename);
var index = pathStr.indexOf("?");
var tempStr = "";
var ext = isSameExt ? this.extname(pathStr) : "";
if (index > 0) {
tempStr = pathStr.substring(index);
pathStr = pathStr.substring(0, index);
}
index = pathStr.lastIndexOf("/");
index = index <= 0 ? 0 : index + 1;
return pathStr.substring(0, index) + basename + ext + tempStr;
}
};
//+++++++++++++++++++++++++something about path end++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++something about loader start+++++++++++++++++++++++++++
/**
* Loader for resource loading process. It's a singleton object.
* @class
*/
cc.loader = /** @lends cc.loader# */{
_jsCache: {},//cache for js
_register: {},//register of loaders
_langPathCache: {},//cache for lang path
_aliases: {},//aliases for res url
resPath: "",//root path of resource
audioPath: "",//root path of audio
cache: {},//cache for data loaded
/**
* Get XMLHttpRequest.
* @returns {XMLHttpRequest}
*/
getXMLHttpRequest: function () {
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP");
},
//@MODE_BEGIN DEV
_getArgs4Js: function (args) {
var a0 = args[0], a1 = args[1], a2 = args[2], results = ["", null, null];
if (args.length === 1) {
results[1] = a0 instanceof Array ? a0 : [a0];
} else if (args.length === 2) {
if (typeof a1 == "function") {
results[1] = a0 instanceof Array ? a0 : [a0];
results[2] = a1;
} else {
results[0] = a0 || "";
results[1] = a1 instanceof Array ? a1 : [a1];
}
} else if (args.length === 3) {
results[0] = a0 || "";
results[1] = a1 instanceof Array ? a1 : [a1];
results[2] = a2;
} else throw "arguments error to load js!";
return results;
},
/**
* Load js files.
* If the third parameter doesn't exist, then the baseDir turns to be "".
*
* @param {string} [baseDir] The pre path for jsList or the list of js path.
* @param {array} jsList List of js path.
* @param {function} [cb] Callback function
* @returns {*}
*/
loadJs: function (baseDir, jsList, cb) {
var self = this, localJsCache = self._jsCache,
args = self._getArgs4Js(arguments);
var preDir = args[0], list = args[1], callback = args[2];
if (navigator.userAgent.indexOf("Trident/5") > -1) {
self._loadJs4Dependency(preDir, list, 0, callback);
} else {
cc.async.map(list, function (item, index, cb1) {
var jsPath = cc.path.join(preDir, item);
if (localJsCache[jsPath]) return cb1(null);
self._createScript(jsPath, false, cb1);
}, callback);
}
},
/**
* Load js width loading image.
*
* @param {string} [baseDir]
* @param {array} jsList
* @param {function} [cb]
*/
loadJsWithImg: function (baseDir, jsList, cb) {
var self = this, jsLoadingImg = self._loadJsImg(),
args = self._getArgs4Js(arguments);
this.loadJs(args[0], args[1], function (err) {
if (err) throw err;
jsLoadingImg.parentNode.removeChild(jsLoadingImg);//remove loading gif
if (args[2]) args[2]();
});
},
_createScript: function (jsPath, isAsync, cb) {
var d = document, self = this, s = cc.newElement('script');
s.async = isAsync;
s.src = jsPath;
self._jsCache[jsPath] = true;
cc._addEventListener(s, 'load', function () {
s.parentNode.removeChild(s);
this.removeEventListener('load', arguments.callee, false);
cb();
}, false);
cc._addEventListener(s, 'error', function () {
s.parentNode.removeChild(s);
cb("Load " + jsPath + " failed!");
}, false);
d.body.appendChild(s);
},
_loadJs4Dependency: function (baseDir, jsList, index, cb) {
if (index >= jsList.length) {
if (cb) cb();
return;
}
var self = this;
self._createScript(cc.path.join(baseDir, jsList[index]), false, function (err) {
if (err) return cb(err);
self._loadJs4Dependency(baseDir, jsList, index + 1, cb);
});
},
_loadJsImg: function () {
var d = document, jsLoadingImg = d.getElementById("cocos2d_loadJsImg");
if (!jsLoadingImg) {
jsLoadingImg = cc.newElement('img');
if (cc._loadingImage)
jsLoadingImg.src = cc._loadingImage;
var canvasNode = d.getElementById(cc.game.config["id"]);
canvasNode.style.backgroundColor = "#f6f6f6";
canvasNode.parentNode.appendChild(jsLoadingImg);
var canvasStyle = getComputedStyle ? getComputedStyle(canvasNode) : canvasNode.currentStyle;
if (!canvasStyle)
canvasStyle = {width: canvasNode.width, height: canvasNode.height};
jsLoadingImg.style.left = canvasNode.offsetLeft + (parseFloat(canvasStyle.width) - jsLoadingImg.width) / 2 + "px";
jsLoadingImg.style.top = canvasNode.offsetTop + (parseFloat(canvasStyle.height) - jsLoadingImg.height) / 2 + "px";
jsLoadingImg.style.position = "absolute";
}
return jsLoadingImg;
},
//@MODE_END DEV
/**
* Load a single resource as txt.
* @param {string} url
* @param {function} [cb] arguments are : err, txt
*/
loadTxt: function (url, cb) {
if (!cc._isNodeJs) {
var xhr = this.getXMLHttpRequest(),
errInfo = "load " + url + " failed!";
xhr.open("GET", url, true);
if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
// IE-specific logic here
xhr.setRequestHeader("Accept-Charset", "utf-8");
xhr.onreadystatechange = function () {
if(xhr.readyState == 4)
xhr.status == 200 ? cb(null, xhr.responseText) : cb(errInfo);
};
} else {
if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8");
xhr.onload = function () {
if(xhr.readyState == 4)
xhr.status == 200 ? cb(null, xhr.responseText) : cb(errInfo);
};
}
xhr.send(null);
} else {
var fs = require("fs");
fs.readFile(url, function (err, data) {
err ? cb(err) : cb(null, data.toString());
});
}
},
_loadTxtSync: function (url) {
if (!cc._isNodeJs) {
var xhr = this.getXMLHttpRequest();
xhr.open("GET", url, false);
if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
// IE-specific logic here
xhr.setRequestHeader("Accept-Charset", "utf-8");
} else {
if (xhr.overrideMimeType) xhr.overrideMimeType("text\/plain; charset=utf-8");
}
xhr.send(null);
if (!xhr.readyState == 4 || xhr.status != 200) {
return null;
}
return xhr.responseText;
} else {
var fs = require("fs");
return fs.readFileSync(url).toString();
}
},
/**
* Load a single resource as json.
* @param {string} url
* @param {function} [cb] arguments are : err, json
*/
loadJson: function (url, cb) {
this.loadTxt(url, function (err, txt) {
try {
err ? cb(err) : cb(null, JSON.parse(txt));
} catch (e) {
throw "load json [" + url + "] failed : " + e;
}
});
},
_checkIsImageURL: function (url) {
var ext = /(\.png)|(\.jpg)|(\.bmp)|(\.jpeg)|(\.gif)/.exec(url);
return (ext != null);
},
/**
* Load a single image.
* @param {!string} url
* @param {object} [option]
* @param {function} cb
* @returns {Image}
*/
loadImg: function (url, option, cb) {
var opt = {
isCrossOrigin: true
};
if (cb !== undefined)
opt.isCrossOrigin = option.isCrossOrigin == null ? opt.isCrossOrigin : option.isCrossOrigin;
else if (option !== undefined)
cb = option;
var img = new Image();
if (opt.isCrossOrigin && location.origin != "file://")
img.crossOrigin = "Anonymous";
var lcb = function () {
this.removeEventListener('load', lcb, false);
this.removeEventListener('error', ecb, false);
if (cb)
cb(null, img);
};
var ecb = function () {
this.removeEventListener('error', ecb, false);
if(img.crossOrigin.toLowerCase() == "anonymous"){
opt.isCrossOrigin = false;
cc.loader.loadImg(url, opt, cb);
}else{
typeof cb == "function" && cb("load image failed");
}
};
cc._addEventListener(img, "load", lcb);
cc._addEventListener(img, "error", ecb);
img.src = url;
return img;
},
/**
* Iterator function to load res
* @param {object} item
* @param {number} index
* @param {function} [cb]
* @returns {*}
* @private
*/
_loadResIterator: function (item, index, cb) {
var self = this, url = null;
var type = item.type;
if (type) {
type = "." + type.toLowerCase();
url = item.src ? item.src : item.name + type;
} else {
url = item;
type = cc.path.extname(url);
}
var obj = self.cache[url];
if (obj)
return cb(null, obj);
var loader = self._register[type.toLowerCase()];
if (!loader) {
cc.error("loader for [" + type + "] not exists!");
return cb();
}
var basePath = loader.getBasePath ? loader.getBasePath() : self.resPath;
var realUrl = self.getUrl(basePath, url);
loader.load(realUrl, url, item, function (err, data) {
if (err) {
cc.log(err);
self.cache[url] = null;
delete self.cache[url];
cb();
} else {
self.cache[url] = data;
cb(null, data);
}
});
},
/**
* Get url with basePath.
* @param {string} basePath
* @param {string} [url]
* @returns {*}
*/
getUrl: function (basePath, url) {
var self = this, langPathCache = self._langPathCache, path = cc.path;
if (basePath !== undefined && url === undefined) {
url = basePath;
var type = path.extname(url);
type = type ? type.toLowerCase() : "";
var loader = self._register[type];
if (!loader)
basePath = self.resPath;
else
basePath = loader.getBasePath ? loader.getBasePath() : self.resPath;
}
url = cc.path.join(basePath || "", url);
if (url.match(/[\/(\\\\)]lang[\/(\\\\)]/i)) {
if (langPathCache[url])
return langPathCache[url];
var extname = path.extname(url) || "";
url = langPathCache[url] = url.substring(0, url.length - extname.length) + "_" + cc.sys.language + extname;
}
return url;
},
/**
* Load resources then call the callback.
* @param {string} resources
* @param {function} [option] callback or trigger
* @param {function|Object} [cb]
* @return {cc.AsyncPool}
*/
load : function(resources, option, cb){
var self = this;
var len = arguments.length;
if(len == 0)
throw "arguments error!";
if(len == 3){
if(typeof option == "function"){
if(typeof cb == "function")
option = {trigger : option, cb : cb };
else
option = { cb : option, cbTarget : cb};
}
}else if(len == 2){
if(typeof option == "function")
option = {cb : option};
}else if(len == 1){
option = {};
}
if(!(resources instanceof Array))
resources = [resources];
var asyncPool = new cc.AsyncPool(resources, 0, function(value, index, cb1, aPool){
self._loadResIterator(value, index, function(err){
if(err)
return cb1(err);
var arr = Array.prototype.slice.call(arguments, 1);
if(option.trigger)
option.trigger.call(option.triggerTarget, arr[0], aPool.size, aPool.finishedSize); //call trigger
cb1(null, arr[0]);
});
}, option.cb, option.cbTarget);
asyncPool.flow();
return asyncPool;
},
_handleAliases: function (fileNames, cb) {
var self = this, aliases = self._aliases;
var resList = [];
for (var key in fileNames) {
var value = fileNames[key];
aliases[key] = value;
resList.push(value);
}
this.load(resList, cb);
},
/**
*
* Loads alias map from the contents of a filename.
*
* @note The plist file name should follow the format below:
*
*
*
*
* filenames
*
* sounds/click.wav
* sounds/click.caf
* sounds/endgame.wav
* sounds/endgame.caf
* sounds/gem-0.wav
* sounds/gem-0.caf
*
* metadata
*
* version
* 1
*
*
*
*
* @param {String} url The plist file name.
* @param {Function} [cb] callback
*/
loadAliases: function (url, cb) {
var self = this, dict = self.getRes(url);
if (!dict) {
self.load(url, function (err, results) {
self._handleAliases(results[0]["filenames"], cb);
});
} else
self._handleAliases(dict["filenames"], cb);
},
/**
* Register a resource loader into loader.
* @param {string} extNames
* @param {function} loader
*/
register: function (extNames, loader) {
if (!extNames || !loader) return;
var self = this;
if (typeof extNames == "string")
return this._register[extNames.trim().toLowerCase()] = loader;
for (var i = 0, li = extNames.length; i < li; i++) {
self._register["." + extNames[i].trim().toLowerCase()] = loader;
}
},
/**
* Get resource data by url.
* @param url
* @returns {*}
*/
getRes: function (url) {
return this.cache[url] || this.cache[this._aliases[url]];
},
/**
* Release the cache of resource by url.
* @param url
*/
release: function (url) {
var cache = this.cache, aliases = this._aliases;
delete cache[url];
delete cache[aliases[url]];
delete aliases[url];
},
/**
* Resource cache of all resources.
*/
releaseAll: function () {
var locCache = this.cache, aliases = this._aliases;
for (var key in locCache)
delete locCache[key];
for (var key in aliases)
delete aliases[key];
}
};
//+++++++++++++++++++++++++something about loader end+++++++++++++++++++++++++++++
/**
* A string tool to construct a string with format string.
* for example:
* cc.formatStr("a: %d, b: %b", a, b);
* cc.formatStr(a, b, c);
* @returns {String}
*/
cc.formatStr = function(){
var args = arguments;
var l = args.length;
if(l < 1)
return "";
var str = args[0];
var needToFormat = true;
if(typeof str == "object"){
needToFormat = false;
}
for(var i = 1; i < l; ++i){
var arg = args[i];
if(needToFormat){
while(true){
var result = null;
if(typeof arg == "number"){
result = str.match(/(%d)|(%s)/);
if(result){
str = str.replace(/(%d)|(%s)/, arg);
break;
}
}
result = str.match(/%s/);
if(result)
str = str.replace(/%s/, arg);
else
str += " " + arg;
break;
}
}else
str += " " + arg;
}
return str;
};
//+++++++++++++++++++++++++something about window events begin+++++++++++++++++++++++++++
(function () {
var win = window, hidden, visibilityChange, _undef = "undefined";
if (!cc.isUndefined(document.hidden)) {
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (!cc.isUndefined(document.mozHidden)) {
hidden = "mozHidden";
visibilityChange = "mozvisibilitychange";
} else if (!cc.isUndefined(document.msHidden)) {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (!cc.isUndefined(document.webkitHidden)) {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
var onHidden = function () {
if (cc.eventManager && cc.game._eventHide)
cc.eventManager.dispatchEvent(cc.game._eventHide);
};
var onShow = function () {
if (cc.eventManager && cc.game._eventShow)
cc.eventManager.dispatchEvent(cc.game._eventShow);
if(cc.game._intervalId){
window.cancelAnimationFrame(cc.game._intervalId);
cc.game._runMainLoop();
}
};
if (hidden) {
cc._addEventListener(document, visibilityChange, function () {
if (document[hidden]) onHidden();
else onShow();
}, false);
} else {
cc._addEventListener(win, "blur", onHidden, false);
cc._addEventListener(win, "focus", onShow, false);
}
if(navigator.userAgent.indexOf("MicroMessenger") > -1){
win.onfocus = function(){ onShow() };
}
if ("onpageshow" in window && "onpagehide" in window) {
cc._addEventListener(win, "pagehide", onHidden, false);
cc._addEventListener(win, "pageshow", onShow, false);
}
win = null;
visibilityChange = null;
})();
//+++++++++++++++++++++++++something about window events end+++++++++++++++++++++++++++++
//+++++++++++++++++++++++++something about log start++++++++++++++++++++++++++++
//to make sure the cc.log, cc.warn, cc.error and cc.assert would not throw error before init by debugger mode.
cc.log = cc.warn = cc.error = cc.assert = function () {
};
//+++++++++++++++++++++++++something about log end+++++++++++++++++++++++++++++
/**
* create a webgl context
* @param {HTMLCanvasElement} canvas
* @param {Object} opt_attribs
* @return {WebGLRenderingContext}
*/
cc.create3DContext = function (canvas, opt_attribs) {
var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
var context = null;
for (var ii = 0; ii < names.length; ++ii) {
try {
context = canvas.getContext(names[ii], opt_attribs);
} catch (e) {
}
if (context) {
break;
}
}
return context;
};
//+++++++++++++++++++++++++something about sys begin+++++++++++++++++++++++++++++
cc._initSys = function (config, CONFIG_KEY) {
/**
* Canvas of render type
* @constant
* @type {Number}
*/
cc._RENDER_TYPE_CANVAS = 0;
/**
* WebGL of render type
* @constant
* @type {Number}
*/
cc._RENDER_TYPE_WEBGL = 1;
/**
* System variables
* @namespace
* @name cc.sys
*/
cc.sys = {};
var sys = cc.sys;
/**
* English language code
* @memberof cc.sys
* @name LANGUAGE_ENGLISH
* @constant
* @type {Number}
*/
sys.LANGUAGE_ENGLISH = "en";
/**
* Chinese language code
* @memberof cc.sys
* @name LANGUAGE_CHINESE
* @constant
* @type {Number}
*/
sys.LANGUAGE_CHINESE = "zh";
/**
* French language code
* @memberof cc.sys
* @name LANGUAGE_FRENCH
* @constant
* @type {Number}
*/
sys.LANGUAGE_FRENCH = "fr";
/**
* Italian language code
* @memberof cc.sys
* @name LANGUAGE_ITALIAN
* @constant
* @type {Number}
*/
sys.LANGUAGE_ITALIAN = "it";
/**
* German language code
* @memberof cc.sys
* @name LANGUAGE_GERMAN
* @constant
* @type {Number}
*/
sys.LANGUAGE_GERMAN = "de";
/**
* Spanish language code
* @memberof cc.sys
* @name LANGUAGE_SPANISH
* @constant
* @type {Number}
*/
sys.LANGUAGE_SPANISH = "es";
/**
* Spanish language code
* @memberof cc.sys
* @name LANGUAGE_DUTCH
* @constant
* @type {Number}
*/
sys.LANGUAGE_DUTCH = "du";
/**
* Russian language code
* @memberof cc.sys
* @name LANGUAGE_RUSSIAN
* @constant
* @type {Number}
*/
sys.LANGUAGE_RUSSIAN = "ru";
/**
* Korean language code
* @memberof cc.sys
* @name LANGUAGE_KOREAN
* @constant
* @type {Number}
*/
sys.LANGUAGE_KOREAN = "ko";
/**
* Japanese language code
* @memberof cc.sys
* @name LANGUAGE_JAPANESE
* @constant
* @type {Number}
*/
sys.LANGUAGE_JAPANESE = "ja";
/**
* Hungarian language code
* @memberof cc.sys
* @name LANGUAGE_HUNGARIAN
* @constant
* @type {Number}
*/
sys.LANGUAGE_HUNGARIAN = "hu";
/**
* Portuguese language code
* @memberof cc.sys
* @name LANGUAGE_PORTUGUESE
* @constant
* @type {Number}
*/
sys.LANGUAGE_PORTUGUESE = "pt";
/**
* Arabic language code
* @memberof cc.sys
* @name LANGUAGE_ARABIC
* @constant
* @type {Number}
*/
sys.LANGUAGE_ARABIC = "ar";
/**
* Norwegian language code
* @memberof cc.sys
* @name LANGUAGE_NORWEGIAN
* @constant
* @type {Number}
*/
sys.LANGUAGE_NORWEGIAN = "no";
/**
* Polish language code
* @memberof cc.sys
* @name LANGUAGE_POLISH
* @constant
* @type {Number}
*/
sys.LANGUAGE_POLISH = "pl";
/**
* @memberof cc.sys
* @name OS_WINDOWS
* @constant
* @type {string}
*/
sys.OS_WINDOWS = "Windows";
/**
* @memberof cc.sys
* @name OS_IOS
* @constant
* @type {string}
*/
sys.OS_IOS = "iOS";
/**
* @memberof cc.sys
* @name OS_OSX
* @constant
* @type {string}
*/
sys.OS_OSX = "OS X";
/**
* @memberof cc.sys
* @name OS_UNIX
* @constant
* @type {string}
*/
sys.OS_UNIX = "UNIX";
/**
* @memberof cc.sys
* @name OS_LINUX
* @constant
* @type {string}
*/
sys.OS_LINUX = "Linux";
/**
* @memberof cc.sys
* @name OS_ANDROID
* @constant
* @type {string}
*/
sys.OS_ANDROID = "Android";
/**
* @memberof cc.sys
* @name OS_UNKNOWN
* @constant
* @type {string}
*/
sys.OS_UNKNOWN = "Unknown";
/**
* @memberof cc.sys
* @name WINDOWS
* @constant
* @default
* @type {Number}
*/
sys.WINDOWS = 0;
/**
* @memberof cc.sys
* @name LINUX
* @constant
* @default
* @type {Number}
*/
sys.LINUX = 1;
/**
* @memberof cc.sys
* @name MACOS
* @constant
* @default
* @type {Number}
*/
sys.MACOS = 2;
/**
* @memberof cc.sys
* @name ANDROID
* @constant
* @default
* @type {Number}
*/
sys.ANDROID = 3;
/**
* @memberof cc.sys
* @name IPHONE
* @constant
* @default
* @type {Number}
*/
sys.IPHONE = 4;
/**
* @memberof cc.sys
* @name IPAD
* @constant
* @default
* @type {Number}
*/
sys.IPAD = 5;
/**
* @memberof cc.sys
* @name BLACKBERRY
* @constant
* @default
* @type {Number}
*/
sys.BLACKBERRY = 6;
/**
* @memberof cc.sys
* @name NACL
* @constant
* @default
* @type {Number}
*/
sys.NACL = 7;
/**
* @memberof cc.sys
* @name EMSCRIPTEN
* @constant
* @default
* @type {Number}
*/
sys.EMSCRIPTEN = 8;
/**
* @memberof cc.sys
* @name TIZEN
* @constant
* @default
* @type {Number}
*/
sys.TIZEN = 9;
/**
* @memberof cc.sys
* @name WINRT
* @constant
* @default
* @type {Number}
*/
sys.WINRT = 10;
/**
* @memberof cc.sys
* @name WP8
* @constant
* @default
* @type {Number}
*/
sys.WP8 = 11;
/**
* @memberof cc.sys
* @name MOBILE_BROWSER
* @constant
* @default
* @type {Number}
*/
sys.MOBILE_BROWSER = 100;
/**
* @memberof cc.sys
* @name DESKTOP_BROWSER
* @constant
* @default
* @type {Number}
*/
sys.DESKTOP_BROWSER = 101;
sys.BROWSER_TYPE_WECHAT = "wechat";
sys.BROWSER_TYPE_ANDROID = "androidbrowser";
sys.BROWSER_TYPE_IE = "ie";
sys.BROWSER_TYPE_QQ = "qqbrowser";
sys.BROWSER_TYPE_MOBILE_QQ = "mqqbrowser";
sys.BROWSER_TYPE_UC = "ucbrowser";
sys.BROWSER_TYPE_360 = "360browser";
sys.BROWSER_TYPE_BAIDU_APP = "baiduboxapp";
sys.BROWSER_TYPE_BAIDU = "baidubrowser";
sys.BROWSER_TYPE_MAXTHON = "maxthon";
sys.BROWSER_TYPE_OPERA = "opera";
sys.BROWSER_TYPE_OUPENG = "oupeng";
sys.BROWSER_TYPE_MIUI = "miuibrowser";
sys.BROWSER_TYPE_FIREFOX = "firefox";
sys.BROWSER_TYPE_SAFARI = "safari";
sys.BROWSER_TYPE_CHROME = "chrome";
sys.BROWSER_TYPE_UNKNOWN = "unknown";
/**
* Is native ? This is set to be true in jsb auto.
* @memberof cc.sys
* @name isNative
* @type {Boolean}
*/
sys.isNative = false;
var webglWhiteList = [sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_SAFARI];
var multipleAudioWhiteList = [
sys.BROWSER_TYPE_BAIDU, sys.BROWSER_TYPE_OPERA, sys.BROWSER_TYPE_FIREFOX, sys.BROWSER_TYPE_CHROME, sys.BROWSER_TYPE_BAIDU_APP,
sys.BROWSER_TYPE_SAFARI, sys.BROWSER_TYPE_UC, sys.BROWSER_TYPE_QQ, sys.BROWSER_TYPE_MOBILE_QQ, sys.BROWSER_TYPE_IE
];
var win = window, nav = win.navigator, doc = document, docEle = doc.documentElement;
var ua = nav.userAgent.toLowerCase();
/**
* Indicate whether system is mobile system
* @memberof cc.sys
* @name isMobile
* @type {Boolean}
*/
sys.isMobile = ua.indexOf('mobile') != -1 || ua.indexOf('android') != -1;
/**
* Indicate the running platform
* @memberof cc.sys
* @name platform
* @type {Number}
*/
sys.platform = sys.isMobile ? sys.MOBILE_BROWSER : sys.DESKTOP_BROWSER;
var currLanguage = nav.language;
currLanguage = currLanguage ? currLanguage : nav.browserLanguage;
currLanguage = currLanguage ? currLanguage.split("-")[0] : sys.LANGUAGE_ENGLISH;
/**
* Indicate the current language of the running system
* @memberof cc.sys
* @name language
* @type {String}
*/
sys.language = currLanguage;
var browserType = sys.BROWSER_TYPE_UNKNOWN;
var browserTypes = ua.match(/micromessenger|qqbrowser|mqqbrowser|ucbrowser|360browser|baiduboxapp|baidubrowser|maxthon|trident|oupeng|opera|miuibrowser|firefox/i)
|| ua.match(/chrome|safari/i);
if (browserTypes && browserTypes.length > 0) {
browserType = browserTypes[0].toLowerCase();
if (browserType == 'micromessenger') {
browserType = sys.BROWSER_TYPE_WECHAT;
} else if (browserType === "safari" && (ua.match(/android.*applewebkit/)))
browserType = sys.BROWSER_TYPE_ANDROID;
else if (browserType == "trident") browserType = sys.BROWSER_TYPE_IE;
}
/**
* Indicate the running browser type
* @memberof cc.sys
* @name browserType
* @type {String}
*/
sys.browserType = browserType;
sys._supportMultipleAudio = multipleAudioWhiteList.indexOf(sys.browserType) > -1;
//++++++++++++++++++something about cc._renderTYpe and cc._supportRender begin++++++++++++++++++++++++++++
var userRenderMode = parseInt(config[CONFIG_KEY.renderMode]);
var renderType = cc._RENDER_TYPE_WEBGL;
var tempCanvas = cc.newElement("Canvas");
cc._supportRender = true;
var notInWhiteList = webglWhiteList.indexOf(sys.browserType) == -1;
if (userRenderMode === 1 || (userRenderMode === 0 && (sys.isMobile || notInWhiteList)) || (location.origin == "file://")) {
renderType = cc._RENDER_TYPE_CANVAS;
}
sys._canUseCanvasNewBlendModes = function(){
var canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
var context = canvas.getContext('2d');
context.fillStyle = '#000';
context.fillRect(0,0,1,1);
context.globalCompositeOperation = 'multiply';
var canvas2 = document.createElement('canvas');
canvas2.width = 1;
canvas2.height = 1;
var context2 = canvas2.getContext('2d');
context2.fillStyle = '#fff';
context2.fillRect(0,0,1,1);
context.drawImage(canvas2, 0, 0, 1, 1);
return context.getImageData(0,0,1,1).data[0] === 0;
};
//Whether or not the Canvas BlendModes are supported.
sys._supportCanvasNewBlendModes = sys._canUseCanvasNewBlendModes();
if (renderType == cc._RENDER_TYPE_WEBGL) {
if (!win.WebGLRenderingContext
|| !cc.create3DContext(tempCanvas, {'stencil': true, 'preserveDrawingBuffer': true })) {
if (userRenderMode == 0) renderType = cc._RENDER_TYPE_CANVAS;
else cc._supportRender = false;
}
}
if (renderType == cc._RENDER_TYPE_CANVAS) {
try {
tempCanvas.getContext("2d");
} catch (e) {
cc._supportRender = false;
}
}
cc._renderType = renderType;
//++++++++++++++++++something about cc._renderTYpe and cc._supportRender end++++++++++++++++++++++++++++++
// check if browser supports Web Audio
// check Web Audio's context
try {
sys._supportWebAudio = !!(new (win.AudioContext || win.webkitAudioContext || win.mozAudioContext)());
} catch (e) {
sys._supportWebAudio = false;
}
/**
* cc.sys.localStorage is a local storage component.
* @memberof cc.sys
* @name localStorage
* @type {Object}
*/
try {
var localStorage = sys.localStorage = win.localStorage;
localStorage.setItem("storage", "");
localStorage.removeItem("storage");
localStorage = null;
} catch (e) {
if (e.name === "SECURITY_ERR" || e.name === "QuotaExceededError") {
cc.warn("Warning: localStorage isn't enabled. Please confirm browser cookie or privacy option");
}
sys.localStorage = function () {
};
}
var capabilities = sys.capabilities = {"canvas": true};
if (cc._renderType == cc._RENDER_TYPE_WEBGL)
capabilities["opengl"] = true;
if (docEle['ontouchstart'] !== undefined || nav.msPointerEnabled)
capabilities["touches"] = true;
if (docEle['onmouseup'] !== undefined)
capabilities["mouse"] = true;
if (docEle['onkeyup'] !== undefined)
capabilities["keyboard"] = true;
if (win.DeviceMotionEvent || win.DeviceOrientationEvent)
capabilities["accelerometer"] = true;
// Get the os of system
var iOS = ( ua.match(/(iPad|iPhone|iPod)/i) ? true : false );
var isAndroid = ua.match(/android/i) || nav.platform.match(/android/i) ? true : false;
var osName = sys.OS_UNKNOWN;
if (nav.appVersion.indexOf("Win") != -1) osName = sys.OS_WINDOWS;
else if (iOS) osName = sys.OS_IOS;
else if (nav.appVersion.indexOf("Mac") != -1) osName = sys.OS_OSX;
else if (nav.appVersion.indexOf("X11") != -1) osName = sys.OS_UNIX;
else if (isAndroid) osName = sys.OS_ANDROID;
else if (nav.appVersion.indexOf("Linux") != -1) osName = sys.OS_LINUX;
/**
* Indicate the running os name
* @memberof cc.sys
* @name os
* @type {String}
*/
sys.os = osName;
/**
* Forces the garbage collection
* @memberof cc.sys
* @name garbageCollect
* @function
*/
sys.garbageCollect = function () {
// N/A in cocos2d-html5
};
/**
* Dumps rooted objects
* @memberof cc.sys
* @name dumpRoot
* @function
*/
sys.dumpRoot = function () {
// N/A in cocos2d-html5
};
/**
* Restart the JS VM
* @memberof cc.sys
* @name restartVM
* @function
*/
sys.restartVM = function () {
// N/A in cocos2d-html5
};
/**
* Dump system informations
* @memberof cc.sys
* @name dump
* @function
*/
sys.dump = function () {
var self = this;
var str = "";
str += "isMobile : " + self.isMobile + "\r\n";
str += "language : " + self.language + "\r\n";
str += "browserType : " + self.browserType + "\r\n";
str += "capabilities : " + JSON.stringify(self.capabilities) + "\r\n";
str += "os : " + self.os + "\r\n";
str += "platform : " + self.platform + "\r\n";
cc.log(str);
}
};
//+++++++++++++++++++++++++something about sys end+++++++++++++++++++++++++++++
//+++++++++++++++++++++++++something about CCGame begin+++++++++++++++++++++++++++
/**
* Device oriented vertically, home button on the bottom
* @constant
* @type {Number}
*/
cc.ORIENTATION_PORTRAIT = 0;
/**
* Device oriented vertically, home button on the top
* @constant
* @type {Number}
*/
cc.ORIENTATION_PORTRAIT_UPSIDE_DOWN = 1;
/**
* Device oriented horizontally, home button on the right
* @constant
* @type {Number}
*/
cc.ORIENTATION_LANDSCAPE_LEFT = 2;
/**
* Device oriented horizontally, home button on the left
* @constant
* @type {Number}
*/
cc.ORIENTATION_LANDSCAPE_RIGHT = 3;
/**
* drawing primitive of game engine
* @type {cc.DrawingPrimitive}
*/
cc._drawingUtil = null;
/**
* main Canvas 2D/3D Context of game engine
* @type {CanvasRenderingContext2D|WebGLRenderingContext}
*/
cc._renderContext = null;
/**
* main Canvas of game engine
* @type {HTMLCanvasElement}
*/
cc._canvas = null;
/**
* This Div element contain all game canvas
* @type {HTMLDivElement}
*/
cc._gameDiv = null;
cc._rendererInitialized = false;
/**
*
* setup game main canvas,renderContext,gameDiv and drawingUtil with argument
*
* can receive follow type of arguemnt:
* - empty: create a canvas append to document's body, and setup other option
* - string: search the element by document.getElementById(),
* if this element is HTMLCanvasElement, set this element as main canvas of engine, and set it's ParentNode as cc._gameDiv.
* if this element is HTMLDivElement, set it's ParentNode to cc._gameDiv, and create a canvas as main canvas of engine.
*
* @function
* @example
* //setup with null
* cc._setup();
*
* // setup with HTMLCanvasElement, gameCanvas is Canvas element
* // declare like this:
* cc._setup("gameCanvas");
*
* //setup with HTMLDivElement, gameDiv is Div element
* // declare like this:
* cc._setup("Cocos2dGameContainer");
*/
cc._setupCalled = false;
cc._setup = function (el, width, height) {
// Avoid setup to be called twice.
if (cc._setupCalled) return;
else cc._setupCalled = true;
var win = window;
var lastTime = new Date();
var frameTime = 1000 / cc.game.config[cc.game.CONFIG_KEY.frameRate];
var stTime = function(callback){
var currTime = new Date().getTime();
var timeToCall = Math.max(0, frameTime - (currTime - lastTime));
var id = window.setTimeout(function() { callback(); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
var ctTime = function(id){
clearTimeout(id);
};
if(cc.sys.os === cc.sys.OS_IOS && cc.sys.browserType === cc.sys.BROWSER_TYPE_WECHAT){
win.requestAnimFrame = stTime;
win.cancelAnimationFrame = ctTime;
}else if(cc.game.config[cc.game.CONFIG_KEY.frameRate] != 60){
win.requestAnimFrame = stTime;
win.cancelAnimationFrame = ctTime;
}else{
win.requestAnimFrame = win.requestAnimationFrame ||
win.webkitRequestAnimationFrame ||
win.mozRequestAnimationFrame ||
win.oRequestAnimationFrame ||
win.msRequestAnimationFrame ||
stTime;
win.cancelAnimationFrame = window.cancelAnimationFrame ||
window.cancelRequestAnimationFrame ||
window.msCancelRequestAnimationFrame ||
window.mozCancelRequestAnimationFrame ||
window.oCancelRequestAnimationFrame ||
window.webkitCancelRequestAnimationFrame ||
window.msCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.oCancelAnimationFrame ||
ctTime;
}
var element = cc.$(el) || cc.$('#' + el);
var localCanvas, localContainer, localConStyle;
if (element.tagName == "CANVAS") {
width = width || element.width;
height = height || element.height;
//it is already a canvas, we wrap it around with a div
localContainer = cc.container = cc.newElement("DIV");
localCanvas = cc._canvas = element;
localCanvas.parentNode.insertBefore(localContainer, localCanvas);
localCanvas.appendTo(localContainer);
localContainer.setAttribute('id', 'Cocos2dGameContainer');
} else {//we must make a new canvas and place into this element
if (element.tagName != "DIV") {
cc.log("Warning: target element is not a DIV or CANVAS");
}
width = width || element.clientWidth;
height = height || element.clientHeight;
localContainer = cc.container = element;
localCanvas = cc._canvas = cc.$(cc.newElement("CANVAS"));
element.appendChild(localCanvas);
}
localCanvas.addClass("gameCanvas");
localCanvas.setAttribute("width", width || 480);
localCanvas.setAttribute("height", height || 320);
localCanvas.setAttribute("tabindex", 99);
localCanvas.style.outline = "none";
localConStyle = localContainer.style;
localConStyle.width = (width || 480) + "px";
localConStyle.height = (height || 320) + "px";
localConStyle.margin = "0 auto";
localConStyle.position = 'relative';
localConStyle.overflow = 'hidden';
localContainer.top = '100%';
if (cc._renderType == cc._RENDER_TYPE_WEBGL)
cc._renderContext = cc.webglContext = cc.create3DContext(localCanvas, {
'stencil': true,
'preserveDrawingBuffer': true,
'antialias': !cc.sys.isMobile,
'alpha': false});
if (cc._renderContext) {
win.gl = cc._renderContext; // global variable declared in CCMacro.js
cc._drawingUtil = new cc.DrawingPrimitiveWebGL(cc._renderContext);
cc._rendererInitialized = true;
cc.textureCache._initializingRenderer();
cc.shaderCache._init();
} else {
cc._renderContext = localCanvas.getContext("2d");
cc._mainRenderContextBackup = cc._renderContext;
cc._renderContext.translate(0, localCanvas.height);
cc._drawingUtil = cc.DrawingPrimitiveCanvas ? new cc.DrawingPrimitiveCanvas(cc._renderContext) : null;
}
cc._gameDiv = localContainer;
cc.log(cc.ENGINE_VERSION);
cc._setContextMenuEnable(false);
if (cc.sys.isMobile) {
var fontStyle = cc.newElement("style");
fontStyle.type = "text/css";
document.body.appendChild(fontStyle);
fontStyle.textContent = "body,canvas,div{ -moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;-khtml-user-select: none;"
+ "-webkit-tap-highlight-color:rgba(0,0,0,0);}";
}
// Init singletons
/**
* @type {cc.EGLView}
* @name cc.view
* cc.view is the shared view object.
*/
cc.view = cc.EGLView._getInstance();
// register system events
cc.inputManager.registerSystemEvent(cc._canvas);
/**
* @type {cc.Director}
* @name cc.director
*/
cc.director = cc.Director._getInstance();
if (cc.director.setOpenGLView)
cc.director.setOpenGLView(cc.view);
/**
* @type {cc.Size}
* @name cc.winSize
* cc.winSize is the alias object for the size of the current game window.
*/
cc.winSize = cc.director.getWinSize();
// Parsers
cc.saxParser = new cc.SAXParser();
/**
* @type {cc.PlistParser}
* @name cc.plistParser
* A Plist Parser
*/
cc.plistParser = new cc.PlistParser();
};
cc._checkWebGLRenderMode = function () {
if (cc._renderType !== cc._RENDER_TYPE_WEBGL)
throw "This feature supports WebGL render mode only.";
};
cc._isContextMenuEnable = false;
/**
* enable/disable contextMenu for Canvas
* @param {Boolean} enabled
*/
cc._setContextMenuEnable = function (enabled) {
cc._isContextMenuEnable = enabled;
cc._canvas.oncontextmenu = function () {
if (!cc._isContextMenuEnable) return false;
};
};
/**
* An object to boot the game.
* @class
* @name cc.game
*/
cc.game = /** @lends cc.game# */{
DEBUG_MODE_NONE: 0,
DEBUG_MODE_INFO: 1,
DEBUG_MODE_WARN: 2,
DEBUG_MODE_ERROR: 3,
DEBUG_MODE_INFO_FOR_WEB_PAGE: 4,
DEBUG_MODE_WARN_FOR_WEB_PAGE: 5,
DEBUG_MODE_ERROR_FOR_WEB_PAGE: 6,
EVENT_HIDE: "game_on_hide",
EVENT_SHOW: "game_on_show",
_eventHide: null,
_eventShow: null,
_onBeforeStartArr: [],
/**
* Key of config
* @constant
* @type {Object}
*/
CONFIG_KEY: {
engineDir: "engineDir",
dependencies: "dependencies",
debugMode: "debugMode",
showFPS: "showFPS",
frameRate: "frameRate",
id: "id",
renderMode: "renderMode",
jsList: "jsList",
classReleaseMode: "classReleaseMode"
},
_prepareCalled: false,//whether the prepare function has been called
_prepared: false,//whether the engine has prepared
_paused: true,//whether the game is paused
_intervalId: null,//interval target of main
/**
* Config of game
* @type {Object}
*/
config: null,
/**
* Callback when the scripts of engine have been load.
* @type {Function}
*/
onStart: null,
/**
* Callback when game exits.
* @type {Function}
*/
onStop: null,
/**
* Set frameRate of game.
* @param frameRate
*/
setFrameRate: function (frameRate) {
var self = this, config = self.config, CONFIG_KEY = self.CONFIG_KEY;
config[CONFIG_KEY.frameRate] = frameRate;
if (self._intervalId)
window.cancelAnimationFrame(self._intervalId);
self._paused = true;
self._runMainLoop();
},
//Run game.
_runMainLoop: function () {
var self = this, callback, config = self.config, CONFIG_KEY = self.CONFIG_KEY,
director = cc.director;
director.setDisplayStats(config[CONFIG_KEY.showFPS]);
callback = function () {
if (!self._paused) {
director.mainLoop();
self._intervalId = window.requestAnimFrame(callback);
}
};
window.requestAnimFrame(callback);
self._paused = false;
},
/**
* Run game.
*/
run: function (id) {
var self = this;
var _run = function () {
if (id) {
self.config[self.CONFIG_KEY.id] = id;
}
if (!self._prepareCalled) {
self.prepare(function () {
self._prepared = true;
});
}
if (cc._supportRender) {
self._checkPrepare = setInterval(function () {
if (self._prepared) {
cc._setup(self.config[self.CONFIG_KEY.id]);
self._runMainLoop();
self._eventHide = self._eventHide || new cc.EventCustom(self.EVENT_HIDE);
self._eventHide.setUserData(self);
self._eventShow = self._eventShow || new cc.EventCustom(self.EVENT_SHOW);
self._eventShow.setUserData(self);
self.onStart();
clearInterval(self._checkPrepare);
}
}, 10);
}
};
document.body ?
_run() :
cc._addEventListener(window, 'load', function () {
this.removeEventListener('load', arguments.callee, false);
_run();
}, false);
},
_initConfig: function () {
var self = this, CONFIG_KEY = self.CONFIG_KEY;
var _init = function (cfg) {
cfg[CONFIG_KEY.engineDir] = cfg[CONFIG_KEY.engineDir] || "frameworks/cocos2d-html5";
if(cfg[CONFIG_KEY.debugMode] == null)
cfg[CONFIG_KEY.debugMode] = 0;
cfg[CONFIG_KEY.frameRate] = cfg[CONFIG_KEY.frameRate] || 60;
if(cfg[CONFIG_KEY.renderMode] == null)
cfg[CONFIG_KEY.renderMode] = 1;
return cfg;
};
if (document["ccConfig"]) {
self.config = _init(document["ccConfig"]);
} else {
try {
var cocos_script = document.getElementsByTagName('script');
for(var i=0;i