引子:前面两篇文章介绍了一些关于在cocos2d-x里面如何实现mvc的理论知识,接下来的这三篇教程,我将用一个简单的教程示例,给大家演示一下具体代码实现细节。
这篇文章的写作目的就是让大家更好地理解如何在cocos2d-x里面实践mvc模式(当然,这里演示的不一定是标准的mvc,因为cocos2d-x特殊的编程方式。但是,这并不妨碍我们编写更好的代码,你们说对吧?),本文是基于前两篇文章的,所以,在继续阅读之前,我强烈建议你先读一下第一篇的理论介绍。
情景
我们将制作一个简单的面板解谜游戏(board puzzle game),当然,我们不是简单地开发一个游戏,而是要利用mvc开发出一个简单的“游戏框架”,而且这个框架将会在我的新游戏里面使用到,它具有如下一些特性:
1 一个n行n列的游戏面板(game board),n可以随着游戏难度进行变化。
2 这个游戏面板里面会包含一些“小方块(game pieces)”,而且每一个game board上都只能放一个game piece。
3 这个游戏面板可以初始化一些固定的小方块,玩家在游戏过程中,是不能移动这些小方块的。
4 这里还定义了一个“工具箱(toolbox)”,它上面可以放置许多小工具(toolbox item),它们可以看作是“可放置可移动小方块的槽子”。
5 小工具(或者叫槽子)上面可以放置许多同一类型的小工具。
6 这些小工具可以从工具箱上面移动,并且可以放置到game board 上面。
基本概念
来自 wikipedia:
model负责管理应用领域的数据和行为逻辑,同时负责响应对自己的状态数据请求(这些请求通常是从view过来的),然后响应一些指令来更改自身的状态(这些请求通常是来自controller的)。在一个事件驱动的系统中,model会通知订阅者(observers)(通常是views)它的状态改变,这样view就可以做相应的显示更新。
view则根据model的状态来合理地显示,通常是一些UI元素。一个model可以对应多个view,比如,同一数据的柱状图、饼状条、曲线图等。
controller负责接收多用户输入和调用model的一些方法。一个controller通过从用户那里获得输入,然后操作model对象,最后,model通知view来更新显示。
从维基百科的定义中,我们可以识别出以下几个主要的类(我们会在后面把model给加上去):
7 GameBoardView 代表应用程序的主视图
8 GameBoardController 是GameBoardView的一个控制器。
请注意,这里的实线代表一种直接的关联关系(controller里面包含一个view的引用),而虚线则代表了一种间接的关联(通过观察者模式)。这里的直接关联后面会用来实现touch事件处理。
实现
项目组织结构
在VS2008里面基于cocos2d-x的默认模板创建一个新的项目之后,我们又创建了下面这些组:
9 View – views & controller 组 (我们也可以把view和controller放在那个不同的group里面,但是,由于我们两个有直接的关联关系,为了方便,我就把它们放在一起了)
10 Model – 之后,我们会把model类放在这个group下面。
GameBoardView 的实现
接下来,我们开始实现GameBoardView。首先,我们把GameBoardView继承至CCNode。
class GameBoardView : public CCLayer {
// ...
// implement the "static node()" method manually
LAYER_NODE_FUNC(GameBoardView);
}
然后,实现它的init方法,然后简单地显示一串字符来验证程序的正确性。(译者:这就和我们有时候会在方法的第一句加一个CCLOG一样,只是为了验证函数是否被调用了,确保每一步都是按照你的想法去走的,这样比那种埋头编写2个小时代码不编译,而后花一晚上修改编译错误和bug要好很多。有时候只是输出还不够,还必须要做单元测试,这样才能提高效率)
virtual bool init(){
bool bRet = false;
do
{
// 先调用超类的init方法
CC_BREAK_IF(! CCLayer::init());
CCLabelTTF *label = CCLabelTTF::labelWithString("Hello World from view", "Marker Felt", 48);
// 获取窗体的尺寸
CCSize size = CCDirector::sharedDirector()->getWinSize();
label->setPosition(ccp(size.width/2, size.height/2));
this->addChild(label, 0);
bRet = true;
} while (0);
return bRet;
}
GameBoardController 实现
GameBoardController负责初始化view,所以它里面包含了一个GameBoardView的引用,将来就可以非常方便地直接使用了。
class GameBoardController : public CCLayer {
public:
GameBoardView *view;
// ...
// implement the "static node()" method manually
LAYER_NODE_FUNC(GameBoardController);
}
因为我们的GameBoardController继承到CCNode,所以,我们可以把GameBoardView当作GameBoardController的孩子给添加进去。
virtual bool init(){
bool bRet = false;
do{
// 先调用超类的init方法
CC_BREAK_IF(! CCLayer::init());
view = GameBoardView::node();
this->addChild(view, 0);
bRet = true;
}while(0)
beturn bRet;
}
static CCScene* scene(){
CCScene *scene = NULL;
do{
scene = CCScene::node();
CC_BREAK_IF(!scene);
GameBoardController *layer = GameBoardController::node();
CC_BREAK_IF(!layer);
scene->addChild(layer);
}while(0);
return scene;
}
最后的修改
我们然后修改AppDelegate类,然后运行我们新创建的contorller:
CCDirector::sharedDirector()->runWithScene(GameBoardController::scene());
好了,现在编译并运行。当程序跑起来的时候,这个结果和cocos2d自带的模板运行效果差不多。但是,有个很重要的区别,那就是我们创建了一个mvc的骨架,在接下来的游戏逻辑中,我们可以在上面做很多文章。
接下来做什么
该项目进行到现在,已经为我们引入一些更高级的概念打下了良好的基础,所以,在下一篇教程里,我们将涉及下面两个东西:
11 处理touch事件.
12 引用model的概念.
参考来源:http://www.cnblogs.com/andyque/archive/2012/03/18/2390100.html