现在的位置: 首页 > 综合 > 正文

Cocos2d-x里面如何实现MVC(三)

2013年10月28日 ⁄ 综合 ⁄ 共 3058字 ⁄ 字号 评论关闭

  引子:前面两篇文章介绍了一些关于在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 上面。

wps_clip_image-26341

基本概念

来自 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的一个控制器。

wps_clip_image-42

    请注意,这里的实线代表一种直接的关联关系(controller里面包含一个view的引用),而虚线则代表了一种间接的关联(通过观察者模式)。这里的直接关联后面会用来实现touch事件处理。

实现

项目组织结构

    在VS2008里面基于cocos2d-x的默认模板创建一个新的项目之后,我们又创建了下面这些组:

9 View – views & controller 组 (我们也可以把view和controller放在那个不同的group里面,但是,由于我们两个有直接的关联关系,为了方便,我就把它们放在一起了)

10 Model – 之后,我们会把model类放在这个group下面。

wps_clip_image-25180

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的概念.

抱歉!评论已关闭.