[cocos2dx]cocos2dx-lua中的框架MVC

[cocos2dx]cocos2dx-lua中的框架MVC,第1张

概述MVC简介 MVC,即Model View Controller。Model(模型),一般负责数据的处理;View(视图),一般负责界面的显示;Controller(控制器),一般负责前端的逻辑处理。拿一款手机游戏来说,界面UI的显示、布局等就是View负责;点击了按钮,手势的滑动等 *** 作由Controller来处理;游戏中需要的数据资源就交给Model。  其中cocos、Controller、M MVC简介 MVC,即Model VIEw Controller。Model(模型),一般负责数据的处理;VIEw(视图),一般负责界面的显示;Controller(控制器),一般负责前端的逻辑处理。拿一款手机游戏来说,界面UI的显示、布局等就是VIEw负责;点击了按钮,手势的滑动等 *** 作由Controller来处理;游戏中需要的数据资源就交给Model。
其中cocos、Controller、Model、VIEw这个不用多说,Event里面保存的全局消息类型,Managers是用于管理游戏中的东东的,比如管理资源,管理各种场景切换,层的切换等等。UtilitIEs提供一些工具类,比如字符串的处理等。大家也可以根据自己的需求来定制目录,比如定义一个NetCenter文件夹,专门用于处理网络的。本例子中没有用到数据 *** 作和工具类,所以这两个文件夹为空。
流程实例 我们以游戏的运行流程为线索来展开说明。运行项目,进入到main.lua文件,来看看main函数:
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
我们最后调用了GameScene类中的startGame函数,来看看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函数中,我们创建了一个空场景,然后调用SceneManager场景管理器来初始化场景。最后调用enterGame函数正式进入游戏主界面,其中enterGame函数中又有一个LayerManager层管理器。我们来看看这两个管理器是如何工作的。先看看SceneManager:
--场景管理器SceneManager = {} --背景层bgLayer = nil--游戏层gameLayer = nil--d窗层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 oend function LayerManager:getInstance()    if self.instance == nil then        self.instance = self:new()    end         return self.instanceend 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    endend
看看gotolayerByType这个函数,首先切换层的时候,看看当前层是否为空,不为空就删掉。然后根据传递过来的参数来判断要切换到哪个层。 这里出现MVC中的Controller部分,看看是什么情况。这里调用了类MainLayerController中的create函数:
function MainLayerC:create()    local layer = MainLayerC:new()    return layerend function MainLayerC:ctor()    self:createUI()--创建界面    self:addBtnEventListener()--添加按钮监听end function MainLayerC:createUI()    local layer = require(VIEw.MainLayerVIEw)    self.mainLayer = layer:createUI()    gameLayer:addChild(self.mainLayer)end
这里我们又发现了MVC中的VIEw,在createUI函数中,我们调用了类MainLayerVIEw的createUI函数,并将其添加到场景的游戏层中。我们来看看MainLayerVIEw这个类。
local eventdispatcher = cc.Director:getInstance():getEventdispatcher() local MainLayerV = class(MainLayerVIEw,function()    return cc.Layer:create()end) function MainLayerV:createUI()    local mainLayer = MainLayerV:new()    return mainLayerend 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)         --创建菜单    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.pngResManager.main_btn1 = cell.pngResManager.main_btn2 = cell2.pngResManager.main_btn3 = cell3.png
这样做的好处是,如果图片改了名字或者换了路径等,只需要在这里改一次就可以了。
可以看到我们给三个按钮注册了响应函数menuCallback,在这个函数中,就是MVC中的V和C之间的“沟通”了。我们定义了一个自定义事件EVENT_CliCK_MENU_MAIN,并给这个事件添加了一个附带参数_usedata,这个参数保存的是三个按钮的tag。然后将这个事件发送给他的监听者。这里大家应该明白了,我们在对应的Controller中注册了EVENT_CliCK_MENU_MAIN的监听,但有这个事件发过来时,我们就响应。根据事件携带的参数_usedata,我们就知道了在VIEw中,玩家点击了哪个按钮,这样做的好处是,保证了每个界面只有一个消息,我们只需要根据这个消息携带的附加参数来判断具体的事件,从而减少了消息个数,这样有助于游戏的效率。另外,我们在响应这个消息的时候,也会做一定的优化,来看看类MainLayerController的响应函数:

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
可以看到实际情况,我们并不需要对传递过来的参数进行判断,而是定义了一个函数数组,直接根据下标来调用对应的消息响应。之后继续通过各种管理器来对游戏内容进行变化,方式和MainLayerController和MainLayerVIEw差不多。 cocos2dx-lua框架流程

很多学习者甚至不知道enterScene(“MainScene”) 为什么里面可以是个字符串?

新建cocos2dx-Lua工程之后,你首先看到的main.lua启动到MyApp.lua。

require("app.MyApp").new():run()  

看MyApp.lua文件:

1. require(“app.MyApp”)
这里执行的MyApp.lua的代码是:

local MyApp = class("MyApp",cc.mvc.AppBase)  -- 继承cc.mvc.AppBasereturn MyApp
这时候,你得到了MyApp这个类(lua关于类的实现网上很多)
2. require(“app.MyApp”).new()
MyApp.new()执行后,执行的代码是:

function MyApp:ctor()    MyApp.super.ctor(self)end
为什么new()了之后会执行MyApp:ctor()?请看function.lua下的function class(classname,super)方法:
function cls.new(...)            local instance = cls.__create(...)            -- copy fIElds from class to native object            for k,v in pairs(cls) do instance[k] = v end            instance.class = cls            instance:ctor(...)            return instanceend
可以看到,在class的实现方法里面,给每个创建的类声明了一个new()方法,方法里面调用了ctor()构造方法(ctor只是个名字,所以不是有些人认为的new了之后,当然会调用构造方法,lua没有类,只是我们模仿了类)
3. require(“app.MyApp”).new():run()
这时候调用了

function MyApp:run()    CCfileUtils:sharedfileUtils():addSearchPath("res/")    self:enterScene("MainScene")end
所以进到了MainScene.lua。
对于MyApp.lua文件,如果我修改成下面的样子,是不是你就理解了上面所做的事情:

-- 声明类MyApp = class("MyApp",cc.mvc.AppBase)  --- 类构造方法--function MyApp:ctor()    MyApp.super.ctor(self)end --- 对应cpp版的static create()方法--function MyApp:create()    local myApp = MyApp.new()    myApp:init()end --- 你自己的方法-- @param self --local function launchMainScene(self)    CCfileUtils:sharedfileUtils():addSearchPath("res/")    self:enterScene("MainScene")end --- init 方法--function MyApp:init()    -- add code here    launchMainScene(self)end
对应的main.lua将原来的require(“app.MyApp”).new():run()
修改为:

require("app.MyApp")MyApp:create()
这样你是不是更容易理解了,哈哈。
4. MainScene.lua
enterScene(“MainScene”) 为什么可以切换场景?
我们看下MyApp的父类AppBase里面:

function AppBase:enterScene(scenename,args,TransitionType,time,more)    local scenePackagename = self. packageRoot .. ".scenes." .. scenename    local sceneClass = require(scenePackagename)    local scene = sceneClass.new(unpack(totable(args)))    display.replaceScene(scene,more)end
这样你能理解了为什么连require文件都没有就能调用MainScene,当然你要留意下,它require时候的文件路径,scene默认写的app/scenes文件夹。好了,其他的应该按照上面的思路基本都能知道为什么了
Lua的MVC框架Sailor

Sailor 是一个 Lua 语言的 MVC 编程框架。支持跨平台,兼容 mod_lua 或者 mod_pLua,Nginx 的 ngx_lua,或者任何支持 CGI 的 Web 服务器,如 Civetweb 或者 Mongoose,前提是必须有 CGILua。使用 Sailor 开发应用的目录结构如下:

/conf - 存放配置文件 /controllers - 控制器 /layouts - 布局文件 /models - 模型 /pub - 静态文件 /runtime - 运行时生成的临时文件 /vIEws - .lp 视图文件 总结

以上是内存溢出为你收集整理的[cocos2dx]cocos2dx-lua中的框架MVC全部内容,希望文章能够帮你解决[cocos2dx]cocos2dx-lua中的框架MVC所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1058176.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存