Cocos Creator 資源載入流程剖析【三】——Load部分
Load流程是整個資源載入管線的最後一棒,由Loader這個pipe負責(loader.js)。通過Download流程拿到內容之後,需要對內容做一些“載入”處理。使得這些內容可以在遊戲中使用。這裡並不是所有的資源都需要進行一個載入處理,目前只有圖片、Json、Plist、Uuid(Prefab、場景)等資源才會執行載入的流程,其他的資源在Download流程之後就可以在遊戲中使用了。
Loader處理
Loader的handle接收一個item和callback,根據item的type在this.extMap中獲取對應的loadFunc。
Loader.prototype.addHandlers = function (extMap) { this.extMap = JS.mixin(this.extMap, extMap); }; Loader.prototype.handle = function (item, callback) { var loadFunc = this.extMap[item.type] || this.extMap['default']; return loadFunc.call(this, item, callback); };
資源的載入方式
Loader的this.extMap記錄了各種資源型別的下載方式,所有的型別最終都對應這5個載入方法,loadNothing、loadJSON、loadImage、loadPlist、loadUuid,它們對應實現了各種型別資源的載入,通過Loader.addHandlers可以新增或修改任意資源的載入方式。載入結束後將可用的內容返回。
// 無需載入,即經過前面的下載已經可用了,例如font、script等資源 function loadNothing (item, callback) { return null; } // 使用JSON.parse進行解析並返回 function loadJSON (item, callback) { if (typeof item.content !== 'string') { return new Error('JSON Loader: Input item doesn\'t contain string content'); } try { var result = JSON.parse(item.content); return result; } catch (e) { return new Error('JSON Loader: Parse json [' + item.id + '] failed : ' + e); } } // 建立Texture2D,並根據圖片的內容初始化Texture2D,最後新增到cc.textureCache中 function loadImage (item, callback) { if (sys.platform !== sys.WECHAT_GAME && !(item.content instanceof Image)) { return new Error('Image Loader: Input item doesn\'t contain Image content'); } var rawUrl = item.rawUrl; var tex = cc.textureCache.getTextureForKey(rawUrl) || new Texture2D(); tex.url = rawUrl; tex.initWithElement(item.content); tex.handleLoadedTexture(); cc.textureCache.cacheImage(rawUrl, tex); return tex; } // 使用cc.plistParser進行解析並返回 function loadPlist (item, callback) { if (typeof item.content !== 'string') { return new Error('Plist Loader: Input item doesn\'t contain string content'); } var result = cc.plistParser.parse(item.content); if (result) { return result; } else { return new Error('Plist Loader: Parse [' + item.id + '] failed'); } }
loadUuid
loadUuid用於載入creator內部統一規劃的資源,每個uuid都會對應一個json物件,可能是prefab、spriteFrame,等等。在loadUuid這個方法中,最關鍵的操作就是cc.deserialize反序列化把資源物件建立了出來,其次就是載入依賴資源。
uuid的解析首先需要一個json物件,如果item的content是string型別,則進行解析,如果是object型別,則直接使用item.content,如果既不是string也不是object則直接報錯。
function loadUuid (item, callback) { if (CC_EDITOR) { MissingClass = MissingClass || Editor.require('app://editor/page/scene-utils/missing-class-reporter').MissingClass; } // 獲取json物件,如果是string則進行解析,如果是object則直接使用,報錯則返回Error物件 var json; if (typeof item.content === 'string') { try { json = JSON.parse(item.content); } catch (e) { return new Error('Uuid Loader: Parse asset [' + item.id + '] failed : ' + e.stack); } } else if (typeof item.content === 'object') { json = item.content; } else { return new Error('JSON Loader: Input item doesn\'t contain string content'); } // 根據是否場景物件、編輯器環境來決定classFinder的實現。 var classFinder; var isScene = isSceneObj(json); if (isScene) { if (CC_EDITOR) { // 編輯器 + 場景的模式下,使用MissingClass.classFinder作為包裹函式 MissingClass.hasMissingClass = false; classFinder = function (type, data, owner, propName) { var res = MissingClass.classFinder(type, data, owner, propName); if (res) { return res; } return cc._MissingScript.getMissingWrapper(type, data); }; classFinder.onDereferenced = MissingClass.classFinder.onDereferenced; } else { // 非編輯器下,使用cc._MissingScript.safeFindClass,也是呼叫了JS._getClassById // 區別是在解析失敗後會呼叫cc.deserialize.reportMissingClass(id); classFinder = cc._MissingScript.safeFindClass; } } else { classFinder = function (id) { // JS為引擎的platform\js.js,而_getClassById方法從_idToClass[classId]中返回Class // _idToClass為id到類的一個註冊map,key為id,value為class // 使用CCClass定義繼承自cc.Component的類會被自動註冊到_idToClass中 // platform\CCClass.js中的var cls = define(name, base, mixins, options); // 最終呼叫了JS.setClassName,Creator的類的實現細節是另外一個大話題 // 這裡只需要瞭解,所有可拖拽到prefab上的類都會被註冊到JS._idToClass中,這裡的id就是類名 var cls = JS._getClassById(id); if (cls) { return cls; } cc.warnID(4903, id); return Object; }; } // 進行反序列化,反序列化出asset var tdInfo = cc.deserialize.Details.pool.get(); var asset; try { // deserialize的實現位於platform\deserialize.js // 具體的實現非常複雜,大致可以理解為new出對應的類,並從json物件中反序列化該類的所有屬性 // 所以返回的asset是這個json最頂層object對應的類,比如cc.SpriteFrame或者自定義的元件 // 該資源所依賴的所有資源會被反序列化到tdInfo中,在tdInfo.uuidList中。 asset = cc.deserialize(json, tdInfo, { classFinder: classFinder, target: item.existingAsset, customEnv: item }); } catch (e) { cc.deserialize.Details.pool.put(tdInfo); var err = CC_JSB ? (e + '\n' + e.stack) : e.stack; return new Error('Uuid Loader: Deserialize asset [' + item.id + '] failed : ' + err); } // 如果是在編輯器下的場景存在類丟失,進行報告(應該是報紅) asset._uuid = item.uuid; if (CC_EDITOR && isScene && MissingClass.hasMissingClass) { MissingClass.reportMissingClass(asset); } // 判斷是否可延遲載入,並呼叫loadDepends var deferredLoad = canDeferredLoad(asset, item, isScene); loadDepends(this.pipeline, item, asset, tdInfo, deferredLoad, callback); }
canDeferredLoad方法會根據資源型別監測是否可以延遲載入,當item的deferredLoadRaw為true且該資源支援延遲載入(在程式碼中搜索preventDeferredLoadDependents可以發現除了TileMap、DragonBones、Spine等資源外,都不支援延遲載入),或是設定了延遲載入的場景才可以延遲載入。
// can deferred load raw assets in runtime
// 檢查是否延遲載入Raw Assets
function canDeferredLoad (asset, item, isScene) {
if (CC_EDITOR || CC_JSB) {
return false;
}
var res = item.deferredLoadRaw;
if (res) {
// check if asset support deferred
// 檢查該資源是否支援延遲載入
if (asset instanceof cc.Asset && asset.constructor.preventDeferredLoadDependents) {
res = false;
}
} else if (isScene) {
// 如果是prefab或scene,取其asyncLoadAssets屬性
if (asset instanceof cc.SceneAsset || asset instanceof cc.Prefab) {
res = asset.asyncLoadAssets;
}
}
return res;
}
loadDepends方法會載入依賴,主要做了2個事情,延遲載入和依賴載入。
延遲載入指的是資源A依賴了B、C、D,其中資源D延遲載入了,那麼BC載入完成即算這個資源載入完成,並執行回撥,D也會進行載入,但什麼時候載入完這裡並不關心。在實際應用中的表現就是載入一個場景,基礎部分的內容載入完成了,進入了該場景之後再陸續看到其他內容載入完成。
根據deferredLoadRawAssetsInRuntime,對raw型別資源進行延遲載入,延遲載入的內容會進入dependKeys陣列,而不延遲載入的內容進入depends陣列。
depends陣列是該資源所依賴的資源陣列,loadDepends會呼叫pipeline.flowInDeps進行載入,如果該陣列為空則不載入依賴,執行完成回撥。dependKeys陣列是item的屬性,記錄了該資源依賴的所有資源,在做資源釋放的時候會用到。預載入的內容會直接進入dependKeys,而正常載入的資源在載入完成後才會被新增到dependKeys中。
最後呼叫pipeline.flowInDeps載入depends陣列,flowInDeps的完成回撥中,如果item載入完成且沒有報錯,呼叫loadCallback,如果未載入完成,插入到item的queue的 _callbackTable[dependSrc]中或新增queue的監聽(這兩個操作的意義都是在item載入完成後執行loadCallback),loadCallback將依賴物件的依賴屬性進行賦值,並新增該資源的id到dependKeys中。
當反序列化出來的asset._preloadRawFiles有值時,會將callback進行包裹,在非同步載入完RawFiles才執行最終的callback。實際並沒有什麼作用。
function loadDepends (pipeline, item, asset, tdInfo, deferredLoadRawAssetsInRuntime, callback) {
// tdInfo.uuidList為這個prefab或場景所依賴的uuid型別的資源
var uuidList = tdInfo.uuidList;
var objList, propList, depends;
var i, dependUuid;
// cache dependencies for auto release
// dependKeys用於快取該資源的依賴,在資源釋放的時候會用到
var dependKeys = item.dependKeys = [];
/******************************* 過濾決定哪些資源要載入,哪些要延遲,得出depends陣列 **********************************/
// 如果支援延遲載入
if (deferredLoadRawAssetsInRuntime) {
objList = [];
propList = [];
depends = [];
// parse depends assets
for (i = 0; i < uuidList.length; i++) {
dependUuid = uuidList[i];
var obj = tdInfo.uuidObjList[i];
var prop = tdInfo.uuidPropList[i];
var info = cc.AssetLibrary._getAssetInfoInRuntime(dependUuid);
if (info.raw) {
// skip preloading raw assets
// 對於raw型別的資源不進行載入,tdInfo.uuidObjList[i][prop] = url
var url = info.url;
obj[prop] = url;
dependKeys.push(url);
} else {
objList.push(obj);
propList.push(prop);
// declare depends assets
// 對於非raw型別的資源,進入depends進行載入,但帶上deferredLoadRaw標記
// 意為該uuid引用的其他raw型別的資源進行延遲載入
depends.push({
type: 'uuid',
uuid: dependUuid,
deferredLoadRaw: true,
});
}
}
} else {
objList = tdInfo.uuidObjList;
propList = tdInfo.uuidPropList;
depends = new Array(uuidList.length);
// declare depends assets
// 不支援延遲載入則直接進入depends陣列,這裡沒有deferredLoadRaw標記
for (i = 0; i < uuidList.length; i++) {
dependUuid = uuidList[i];
depends[i] = {
type: 'uuid',
uuid: dependUuid
};
}
}
/******************************* tdInfo.rawProp和asset._preloadRawFiles的處理 **********************************/
// declare raw
// 有些json檔案包含了一些raw屬性,以$_$rawType結尾,這裡會直接載入item.url,但目前還未碰到過這樣型別的資源。
// 下面2個說法是錯誤的。
// 如果這個uuid資源本身就是一個raw資源,載入自己?
// 如果這個uuid資源存在raw屬性,例如一個指令碼拖拽了一個Texture2D型別的資源作為它的成員變數?
if (tdInfo.rawProp) {
objList.push(asset);
propList.push(tdInfo.rawProp);
depends.push(item.url);
}
// preload raw files
// 預載入它的raw檔案,這裡是asset的屬性,但從引擎程式碼沒有看到哪裡對這個屬性賦值過
// 不過prefab等檔案倒是有一個_rawFiles的屬性,但從程式碼上看也與這個方法無關,看上去倒像是預留的一個介面
// 提供給開發者做某種資源型別的完成回撥包裝。
if (asset._preloadRawFiles) {
var finalCallback = callback;
callback = function () {
asset._preloadRawFiles(function (err) {
finalCallback(err || null, asset);
});
};
}
// fast path
// 如果沒有資源要載入就直接返回
if (depends.length === 0) {
cc.deserialize.Details.pool.put(tdInfo);
return callback(null, asset);
}
/******************************* 呼叫pipeline.flowInDeps進行依賴載入,資源載入完成後呼叫loadCallback **********************************/
// Predefine content for dependencies usage
// 載入depends,載入完成後註冊到item.dependKeys中,並賦值給this.obj[this.prop]
item.content = asset;
pipeline.flowInDeps(item, depends, function (errors, items) {
// 這個回撥在所有的item都載入完成後執行,所以item都是有的,但有可能有報錯
var item, missingAssetReporter;
for (var src in items.map) {
item = items.map[src];
if (item.uuid && item.content) {
item.content._uuid = item.uuid;
}
}
for (var i = 0; i < depends.length; i++) {
var dependSrc = depends[i].uuid;
var dependUrl = depends[i].url;
var dependObj = objList[i];
var dependProp = propList[i];
item = items.map[dependUrl];
if (item) {
var thisOfLoadCallback = {
obj: dependObj,
prop: dependProp
};
// 資源載入完成的回撥,關聯依賴物件obj的prop為item的value
function loadCallback (item) {
var value = item.isRawAsset ? item.rawUrl : item.content;
this.obj[this.prop] = value;
if (item.uuid !== asset._uuid && dependKeys.indexOf(item.id) < 0) {
dependKeys.push(item.id);
}
}
// 如果資源已經載入完了,且沒有報錯,則執行loadCallback回撥
if (item.complete || item.content) {
if (item.error) {
if (CC_EDITOR && item.error.errorCode === 'db.NOTFOUND') {
if (!missingAssetReporter) {
var MissingObjectReporter = Editor.require('app://editor/page/scene-utils/missing-object-reporter');
missingAssetReporter = new MissingObjectReporter(asset);
}
missingAssetReporter.stashByOwner(dependObj, dependProp, Editor.serialize.asAsset(dependSrc));
} else {
cc._throw(item.error);
}
} else {
loadCallback.call(thisOfLoadCallback, item);
}
} else {
// item was removed from cache, but ready in pipeline actually
// 該item從cache中移除了?但在pipeline中?
// 這裡監聽了該item的載入完成事件,在載入完成時呼叫loadCallback
var queue = LoadingItems.getQueue(item);
// Hack to get a better behavior
// 這個behavior非常的bad,_callbackTable是CallbacksHandler的成員變數
// 兩個操作都是新增監聽,但前者是直接拿到監聽該事件的回撥陣列,強行插入
var list = queue._callbackTable[dependSrc];
if (list) {
list.unshift(loadCallback, thisOfLoadCallback);
} else {
queue.addListener(dependSrc, loadCallback, thisOfLoadCallback);
}
}
}
}
if (CC_EDITOR && missingAssetReporter) {
missingAssetReporter.reportByOwner();
}
cc.deserialize.Details.pool.put(tdInfo);
callback(null, asset);
});
}
CCLoader的flowInDeps,實現如下,傳入資源的owner,依賴列表urlList,以及urlList的回撥。當一個依賴又有依賴的時候,queue的append又會走到這個新資源的loadUuid,去載入那一層所依賴的資源。而flowInDeps開頭的var item = this._cache[res.url] 也確保了資源不會被重複載入。
proto.flowInDeps = function (owner, urlList, callback) {
// 準備_sharedList,已載入或正在載入的資源push item,未載入的push res
_sharedList.length = 0;
for (var i = 0; i < urlList.length; ++i) {
var res = getResWithUrl(urlList[i]);
if (!res.url && ! res.uuid)
continue;
var item = this._cache[res.url];
if (item) {
_sharedList.push(item);
} else {
_sharedList.push(res);
}
}
// 建立一個新的佇列,當有owner時,將子佇列的進度同步到ownerQueue
var queue = LoadingItems.create(this, owner ? function (completedCount, totalCount, item) {
if (this._ownerQueue && this._ownerQueue.onProgress) {
this._ownerQueue._childOnProgress(item);
}
} : null, function (errors, items) {
callback(errors, items);
// Clear deps because it's already done
// Each item will only flowInDeps once, so it's still safe here
// 載入完成後清除owner.deps陣列
owner && owner.deps && (owner.deps.length = 0);
items.destroy();
});
if (owner) {
var ownerQueue = LoadingItems.getQueue(owner);
// Set the root ownerQueue, if no ownerQueue defined in ownerQueue, it's the root
// 設定queue的ownerQueue
queue._ownerQueue = ownerQueue._ownerQueue || ownerQueue;
}
var accepted = queue.append(_sharedList, owner);
_sharedList.length = 0;
return accepted;
};
延遲載入
延遲載入的作用
在creator編輯器中可以設定場景和prefab的延遲載入,設定了延遲載入之後,場景或prefab所引用的一些Raw型別資源如cc.Texture2D、cc.AudioClip等會延遲載入,同時,玩家進入場景後可能會看到一些資源陸續顯示出來,並且啟用新介面時也可能會看到介面中的元素陸續顯示出來,因此這種載入方式更適合網頁遊戲。
具體的實現是在loadUuid中執行canDeferredLoad時,它的asset.asyncLoadAssets為一個Object。在後面的loadDepends方法中會執行deferredLoadRawAssetsInRuntime的判斷。所有Raw型別的資源會被延遲載入,而非Raw型別的資源會被新增到depends陣列中進行載入。最終載入完成時我們可以得到一個不完整的資源(因為它有一部分依賴被延遲載入了)。
延遲載入的資源在什麼時候載入?
從整個Pipeline的載入流程來看,並沒有任何地方去載入這些被延遲的Raw型別資源,而在底層載入圖片的地方進行斷點,可以發現當場景或Prefab被啟用時(新增到場景中),會有一個ensureLoadTexture方法被呼叫,在這裡會執行這些延遲資源的載入流程。所以延遲載入的資源在節點被啟用時會自動載入。下圖是一個延遲載入圖片的呼叫堆疊。
ensureLoadTexture的實現如下所示,AudioClip也類似,在呼叫play播放聲音時會執行preload,檢測到聲音沒有被載入時會執行cc.loader.load方法載入聲音。
/**
* !#en If a loading scene (or prefab) is marked as `asyncLoadAssets`, all the textures of the SpriteFrame which
* associated by user's custom Components in the scene, will not preload automatically.
* These textures will be load when Sprite component is going to render the SpriteFrames.
* You can call this method if you want to load the texture early.
* !#zh 當載入中的場景或 Prefab 被標記為 `asyncLoadAssets` 時,使用者在場景中由自定義元件關聯到的所有 SpriteFrame 的貼圖都不會被提前載入。
* 只有當 Sprite 元件要渲染這些 SpriteFrame 時,才會檢查貼圖是否載入。如果你希望載入過程提前,你可以手工呼叫這個方法。
*/
ensureLoadTexture: function () {
if (!this._texture) {
this._loadTexture();
}
},
_loadTexture: function () {
if (this._textureFilename) {
// 這裡返回的tex可能是一個未載入完成的紋理,如紋理未載入完成,可監聽其載入完成回撥
var texture = cc.textureCache.addImage(this._textureFilename);
this._refreshTexture(texture);
}
},
_refreshTexture: function (texture) {
var self = this;
if (self._texture !== texture) {
var locLoaded = texture.loaded;
this._textureLoaded = locLoaded;
this._texture = texture;
function textureLoadedCallback () {
if (!self._texture) {
// clearTexture called while loading texture...
// 在載入紋理的時候呼叫了clearTexture方法
return;
}
self._textureLoaded = true;
var w = texture.width, h = texture.height;
// 如果在Canvas模式下,圖片有旋轉,需要進行旋轉的特殊處理(_cutRotateImageToCanvas)
if (self._rotated && cc._renderType === cc.game.RENDER_TYPE_CANVAS) {
var tempElement = texture.getHtmlElementObj();
tempElement = _ccsg.Sprite.CanvasRenderCmd._cutRotateImageToCanvas(tempElement, self.getRect());
var tempTexture = new cc.Texture2D();
tempTexture.initWithElement(tempElement);
tempTexture.handleLoadedTexture();
self._texture = tempTexture;
self._rotated = false;
w = self._texture.width;
h = self._texture.height;
self.setRect(cc.rect(0, 0, w, h));
}
if (self._rect) {
self._checkRect(self._texture);
} else {
self.setRect(cc.rect(0, 0, w, h));
}
if (!self._originalSize) {
self.setOriginalSize(cc.size(w, h));
}
if (!self._offset) {
self.setOffset(cc.v2(0, 0));
}
// dispatch 'load' event of cc.SpriteFrame
// cc.SpriteFrame的觸發load事件
self.emit("load");
}
// 如果圖片已載入完,則直接執行回撥,否則監聽texture的load方法
if (locLoaded) {
textureLoadedCallback();
} else {
texture.once("load", textureLoadedCallback);
}
}
},
禁止延遲載入
在Creator的官方文件中介紹到“Spine 和 TiledMap 依賴的資源永遠都不會被延遲載入”,這主要是因為它們對Raw資源是一個強依賴,也就是說節點被啟用時就必須使用到它們的紋理,所以不能延遲載入。那麼它們是如何實現禁止延遲載入的呢?
在canDeferredLoad方法中,如果資源的asset.constructor.preventDeferredLoadDependents為true時,會強制返回false。在引擎中進行搜尋可以發現,除了Spine和TiledMap,還有DragonBones也是被禁止延遲載入的。
相關推薦
Cocos Creator 資源載入流程剖析【三】——Load部分
Load流程是整個資源載入管線的最後一棒,由Loader這個pipe負責(loader.js)。通過Download流程拿到內容之後,需要對內容做一些“載入”處理。使得這些內容可以在遊戲中使用。這裡並不是所有的資源都需要進行一個載入處理,目前只有圖片、Json、Plist、Uuid(Prefab、場景)等資
Cocos Creator 資源載入流程剖析【五】——從編輯器到執行時
我們在編輯器中看到的資源,在構建之後會進行一些轉化,本章將揭開Creator對資源進行的處理。 資源處理的整體規則 首先我們將Creator的開發和執行劃分為以下幾個場景: 編輯器 當我們將資源放到編輯器中時,Creator會為每個資源生成唯一的uuid以及meta檔案,並在專案的library目錄下生成對應
Cocos Creator 資源載入流程剖析【六】——場景切換流程
這裡討論場景切換的完整流程,從我們呼叫了loadScene開始切換場景,到場景切換完成背後發生的事情。整個流程可以分為場景載入和場景切換兩部分,另外還簡單討論了場景的預載入。 載入場景的流程 loadScene主要做了3件事,通過_getSceneUuid獲取要載入場景的資訊,對於原生平臺的非啟動場景
Cocos Creator 資源加載流程剖析【三】——Load部分
用戶 ksh text 最終 開發者 mixin 包裝 sso refresh Load流程是整個資源加載管線的最後一棒,由Loader這個pipe負責(loader.js)。通過Download流程拿到內容之後,需要對內容做一些“加載”處理。使得這些內容可以在遊戲中使用
Google Chrome原始碼剖析【三】:程序模型
【三】 Chrome的程序模型 1. 基本的程序結構 Chrome是一個多程序的架構,不過所有的程序都會由老大,Browser程序來管理,走的是集中化管理的路子。在Browser程序中,有xxxProcessHost,每一個host,都對應著一個Process,比如Re
Chrome原始碼剖析【三】Chrome的程序模型
1. 基本的程序結構 Chrome是一個多程序的架構,不過所有的程序都會由老大,Browser程序來管理,走的是集中化管理的路子。在Browser程序中,有xxxProcessHost,每一個host,都對應著一個Process,比如RenderProcessHost對
cocos creator 實現載入遠端資源到本地快取
在專案開發過程中有時候需要將遠端連線的圖片載入到本地存放,供以後使用,但是在cocos 官方文件裡面沒有詳細的介紹存放到本地的方法,現在在這裡講述如何將遠端資源載入到本地進行儲存 首先新建一個物件類專門用來管理載入圖片的類 ImageLoader.js var md = require("./
cocos creator主程入門教程(三)—— 資源管理
五邑隱俠,本名關健昌,10年遊戲生涯,現隱居五邑。本系列文章以TypeScript為介紹語言。 在初識篇,我介紹過怎樣載入prefab。cocos提供了一系列的載入介面,包括cc.loader.load,cc.loader.loadRes,cc.loader.loadArray,cc.loa
Cocos Creator 動態載入遠端圖片資源
這個問題折騰了我一個下午,很難受,想通過客戶端載入遠端伺服器中的使用者頭像圖片。 var url = "http://localhost:8080/pic/10001.png";//圖片路徑 var container = this.user_photo.get
【Python】【控制流程】【三】【協程】
trace 執行 this tool 引用 給他 異常 rmp 解釋 """# 16.2 用過協程的生成器的基本行為#例子16-1 可能是協程最簡單的使用演示def simple_coroutine(): print(‘-> coroiutine started
cocos creator如何載入excel等文字檔案
隨著遊戲技術的日新月異,玩家對遊戲要求的不斷提高,咱們製作的遊戲的專案也越來越複雜,一個專案的文字檔案多是很正常的事,但如何讓這些文字檔案以最簡單的方式為我們所用呢? 我們的前輩已經給出了答案,因為cocos creator是可以支撐json
cocos creator動態載入DragonBones
根據creator的龍骨元件來看的話新增一個龍骨的話需要設定五個地方,分別是DragonAsset(龍骨的配置json檔案),DragonAtlas(龍骨的紋理json資源),Armature(Armature名稱),Animation(Anima
Android Webkit 派生資源載入流程
以image為例解析image資源的載入過程: 1. HTMLImageElement被建立時在建構函式HTMLImageElement()中將HTMLImageElement物件傳遞給HTMLImageLoader創建出m_imageLoader 2.
read 系統調用剖析【轉】
column 解析 sync 表示 per page 初始化過程 使用 eric 轉自:https://www.ibm.com/developerworks/cn/linux/l-cn-read/ 大部分程序員可能會有這樣的疑問:當在程序中調用庫函數 read 時
計算機網絡【三】:數據鏈路層 【轉】
緩存 strong mac 幾分鐘 tcp協議 tran 可靠性 如何 wid 轉自:http://blog.chinaunix.net/uid-26275986-id-4104189.html 按照TCP/IP協議由下往上的順序,今天我們來學習一下數據鏈
【三】剛學Python的幾道簡單練習題
-1 找到 ext split art style white 字符串索引 是否 python交友娛樂會所:613176398 (一)name = "aleX leNb" 1) 移除 name 變量對應的值兩邊的空格,並輸出處理結果 name = "a
【三】MongoDB文檔的CURD操作
其中 iat options match imu 可選 不能 dal 多個 一、插入文檔 使用insert方法插入文檔到一個集合中,如果集合不存在創建集合,有以下幾種方法: db.collection.insertOne({}):(v3.2 new) #插入一個文檔到集
【Python】【元編程】【三】【元類】
無法使用 import iter 時也 food ini lin abc __init__ ‘‘‘# str、 type 和 LineItem 是object 的子類 str、 object 和 LineItem 是 type 的實例,因為它們都是類object 類和
【Linux】【三】linux 復制文件到指定目錄
color 指令 tro too pos -s .cn -cp com 將 application/file/test/logs/ 下的文件 logs.log , logs.tar 復制到 application/file/test/tools/ 下,並新
Linux MTD系統剖析【轉】
過程 當下 default targe lin 讀取內容 state yaffs2 lock 轉自:http://blog.csdn.net/lwj103862095/article/details/21545791 MTD,Memory Technology Dev