quick-cocos2d-x裡的MVC,quick-cocos2d-xmvc
標題有點大。內容有點水哈。最近app上架,空閑時間比較多,於是開始重構代碼。發現重構是件很好玩的事情,可以把以前看過的設計模式實驗一番。可惜水平有點淺,所以高手就迴避吧。
看過一本書,叫《cocos2d-x進階開發教程-製作自己的捕魚達人》。裡面有個觀點是,scene應該是MVC裡面的control層。後來想了想還是挺有道理的,這幾天就實踐了一把。其實cocos2d-x有自己的圖形介面工具,但是實際的做法很簡單,我也懶得去學(也可能是我閉門造車哈)。quick裡面的MVC 還是很簡單的,scene來處理商務邏輯,UI可以用資料驅動。
首先將產生UI的資料寫到lua table中,格式如下:
local firstLogin = { class = "CCNode", name = "root", childrens = { { name = "loginMenu", class = "CCMenu", items = { {name = "loginBg", class = "ImageMenuItem", options = { image = {class = "CCSprite9Scale", file = "res/ui030_1_2.png", size = CCSize(275, 75)}, imageSelected = {class = "CCSprite9Scale", file = "res/ui030_1_8.png", size = CCSize(275, 75)}, tag = 11, pos = CCPoint(172, display.height - 408) } }, {name = "registBg", class = "ImageMenuItem", options = { image = {class = "CCSprite9Scale", file = "res/ui030_1_2.png", size = CCSize(275, 75)}, imageSelected = {class = "CCSprite9Scale", file = "res/ui030_1_8.png", size = CCSize(275, 75)}, tag = 13, pos = CCPoint(467, display.height - 408) } }, }, tag = 1112 }, { name="label1", class="UILabel", options={text="登入",size=30,color=ccc3(255, 255, 255)}, pivot="center", x=172, y=display.height - 410, tag=10 } }, tag = 44}return firstLogin當然,你也可以不用這麼寫,畢竟不用cocos2d內建的UI產生工具就是為了發揮自主性,只要你覺得容易解析,資料格式怎麼定義都無所謂。
然後去解析資料,這裡用了一下原廠模式,將資料傳入工廠,工廠負責解析資料,最後交由具體的車間去生產。由於層級不是固定的,存在子結點與父結點的關係。所以工廠最後用遞迴來寫一下。產生結點代碼如下(這裡要注意一下,child:addTo(parent)根據tag是檢索不到child的,要用tag檢索就要使用parent:addChild())。
function NodeInflater:inflate_luaTable(param, parentNode) local rootNode = param -- 建立自己 local node = self:createNodeFromTag(rootNode.class, rootNode) -- 孩子 self:rInflate(rootNode, node) -- 加到父節點上去 parentNode:addChild(node) return nodeend
至於車間怎麼設計,看個人愛好了。我是這麼做的
function NodeFactory:onCreateNode(jsonNode) local uiNode local className = jsonNode.class -- 判斷控制項的類型 if "UIImage" == className then -- sprite uiNode = self:onCreateNode_UIImage(jsonNode) elseif "CCNode" == className then -- node uiNode = self:onCreateNode_CCNode(jsonNode) elseif "UIPushButton" == className then -- UIPushButton uiNode = self:onCreateNode_UIPushButton(jsonNode) elseif "UILabel" == className then -- label uiNode = self:onCreateNode_UILabel(jsonNode) elseif "UISlider" == className then --slider uiNode = self:onCreateNode_UISlider(jsonNode) elseif "CCProgressTimer" == className then --progresstimer uiNode = self:onCreateNode_CCProgressTimer(jsonNode) elseif "CCMenu" == className then -- CCMenu uiNode = self:onCreateNode_CCMenu(jsonNode) elseif "CCSprite" == className then -- CCSprite uiNode = self:onCreateNode_CCSprite(jsonNode) elseif "CCSprite9Scale" == className then uiNode = self:onCreateNode_CCSprite9Scale(jsonNode) end -- 應用 self:applyNodeAttributesByJsonNode(uiNode, jsonNode) return uiNodeend
這裡注意一下,為了在scene中檢索到具體的子結點,既可以將每個結點的索引存到父節點的table中(在quick中一切資料結構皆為table),也可以用tag進行檢索,我這裡採用的是使用tag進行檢索。
最後是在scene中產生UI並添加邏輯(以menu為例),
local function loginSelected(tag)end -- 產生first login local fileName = "app.data.FirstLoginData" require("app.Utils.NodeInflater"):easyRootInflater():inflate(fileName, layer) -- 為menu添加觸摸事件 local menuItems = layer:getChildByTag(44):getChildByTag(1112):getChildren() for i=1,menuItems:count() do menuItems:objectAtIndex(i-1):registerScriptTapHandler(loginSelected) end
這樣子就可以完成UI,與邏輯分離了。水平有限,是在抱歉。