接上一篇文章的內容繼續:

馬鑫:Unity遊戲開發筆記-UI框架之Lua層封裝?

zhuanlan.zhihu.com
圖標

在開始編碼之前,首先可能需要大家掌握幾個知識點

  1. Lua語言基礎
  2. Lua如何實現面向對象
  3. Lua如何和C#進行交互
  4. ToLua框架

基於掌握以上基礎的前提,我們整理一下邏輯~關於Base的邏輯的生命周期,我思考了好久結合當前正在做的項目中的設計,得到了類似下圖的決定:

開始代碼的編寫:

-- @FileName UIBase
-- @Create by mx
-- @Create time 2019/05/26 22:08:38
-- @FileInfo 所有UI的基類

--全局申明UIBase基類
UIBase = Class("UIBase")
--全局申明 UI資源載入方式
UILoadType =
{
Sync, --同步
ASync, --非同步
}

function UIBase:Ctor( ... )
--該UI是否已經初始化完成
self.m_isInited = false
--實例化的Prefab
self.m_uiObj = nil
--實例化的TransForm信息
self.m_uiTrans = nil
--是否處於激活狀態
self.m_isActive = false
--UIName
self.m_uiName = nil
--UIPath
self.m_uiFullPath = nil
--是否在載入中
self.m_isLoading = false
--資源載入方式 默認同步
self.m_resLoadType = UILoadType.Sync
--存儲UI的數據信息
self.m_uiPanel = nil
end

--資源載入
function UIBase:Load( callBack )
if self.m_isLoading then return end
if self.m_uiObj then LogError("Already Loaded UIName :"..self.m_uiName) return end
if self.m_uiFullPath == nil then self:SetUIFullPath() end
local l_uiObj = nil
if self.m_resLoadType == UILoadType.Sync then
l_uiObj = MObjectManager:InstantiateGameObeject(self.m_uiFullPath)
self:OnLoadFinish(l_uiObj,callBack)
else
l_uiObj = MObjectManager:InstantiateGameObejectAsync(self.m_uiFullPath,function (resPath,mResObjItem,parms)
self:OnLoadFinish(l_uiObj,callBack)
end,LoadResPriority.RES_LOAD_LEVEL_HEIGHT)
end
end

--資源載入完成 初始化信息的設置
function UIBase:OnLoadFinish(obj,callBack)
if obj == nil then
LogError("資源載入失敗~ Name:"..self.m_uiName)
self.m_uiObj = nil
return
end
obj.name = self.m_uiName
self.m_uiObj = obj
self.m_uiTrans = obj.transform
self:Init()
if callBack then callBack(self) end
end

--資源釋放
function UIBase:UnLoad( ... )
--Todo 非同步載入對正在載入的非同步邏輯做取消判定
--資源載入缺少這個介面 需要補上
if self.m_isLoading then

end

if self.m_uiObj then
MObjectManager:ReleaseObject(self.m_uiObj)
self.m_uiObj = null
self.m_uiTrans = null
end
end

--邏輯初始化 在資源載入完成後調用
function UIBase:Init()
self.m_isInited = true
end

--資源卸載後調用
function UIBase:Uninit()
self:UnLoad()
self.m_isInited = false
self.m_uiPanel = false
end

--打開UI
function UIBase:Active()
end

--關閉UI
function UIBase:Deactive()
end

--UI顯示時
function UIBase:OnActive()
end

--UI關閉前
function UIBase:OnDeactive()
end

--事件綁定
function UIBase:BindEvents()
end

--事件解綁
function UIBase:UnBindEvents()
end

--Update事件
function UIBase:Update()
end

--觸摸事件
function UIBase:UpdateInPut(touchItem)
end

--斷線重連
function UIBase:OnReconnected()
end

--遊戲註銷
function UIBase:OnLogout()
end

function UIBase:IsActive( ... )
return self.isActive
end

function UIBase:IsInited( ... )
return self.IsInited
end

--設置UI的全路徑
function UIBase:SetUIFullPath( ... )
if self.m_uiFullPath ~= nil then return end
if self.m_uiName == nil then
LogError("UIName is nil ~ Please Check it")
end
self.m_uiFullPath = MPathUtils.UI_MAINPATH.."/"..self.m_uiName..MPathUtils.UI_PREFAB_SUFFIX
end

--UIBase Test
--UIBase.m_uiName = "LoginPanel"
--UIBase.Load(UIBase)
return UIBase

以上為Base的基礎設計,後續的開發過程中在持續優化~

接下來就是幾個繼承UIBase的基礎類

UIBaseWind基本窗體類

UIBaseToggleWind依附於基本窗體的類

UIBaseSlot復用Object類

這裡我們在來理一下思路:

UIBaseWind

屬性

當前UI的顯示層級 m_uiLayer

當前UI的顯示類型 m_uiType

當前UI是否是Toggle的父類 如果是那麼保存繼承UIBaseToggle的UIToggleWind的引用 m_uiToggleWindTb = {}

保存當前UI下創建的所有繼承自UIBaseSlot的復用性組件 m_uIbaseSlotTb = {}

介面

支持創建UIbaseSlot

支持創建UIBaseToggle

UIBaseToggleWind

當前ToggleWind的父節點

當前ToggleWind的名字

UIBaseSlot

當前Slot的父節點

當前Slot的Id

考慮到Slot有可能用於ScrollView需要頻繁創建 需要一個當前Slot的SlotPool池管理

統一以上生命周期 做好釋放邏輯 以免內存泄露

以上就是幾個基礎類的設計了~ 代碼不貼了。接下來就是UIManager類似C#的設計Manager需要核心做以下的事情

1 管理UI的顯示 隱藏 銷毀

2 管理UI堆棧

3 統一一些生命周期的入口,比如說Update,OnReconnect,OnLogout等

然後就是提供一些常用的介面,比如獲取某一個UI的狀態啊,獲取某一個UI啊,堆棧清空啊,彈出一個棧頂的UI等等~


還有一點之前沒有講到,就是Lua邏輯基礎代碼的自動生成,其實定義好基類之後,業務層的開發會有一個統一的結構,從文本角度看基礎類無非就是UI的名字不一樣,那麼這個時候就需要做一個UI代碼的生成工具了。

其實這裡還有一點小東西當前項目做得很好,就是寫了一個腳本管理UI的所有類型,然後給每一個我們需要操作的節點掛上這個腳本,生成代碼的時候我們就可以直接生成這個掛腳本的節點的位置信息,不需要代碼裡面去做Transform.Find操作。

代碼生成是非常重要的一環,可以大大縮短開發時間,真的非常有必要。

UI框架這塊基本介紹完了。我們當前的遊戲框架中引入了Lua的熱重載,就是不需要重啟遊戲,直接就可以更新Lua虛擬機中的代碼,大大加快了開發的速度。後面我會把這個東西也集成到我們的遊戲框架中,給大家做一個簡單的講解。

共勉。


推薦閱讀:
相关文章