文/邪讓多杰
需求環(huán)境
在上一級的【解決方案】文章中,我們設(shè)計出了動態(tài)加載資源的業(yè)務(wù)流程,而這一節(jié),我們就通過一些簡單的代碼,來實(shí)現(xiàn)出業(yè)務(wù)流程中的效果。
吸取之前文章的經(jīng)驗,如果按照正式項目的規(guī)格開發(fā),本篇文章就會非常冗余,所以我們優(yōu)化一下,僅僅針對技術(shù)點(diǎn)進(jìn)行講解與釋放,具體與工程相關(guān)的,我們就不再文章中講解,但你可以在Github的工程中找到它們。、
現(xiàn)在,我們先回顧一下之前所設(shè)計出的業(yè)務(wù)流程。
那么,在這個業(yè)務(wù)流程中,我可以定義出在游戲運(yùn)行時,資源有三種狀態(tài):
1、未加載
2、已經(jīng)加載
3、已可以釋放
三種狀態(tài)了某個資源此時的最佳使用環(huán)境,也就是說,接下來需要使用的資源,我就放到池中,而接下來很長一段時間內(nèi)不需要使用的資源,我就徹底釋放掉。以確保程序的內(nèi)存總是在可控范圍之內(nèi)。
設(shè)計
為了達(dá)到這樣的目的,我們就需要劃分三個模塊去做。
1、最基礎(chǔ)的資源加載,與池。
2、資源加載的自動記錄過程。
3、資源加載的動態(tài)釋放與加載過程。
池
首先,池,因為我們是模擬,所以這個就比較容易實(shí)現(xiàn),在現(xiàn)實(shí)工程中,則可能需要考慮不同資源類型的具體邏輯。
///
/// 池
///
Dictionary Stack> PoolDict = new Dictionary();
///
/// 正在工作的資源對象
///
Dictionary int> WorkingPool = new Dictionary();
首先是2個定義,一個是回收池,一個是工作區(qū),工作區(qū)用來反向查資源的ID,同時,也檢測是否有資源是通過其他方法加載的,理論上,游戲內(nèi)不應(yīng)該存在其他的途徑來加載資源。
接下來,就是2份邏輯代碼,一個是創(chuàng)建資源,它用到了之前我們實(shí)現(xiàn)的資源管理器,另一個是回收資源。
?
- ///
- ?
- ?
- /// 池
- ///
- Dictionary Stack> PoolDict = new Dictionary();
- ?
- ///
- /// 正在工作的資源對象
- ///
- Dictionary int> WorkingPool = new Dictionary();
- 首先是2個定義,一個是回收池,一個是工作區(qū),工作區(qū)用來反向查資源的ID,同時,也檢測是否有資源是通過其他方法加載的,理論上,游戲內(nèi)不應(yīng)該存在其他的途徑來加載資源。
- 接下來,就是2份邏輯代碼,一個是創(chuàng)建資源,它用到了之前我們實(shí)現(xiàn)的資源管理器,另一個是回收資源。
- ///
- ?
- ?
- /// 得到資源,如果池子里有,直接拿,否則創(chuàng)建
- ///
- ///資源類型,方便上級使用
- ///資源id
- ///
- public T getObj(int _id)
- where T : Object
- {
- Object temp = null;
- //池子里有就取一個
- if (PoolDict.ContainsKey(_id)
- PoolDict[_id].Count > 0)
- ?
- temp = PoolDict[_id].Pop();
- ?
- //如果池子里沒有,就創(chuàng)建一個新的
- temp = DJAssetsManager.GetInstance().Load(_id);
- ?
- if (temp as T == null)
- {
- Debug.LogError(代碼寫錯了或資源配錯了,傳入的資源id與希望得到的類型不匹配);
- Debug.Break();
- return null;
- }
- ?
- //加入工作池
- WorkingPool.Add(temp,_id);
- ?
- return (T)temp;
- }
- ?
- ///
- /// 回收資源
- ///
- public void recObj(Object _obj)
- {
- if (WorkingPool.ContainsKey(_obj))
- {
- //正?;厥?br />
- int id = WorkingPool[_obj];
- WorkingPool.Remove(_obj);
- ?
- if (PoolDict.ContainsKey(id) == false)
- PoolDict.Add(id, new Stack());
- ?
- PoolDict[id].Push(_obj);
- }
- else
- {
- //不屬于池管理的資源直接刪除掉。不過得打出警告,按理說不應(yīng)該存在
- Debug.LogWarning(檢測到非法創(chuàng)建的資源: + _obj.name);
- Destroy(_obj);
- }
- }
PS: 在文章代碼中并沒有對預(yù)制體進(jìn)行管理,這其實(shí)是不好的,最好手動的控制他們的加載與釋放。
資源生命周期的自動記錄
要記錄資源的生命周期,首先我們得確定自己的游戲形勢,如果是大世界類型的游戲,我們需要根據(jù)區(qū)域范圍來確定資源表,那么如果是副本類型的,我們就需要以副本為單位記錄一份資源表。
并且,有的資源我們希望是動態(tài)加載的,而有的資源,比如主角的特效,模型,音頻等等,我們更希望它們是常駐的。所以,我們還需要區(qū)分一份資源是否需要動態(tài)加載。
表
知道了需求后,我們就可以對自動記錄表進(jìn)行設(shè)計。為了講解清晰,我盡量的保持任何一個元素都只是為了測試,不與業(yè)務(wù)邏輯掛鉤。
在工程中,你可以到之前我們創(chuàng)建過的DJAssetsDefine 命名空間,里面我們新添加了這一次需要使用到的記錄表。
?
?
- [System.Serializable]
- public class AssetPreConfig
- {
- ///
- ?
- ?
- /// 資源ID
- ///
- public int AssetId;
- ?
- ///
- /// 加載時間
- ///
- public float LordTime;
- ?
- ?
- ///
- /// 下一個次同類資源的加載時間,-1 就是再也沒有加載過了
- ///
- public float NextTime = -1;
- }
- public float NextTime = -1;
- ///
- /// 下一個次同類資源的加載時間,-1 就是再也沒有加載過了
- ?
- public float LordTime;
- ///
- /// 加載時間
- ?
- public int AssetId;
- ///
- ?
- ///
- {
- public class AssetPreConfig
代碼如下:
?
?
- ///
- ?
- ?
- /// 得到一個克隆體
- ///
- ///資源id
- /// 是否預(yù)加載
- ///
- private Object getClone(int _id, bool _isPre = false)
- {
- //預(yù)加載直接返回新的
- if (_isPre) return Object.Instantiate(PoolDict[_id].pre); ;
- ?
- //池里有從池里拿
- if (PoolDict[_id].Pools.Count > 0)
- {
- currentIndex+= 1;
- return PoolDict[_id].Pools.Pop();
- }
- ?
- //記錄下這次加載
- AutoLog(_id);
- ?
- //返回一個新的
- return Object.Instantiate(PoolDict[_id].pre);
- }
- return Object.Instantiate(PoolDict[_id].pre);
- ?
- AutoLog(_id);
- ?
- }
- return PoolDict[_id].Pools.Pop();
- currentIndex+= 1;
- {
- if (PoolDict[_id].Pools.Count > 0)
- ?
- if (_isPre) return Object.Instantiate(PoolDict[_id].pre); ;
- //預(yù)加載直接返回新的
- {
- private Object getClone(int _id, bool _isPre = false)
- ///
- /// 是否預(yù)加載
- ///資源id
- ///
- ?
第一次
此時記錄表內(nèi)的內(nèi)容
第二次
可以看到,前兩次的資源都有預(yù)加載,所以時間上間斷了。而第三次資源,卻比第一次還要多,因為中間發(fā)生了資源刪除事件。
第三次
這一次,沒有任何資源是在使用時才被加載的,前2份資源也不會“輕易”的放棄了自己生命,而是等待這第3份的調(diào)用。徹底完成了優(yōu)化的過程。
結(jié)束語
如果和業(yè)務(wù)邏輯相結(jié)合,我們所演示的功能是不夠的,但卻構(gòu)建了整個自動化的資源加載與釋放的核心框架,使得我們在項目后續(xù)的開發(fā)過程中,盡可能的不會在IO方面遇到困難。
同時,如果我們能繼續(xù)對這部分的工作進(jìn)行優(yōu)化,還能制作出更平緩的游戲資源IO流程,提供更好的游戲性能。
銳亞教育,游戲開發(fā)論壇|游戲制作人|游戲策劃|游戲開發(fā)|獨(dú)立游戲|游戲產(chǎn)業(yè)|游戲研發(fā)|游戲運(yùn)營| unity|unity3d|unity3d官網(wǎng)|unity3d 教程|金融帝國3|8k8k8k|mcafee8.5i|游戲蠻牛|蠻牛 unity|蠻牛
- 還沒有人評論,歡迎說說您的想法!