先簡單說說MVC,即Model View Controller。Model(模型),一般負(fù)責(zé)數(shù)據(jù)的處理;View(視圖),一般負(fù)責(zé)界面的顯示;Controller(控制器),一般負(fù)責(zé)前端的邏輯處理。拿一款手機游戲來說,界面UI的顯示、布局等就是View負(fù)責(zé);點擊了按鈕,手勢的滑動等操作由Controller來處理;游戲中需要的數(shù)據(jù)資源就交給Model。
接下來,看看在游戲開發(fā)中怎么用,這里用Lua(環(huán)境使用cocos code ide)給大家說說。
先來看看項目的目錄結(jié)構(gòu):
其中cocos、Controller、Model、View這個不用多說,Event里面保存的全局消息類型,Managers是用于管理游戲中的東東的,比如管理資源,管理各種場景切換,層的切換等等。Utilities提供一些工具類,比如字符串的處理等。大家也可以根據(jù)自己的需求來定制目錄,比如定義一個NetCenter文件夾,專門用于處理網(wǎng)絡(luò)的。本例子中沒有用到數(shù)據(jù)操作和工具類,所以這兩個文件夾為空。
我們以游戲的運行流程為線索來展開說明。
運行項目,進(jìn)入到main.lua文件,來看看main函數(shù):
local function main() collectgarbage("collect") -- avoid memory leak collectgarbage("setpause", 100) collectgarbage("setstepmul", 5000) -- initialize director local director = cc.Director:getInstance() --turn on display FPS director:setDisplayStats(true) --set FPS. the default value is 1.0/60 if you don't call this director:setAnimationInterval(1.0 / 60) cc.Director:getInstance():getOpenGLView():setDesignResolutionSize(320, 480, 1) --create scene local scene = require("GameScene") local gameScene = scene:startGame() end
我們最后調(diào)用了GameScene類中的startGame函數(shù),來看看GameScene這個類:
require("Managers.SceneManager") require("Managers.LayerManager") local GameScene = class("GameScene") local scene = nil function GameScene:startGame() --初始化 scene = cc.Scene:create() if cc.Director:getInstance():getRunningScene() then cc.Director:getInstance():replaceScene(scene) else cc.Director:getInstance():runWithScene(scene) end SceneManager:initLayer(scene) self:enterGame() end function GameScene:enterGame() LayerManager:getInstance():gotoLayerByType(LAYER_TYPE_MAIN) end return GameScene
在startGame函數(shù)中,我們創(chuàng)建了一個空場景,然后調(diào)用SceneManager場景管理器來初始化場景。最后調(diào)用enterGame函數(shù)正式進(jìn)入游戲主界面,其中enterGame函數(shù)中又有一個LayerManager層管理器。我們來看看這兩個管理器是如何工作的。先看看SceneManager:
--場景管理器 SceneManager = {} --背景層 bgLayer = nil --游戲?qū)? gameLayer = nil --彈窗層 panelLayer = nil function SceneManager:initLayer(scene) bgLayer = cc.Layer:create() scene:addChild(bgLayer) gameLayer = cc.Layer:create() scene:addChild(gameLayer) panelLayer = cc.Layer:create() scene:addChild(panelLayer) end
很簡單,按順序初始化了三個空Layer。再來看看LayerManager管理器:
--Layer管理器 LayerManager = {} LAYER_TYPE_MAIN = "LAYER_TYPE_MAIN" local curLayer = nil function LayerManager:new(o) o = o or {} setmetatable(o,self) self.__index = self return o end function LayerManager:getInstance() if self.instance == nil then self.instance = self:new() end return self.instance end function LayerManager:gotoLayerByType(type) if curLayer ~= nil then curLayer:destroy() end if type == "LAYER_TYPE_MAIN" then local layer = require("Controller.MainLayerController"):create() curLayer = layer end end
看看gotoLayerByType這個函數(shù),首先切換層的時候,看看當(dāng)前層是否為空,不為空就刪掉。然后根據(jù)傳遞過來的參數(shù)來判斷要切換到哪個層。這里出現(xiàn)MVC中的Controller部分,看看是什么情況。這里調(diào)用了類MainLayerController中的create函數(shù):
function MainLayerC:create() local layer = MainLayerC:new() return layer end function MainLayerC:ctor() self:createUI()--創(chuàng)建界面 self:addBtnEventListener()--添加按鈕監(jiān)聽 end function MainLayerC:createUI() local layer = require("View.MainLayerView") self.mainLayer = layer:createUI() gameLayer:addChild(self.mainLayer) end
這里我們又發(fā)現(xiàn)了MVC中的View,在createUI函數(shù)中,我們調(diào)用了類MainLayerView的createUI函數(shù),并將其添加到場景的游戲?qū)又小N覀儊砜纯碝ainLayerView這個類。
local eventDispatcher = cc.Director:getInstance():getEventDispatcher() local MainLayerV = class("MainLayerView",function() return cc.Layer:create() end) function MainLayerV:createUI() local mainLayer = MainLayerV:new() return mainLayer end function MainLayerV:ctor() self:initUI() end function MainLayerV:initUI() local winSize = cc.Director:getInstance():getWinSize() self.bg = cc.Sprite:create(ResManager.main_bg) self.bg:setPosition(winSize.width / 2,winSize.height / 2) self:addChild(self.bg) local function menuCallback(tag,menuItem) local event = cc.EventCustom:new(EVENT_CLICK_MENU_MAIN) event._usedata = tag eventDispatcher:dispatchEvent(event) end self.btnItem1 = cc.MenuItemImage:create(ResManager.main_btn1,ResManager.main_btn1,ResManager.main_btn1) self.btnItem1:setPosition(winSize.width / 2,winSize.height / 3) self.btnItem1:setTag(1) self.btnItem1:registerScriptTapHandler(menuCallback) self.btnItem2 = cc.MenuItemImage:create(ResManager.main_btn2,ResManager.main_btn2) self.btnItem2:setPosition(winSize.width / 2,winSize.height / 2) self.btnItem2:setTag(2) self.btnItem2:registerScriptTapHandler(menuCallback) self.btnItem3 = cc.MenuItemImage:create(ResManager.main_btn3,ResManager.main_btn3) self.btnItem3:setPosition(winSize.width / 2,winSize.height / 3 * 2) self.btnItem3:setTag(3) self.btnItem3:registerScriptTapHandler(menuCallback) --創(chuàng)建菜單 self.menu = cc.Menu:create(self.btnItem1,self.btnItem2,self.btnItem3) self.menu:setPosition(0,0) self:addChild(self.menu) end return MainLayerV
可以看到,我們在主界面中添加了一張背景圖和三個按鈕。我們是通過資源管理器ResManager來管理游戲中的素材的,ResManager文件很簡單:
--資源管理器 ResManager = {} --主界面 ResManager.main_bg = "bg_big.png" ResManager.main_btn1 = "cell.png" ResManager.main_btn2 = "cell2.png" ResManager.main_btn3 = "cell3.png"
這樣做的好處是,如果圖片改了名字或者換了路徑等,只需要在這里改一次就可以了。
可以看到我們給三個按鈕注冊了響應(yīng)函數(shù)menuCallback,在這個函數(shù)中,就是MVC中的V和C之間的“溝通”了。我們定義了一個自定義事件EVENT_CLICK_MENU_MAIN,并給這個事件添加了一個附帶參數(shù)_usedata,這個參數(shù)保存的是三個按鈕的tag。然后將這個事件發(fā)送給他的監(jiān)聽者。這里大家應(yīng)該明白了,我們在對應(yīng)的Controller中注冊了EVENT_CLICK_MENU_MAIN的監(jiān)聽,但有這個事件發(fā)過來時,我們就響應(yīng)。根據(jù)事件攜帶的參數(shù)_usedata,我們就知道了在View中,玩家點擊了哪個按鈕,這樣做的好處是,保證了每個界面只有一個消息,我們只需要根據(jù)這個消息攜帶的附加參數(shù)來判斷具體的事件,從而減少了消息個數(shù),這樣有助于游戲的效率。另外,我們在響應(yīng)這個消息的時候,也會做一定的優(yōu)化,來看看類MainLayerController的響應(yīng)函數(shù):
function MainLayerC:addBtnEventListener() --按鈕事件處理 local function eventBtnListener(event) local eventNum = event._usedata local switch = { [1] = function() print("Btn one") end, [2] = function() print("Btn two") end, [3] = function() print("Btn three") end } switch[eventNum]() end --注冊事件處理 self._eventBtnListener = cc.EventListenerCustom:create(EVENT_CLICK_MENU_MAIN,eventBtnListener) eventDispatcher:addEventListenerWithSceneGraphPriority(self._eventBtnListener,self.mainLayer) end
可以看到實際情況,我們并不需要對傳遞過來的參數(shù)進(jìn)行判斷,而是定義了一個函數(shù)數(shù)組,直接根據(jù)下標(biāo)來調(diào)用對應(yīng)的消息響應(yīng)。之后繼續(xù)通過各種管理器來對游戲內(nèi)容進(jìn)行變化,方式和MainLayerController和MainLayerView差不多。
到這里,MVC應(yīng)用的簡單介紹就結(jié)束啦,希望大家能夠喜歡本文,能夠?qū)Υ蠹覍W(xué)習(xí)lua有所幫助。
標(biāo)簽:臺灣 德宏 天門 天門 濰坊 金昌 儋州 宣城
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《lua開發(fā)中實現(xiàn)MVC框架的簡單應(yīng)用》,本文關(guān)鍵詞 lua,開發(fā),中,實現(xiàn),MVC,框架,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。