当前位置: 移动技术网 > IT编程>脚本编程>Lua > lua开发中实现MVC框架的简单应用

lua开发中实现MVC框架的简单应用

2017年12月08日  | 移动技术网IT编程  | 我要评论

       先简单说说mvc,即model view controller。model(模型),一般负责数据的处理;view(视图),一般负责界面的显示;controller(控制器),一般负责前端的逻辑处理。拿一款手机游戏来说,界面ui的显示、布局等就是view负责;点击了按钮,手势的滑动等操作由controller来处理;游戏中需要的数据资源就交给model。

       接下来,看看在游戏开发中怎么用,这里用lua(环境使用cocos code ide)给大家说说。

       先来看看项目的目录结构:

        其中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 
--弹窗层 
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这个函数,首先切换层的时候,看看当前层是否为空,不为空就删掉。然后根据传递过来的参数来判断要切换到哪个层。这里出现mvc中的controller部分,看看是什么情况。这里调用了类mainlayercontroller中的create函数:

function mainlayerc:create() 
  local layer = mainlayerc:new() 
  return layer 
end 
 
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 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) 
   
  --创建菜单 
  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" 

       这样做的好处是,如果图片改了名字或者换了路径等,只需要在这里改一次就可以了。

       可以看到我们给三个按钮注册了响应函数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差不多。

        到这里,mvc应用的简单介绍就结束啦,希望大家能够喜欢本文,能够对大家学习lua有所帮助。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网