这篇文章先是用中文写的,因为要给老外分享,我又翻译成英文了。(欢迎转载~~~)
cocos2D-javascript使用了jah来管理js文件和资源文件。但是网站上的文档和教程都没有提到如何使用它。一番深入挖掘源代码后,我来分享一下成果。
‘jah’ is the library used by cocos2D-javascript for managing js files and asserts file. But there are not any materials mentioned jah from the document and tutorial in the site. The origin description from the author's github is:
"Jah is simple Node.js framework which enables you to build Web browser based applications using theCommonJS module system. This means you can easily break your application up into separate directories and files and include them when needed using the
require
function."
After digging deep in the src code, I want to share you the result.
init.js:
(function (window) {
var assetURL = STATIC_URL + "assets";
var scripts = [
"http://code.jquery.com/jquery-1.10.2.min.js",
STATIC_URL + "js/lib/cocos2d.js",
STATIC_URL + "js/src/main.js",
STATIC_URL + "js/src/state_machine.js",
STATIC_URL + "js/src/logic_controller.js",
STATIC_URL + "js/src/html_ui.js",
STATIC_URL + "js/src/menu_scene.js",
STATIC_URL + "js/src/loading_scene.js",
STATIC_URL + "js/src/game_scene.js",
STATIC_URL + "js/src/win_scene.js",
];
var assets = [
{baseUri:assetURL, path:"/questions/whois_that_pokemon.jpg", mimeType:"image/jpg"},
];
window.__jah__ = {resources:{}, assetURL: assetURL, __blockReady: true};
function initializeApplication () {
if (window.document.readyState != 'complete') return;
var i = 0
function nextScript () {
if (scripts.length > i) {
addScript(document, scripts[i], nextScript)
i++
} else {
window.__jah__.__triggerReady()
}
}
nextScript();
for(i = 0; i < assets.length; ++i) {
var asset = assets[i];
addAsset(asset.baseUri, asset.path, asset.mimeType);
}
}
function addScript (document, script, callback) {
s = document.createElement('script')
s.type = 'text/javascript'
s.defer = true
s.onload = callback
s.src = script
document.body.appendChild(s)
}
function addAsset(baseUri, path, mimeType) {
__jah__.resources[path] = {data: baseUri + path, mimetype: mimeType, remote: true};
}
if (typeof window.document.onreadystatechange !== 'undefined') {
var listener = window.document.addEventListener('readystatechange', initializeApplication, false)
initializeApplication()
} else if (window.document.readyState) {
var checkReadyState = function () {
if (window.document.readyState == 'complete') {
initializeApplication()
} else {
setTimeout(checkReadyState, 13)
}
}
checkReadyState()
} else {
window.onload = initializeApplication
}
})(window)
作者提供了一套帮助加载模块和资源的模板js,并提供了一套nodejs脚本来帮助build出模块和资源。以上代码是我实例出的代码,并进行过些许改动,不影响作者原意。
Init.js is an template file for initializing module and assert. The above code is an instance with some mine changes to illustrate the principle.
.
这里首先要明确“模块”和“资源”的概念。
Firstly we should define the terms : "module" and "asset".
“模块”是指经过编译的单独的js文件。这里的编译仅仅是一些文法上的包装。可以通过require全局函数来导出模块所暴露的对象,供模块间使用。
"module" refers to the separated js files which have been built. The build here is just some kind of grammar wrapping. The globe function 'require' can be used to export the object which the module wants to expose for external using.
“资源”是指mimeType类型的资源,可以是js脚本,图片文件,视频文件,txt,json文本等……可以通过resource全局函数来引用。目前jah只支持一些文本类型的资源和图片资源。
‘asset’ refers to mime type resources. It can be js script, image, video, txt, json and so on... The globe function 'resource' can be used to reference the wanted asset. For now jah only implements some text type asset and image.
"模块"和“资源”都定义在全了__jah__这个全局变量中的resource对象里了。每一项都是resource中的一个属性对象,通过path作为属性名来查找具体的对象。remote属性表示它是一个“资源”,对于“模块”它的值是false。对“模块”来说,data是一个闭包对象来供程序调用。对“资源”来说,data保存url。
'module' and 'asset' are both listed in the 'resource' object which belongs to the globe object __jah__. The path is as the property name for the key to reference the resource. The 'remote' property means the resource will be loaded as an 'asset'. So the 'module' will has a false value. For 'module', data stands for a closure object for other scripts using. For 'asset', data stands for the url.
window.__jah__.resources[path] = {data: string/closure, mimetype: string, remote: bool};
从init.js内容来看,只看到了addAsset函数添加里__jah__.resource的属性,addScript没有。那是因为remote为false的“module”只能被直接append到dom中去,而“assert”可以被__jah__来动态的加载。
From init.js, we can see only addAsset function adds property to __jah__.resource, addScript not. It is because "module" resource which has a false value on remote property won't be loaded by jah( jah is the one of "modules", it can't be loaded by itself ), but "asset' resource can be loaded by jah dynamiclly.
所以要想利用模块化的特性,部署的js文件必须经过“编译”。以下是一个“模块”文件的例子,你可以看到所谓的“编译”只是加了一个resources属性的封装而已。
To take advantage of the modularization feature, the js must be "built". You can find that the so-called 'build' is just a property wrap in __jah__.resources though the following sample.
__jah__.resources["/main.js"] = {data: function (exports, require, module, __filename, __dirname) {"use strict" // Use strict JavaScript mode
var events = require('events');
var director = require('cocos2d').Director.sharedDirector;
var logic_controller = require('/logic_controller').logic_controller;
function main() {
events.addListener(director, 'ready', function (director) {
logic_controller.Init();
})
director.attachInView(document.getElementById('view'));
director.runPreloadScene();
var img = resource('/questions/whois_that_pokemon.jpg');
}
exports.main = main;
}, mimetype: "application/javascript", remote: false};
The following logic begins to be simple. After initialize the array of 'module' and 'asset', the DOM will complete all the appended scripts. One of them must be cocos2d.js. It will init __jah__ inside function. Then 'require' and 'resource' will be added as globe functions. Do you have an attention on '__triggerReady' ? It will drive to run a preload scene preseted by cocos2D-javascript. In this scene a preloader will be started for loading the asserts in the list one by one. While the process, user can see the process in the process bar of the scene. Of course, you can overload the preload scene to change the representation by what you want.