MVC简介
MVC,即Model View Controller。 Model(模型),一般负责数据的处理 ; View(视图),一般负责界面的显示 ;Controller(控制器), 一般负责前端的逻辑处理 。拿一款手机游戏来说,界面UI的显示、布局等就是View负责;点击了按钮,手势的滑动等操作由Controller来处理;游戏中需要的数据资源就交给Model。其中cocos、Controller、Model、View这个不用多说, Event里面保存的全局消息类型 , Managers是用于管理游戏中的东东的,比如管理资源,管理各种场景切换,层的切换 等等。 Utilities提供一些工具类,比如字符串的处理等 。大家也可以根据自己的需求来定制目录,比如定义一个NetCenter文件夹,专门用于处理网络的。本例子中没有用到数据操作和工具类,所以这两个文件夹为空。
流程实例
我们以游戏的运行流程为线索来展开说明。运行项目,进入到main.lua文件,来看看main函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
--场景管理器
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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
--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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
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
|
1
2
3
4
5
6
7
8
|
--资源管理器
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的响应函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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
|
cocos2dx-lua框架流程
很多学习者甚至不知道enterScene(“MainScene”) 为什么里面可以是个字符串?
新建cocos2dx-Lua工程之后,你首先看到的main.lua启动到MyApp.lua。
1
|
require(
"app.MyApp"
).
new
():run()
|
看MyApp.lua文件:
1. require(“app.MyApp”)
这里执行的MyApp.lua的代码是:
1
2
|
local MyApp =
class
(
"MyApp"
, cc.mvc.AppBase) -- 继承cc.mvc.AppBase
return
MyApp
|
2. require(“app.MyApp”).new()
MyApp.new()执行后,执行的代码是:
1
2
3
|
function MyApp:ctor()
MyApp.
super
.ctor(self)
end
|
1
2
3
4
5
6
7
8
|
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
instance
end
|
3. require(“app.MyApp”).new():run()
这时候调用了
1
2
3
4
|
function MyApp:run()
CCFileUtils:sharedFileUtils():addSearchPath(
"res/"
)
self:enterScene(
"MainScene"
)
end
|
对于MyApp.lua文件,如果我修改成下面的样子,是不是你就理解了上面所做的事情:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
-- 声明类
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
|
修改为:
1
2
|
require(
"app.MyApp"
)
MyApp:create()
|
4. MainScene.lua
enterScene(“MainScene”) 为什么可以切换场景?
我们看下MyApp的父类AppBase里面:
1
2
3
4
5
6
|
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, transitionType, time, more)
end
|
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 视图文件
原文地址:http://www.2cto.com/kf/201505/399069.html