【深入Cocos2d-x】使用MVC架构搭建游戏Four
喜欢Four这个项目,就赶快在GitHub上Star这个项目吧!
喜欢我的文章,来微博关注我吧:王选易在学C艹
项目起源
项目Logo:

下面是该游戏的项目地址,各位想参考源代码的同学可以到我的GitHub上下载该项目的源码。

我做这个项目的原始目的是实验MVC在游戏中的应用。
Model-View-Controller(MVC)是一种组合设计模式,它体现了一种关注点分离(Separation of concerns,SoC)的思想。MVC主要把逻辑层和表现层进行了解耦,将一个问题划分成了不同的关注点。增强了应用的稳定性,易修改性和易复用性。
MVC经常被使用在Web框架中,包括J2EE,RoR和.Net中都对MVC模型进行了框架层面上的封装,以便程序员可以简单方便地作出结构良好的Web应用。
Cocos2d-x本身并没有提供内置的MVC支持,但是,我们还是可以在游戏中基于MVC架构来设计游戏。在这篇博文中,我将向大家展示一下我是如何使用MVC架构来塔尖Four这个游戏的。
游戏情景
Four这个游戏的创意来自一个叫做走四棋的传统游戏,走四棋规则的详细介绍在这里:走四棋的百度百科。
下面我简单谈一下这个面板游戏(board game)的一些特性
- 一个4行4列的棋盘(Game Board)
- 棋盘上会有一些“棋子”(Game Piece),每一个方格上只能放一个棋子(Game Piece)。
- 游戏初始化时,棋盘的上面四格和下面四格分别有4个黑子和四格白子
- 玩家可以通过话筒使棋子在棋盘上发生移动,从而触发吃子和胜利等事件。
- 当游戏中出现一个横行或者一个竖列的棋子排布变为两黑一白或者两白一黑时,即可吃掉一子。
- 当一方(黑或白)的棋子被吃到只剩一个之后,这一方被记为失败
举个例子,下面这幅图即为游戏过程中的一幅图。在下面的游戏过程中,位于(1,0)位置的黑子向左移动到(0,0)的位置后即可吃掉白子。

Cocos2d-x提供的工具
Cocos2d-x有这样一些主要的类,CCSprite,CCLayer,CCScene,CCNotificationCenter。我们会使用这些类进行游戏中MVC架构的搭建,如果你对这些类的作用不熟,请参考我的这篇博文【Cocos2d-x-基础概念】Director Scene Layer and Sprite。
我们一般的游戏流程是
- 通过AppDelegate初始化第一个CCScene。
- 在第一个CCScene创建多个CCLayer。并控制好CClayer的叠加层次(zOrder)。
- 在CCLayer中添加各种CCSprite或者CCLabelAtlas或者粒子效果。
- 在CCLayer层注册触摸事件的监听,并且在CCLayer的实现中写出相应的callback函数,对CCLayer的Child Node进行相应的逻辑处理。
这个过程看起来十分简单,并且可以十分快速地做出游戏。但是其缺陷就在于在CCLayer中我们做了太多的事情。CCLayer同时承担了逻辑层和表示层的任务。不符合我们上文中提到的关注点分离的原则。如果游戏中有较为复杂的状态转换时就捉襟见肘了。
项目的文件目录
下面是该游戏项目的目录结构,我们接下来对这几个文件夹进行分别的讲解:

下面是该项目的一个简单的类图

在类图中,虚线代表的是通过消息机制进行沟通,而在Cocos2d-x中,这种沟通是通过CCNotificationCenter来实现的。
Model(模型)

Model在游戏中代表的是消息驱动的有限状态机,Model会接受Controller层发送的消息,并根据消息来更改自己的内部数据,然后把内部数据改变这一消息发送给View,通知它更新。
Model在Cocos2d-x对应的是哪个类呢?
很遗憾,但是Cocos2d-x并没有提供状态机的feature,所以我们需要自己实现一个Model类,在Model类中,需要自己实现诸如状态转换和消息处理等功能。例如在我的Model类中,我提供了如下接口。
class Model : public CCObject {
public:
// 添加一条状态转换,from-起始状态,msg-接收的消息,to-终结状态,在msg发生时会发生状态转换
Model* addTransition(const string& from, const string& msg, const string& to);
// 检查当前状态机能否发生msg对应的状态转换
bool checkMessage(const string& msg);
// 触发msg对应的状态转换
void onMessage(const string& msg);
void onMessage(const string& msg, CCObject* o);
// 等待某个CCAction结束后发送一条消息。
void waitAction(cocos2d::CCNode* node, cocos2d::CCFiniteTimeAction* action, const string& msg);
// 得到当前状态名称
const char* getState();
};
注意以下几点:
- 让Model类继承CCObject,是为了与Cocos2d-x自身的内存管理系统一致。
- onMessage中,我们做的事情就是首先找到当前状态在msg情况下的状态转换。在状态转换后,通过
CCNotificationCenter发送一条消息通知游戏中的其他组件更新逻辑。 - waitAction中,我们是在处理一种异步的状态转换,比如一个棋子在移动时就会经历这样的状态转换start->moving->end,那么在移动结束后,View就要发送一条类似END_MOVE的消息来通知Model更新自己的状态。
Model不会持有View,所以View都是通过消息来获得Model更新的事件的。
我们在编写游戏时,应该先编写Model,然后通过测试来保证Model的正确性。
之后,我们去写View的时候,实际就是对Model这个状态机发送的各种消息的回调函数的编写了。
这样就讲表示层和逻辑层分离开,可以方便地单独测试每个模块,可维护性大大提高。
逻辑数据和实际数据
在编写Model的时候,我们经常会遇到这样的问题,就是Model中的数据是否应当与View中的数据保持一致。
比如:在View层的棋子的位置信息是否应该和Model层的位置信息保持一致?
其实,真实情况就是,这要看Model层的
计算使用那种数据形式更加方便,比如在Model中,我们会把棋盘转化为一个二维数组,这样在AI运算,逻辑判断时,更加有利,所以棋子的逻辑位置和实际位置必然是不同的。
再比如,很多时候游戏中的物理引擎的计量单位是厘米,米。而不是OpenGL中的坐标。这也是为了逻辑运算的方便。
但是有些数值,我们会让它保持一致,比如人物的属性等等。
View(视图)

View在游戏中代表的是Model消息的接受者,在Cocos2d-x中,View一般是指CCLayer的子节点,即CCSprite,CCLabelAtlas,CCMenuItem,Particle System(粒子系统)等等。
它们会重载onEnter函数,在onEnter中注册自己对某个Message的监听。同时在onExit函数中将所有监听清除。(清除监听很重要,否则会出现很可怕的野指针问题)。
Controller(控制器)

Controller在游戏中负责将用户触摸事件转化为逻辑事件(即我们上文中所说的消息),同时要对用户触摸事件中的信息进行正规化,并且通知变更。
Controller在Cocos2d-x中一般用CCLayer
来实现,因为CCLayer自然地继承了CCTouchDelegate这一接口,本身就可以触摸事件,所以我在这个游戏中所有的XXXController都是继承自CCLayer。
Controller另一个很重要的职责,就是创建View和Model,因为Controller相当于Model和View的一个中间层,所以自然Controller会同时持有View和Model的应用,来方便地传递数据。
Protocol(协议)

Protocol中定义了一些Model,View和Controller中共享的数据,
- 在
Message.h中,就定义了游戏中各种类型的消息, - 在
Tag.h中,就定义了游戏中一些Node的Tag,其实Tag这个定义不是很准确,其实这里的Tag指的是唯一标识CCNode的一个ID。 - 在
ChessboardProrocol.h中,定义了游戏中期盘的宽,搞和一些常用的数据结构。
参考文献
【深入Cocos2d-x】使用MVC架构搭建游戏Four的更多相关文章
- 钟表维修管理系统技术解析(一) MVC架构搭建
钟表维修管理系统技术解析(一) MVC架构搭建 1.1新建项目 第一步:打开VS2010界面,点击左上角文件,点击新建,选择项目 1.1(图1) 第二步:点击网站Web类型,选择ASP.net MV ...
- MVC架构在游戏开发中的应用
一 定义 MVC即Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写. MVC是一种"前端"的设计模式. MV ...
- 【JAVA】基于MVC架构Java技术荟萃案例演练
基于JAVA-MVC技术的顾客管理项目案例总结 作者 白宁超 2016年6月9日22:47:08 阅读前瞻:本文源于对javaweb相关技术和资料汇总,涉及大量javaweb基础技术诸如:Servle ...
- mvc项目架构搭建之UI层的搭建
项目架构搭建之UI层的搭建 Contents 系列一[架构概览] 0.项目简介 1.项目解决方案分层方案 2.所用到的技术 3.项目引用关系 系列二[架构搭建初步] 4.项目架构各部分解析 5.项目创 ...
- mvc项目架构分享系列之架构搭建初步
mvc项目架构分享系列之架构搭建初步 Contents 系列一[架构概览] 0.项目简介 1.项目解决方案分层方案 2.所用到的技术 3.项目引用关系 系列二[架构搭建初步] 4.项目架构各部分解析 ...
- Asp.net mvc项目架构分享系列之架构搭建初步
copy to:http://www.cnblogs.com/ben121011/p/5014795.html 项目架构各部分解析 Core Models IDAL MSSQLDAL IBLL BLL ...
- Intellij IDEA采用Maven+Spring MVC+Hibernate的架构搭建一个java web项目
原文:Java web 项目搭建 Java web 项目搭建 简介 在上一节java web环境搭建中,我们配置了开发java web项目最基本的环境,现在我们将采用Spring MVC+Spring ...
- MVC三层架构搭建
MVC三层架构搭建 项目主要是用三层来搭建项目,三层分为表现层,数据层和业务层.项目用了目前比较流行的IOC架构.目前流行的IoC 框架有AutoFac,Unity,Spring.NET等,项目中选用 ...
- mvc项目架构分享系列之架构搭建之Repository和Service
项目架构搭建之Repository和Service的搭建 Contents 系列一[架构概览] 0.项目简介 1.项目解决方案分层方案 2.所用到的技术 3.项目引用关系 系列二[架构搭建初步] 4. ...
随机推荐
- 转:HashMap深度解析(一)
HashMap哈希码hashCodeequals 本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/16843543,转载 ...
- unity3d摄像机入门01
Clear Flags 清除标记 决定屏幕的哪部分将被清除.当使用多个相机来描绘不同的游戏景象时,利用它是非常方便的 Background 背景 在镜头中的所有元素描绘完成且没有天空盒的情况下,将选 ...
- 2016-1-15 抽屉效果实现demo
// // ViewController.m // 抽屉 // // Created by Mac on 16/1/15. // Copyright © 2016年 Mac. All rights r ...
- 统计文件夹下java代码行数的小程序--主要是学习任务队列的思想
首先感谢czbk的老师,录制的视频,让我们有这么好的学习资料.……—— 统计文件夹java文件的行数,首先想到的肯定是用递归的方法,因为文件夹下面可能包含文件夹,用递归的方法,代码容易写.(这和写简单 ...
- MAC PHP MARK
这是一篇以 iOS 开发人员的视角写给广大iOS 程序猿的 PHP 入门指南.在这篇文章里我努力去发掘 objectiv-c 与 php 之间的共性,来帮助有一定 iOS 开发经验的攻城狮来快速上手一 ...
- STL源码分析----神奇的 list 的 sort 算法实现
STL中有一个std::sort算法,但它是不支持std::list的,因为list不提供RandomIterator的支持,但list自己提供了sort算法,把list的元素按从小到大的方式来排序, ...
- nno_setup制作升级包必须面临的几个问题 2
这两天的时间一直在制作应用程序的升级包,期间碰到一些问题这里一并记录下来,相信这是制作升级包必须面临和解决的问题: 1. 升级包安装程序如何不再产生新的安装.卸载程序 Inno_setup中AppId ...
- 【转】互联网全站HTTPS的时代已经到来
原文地址:http://blog.csdn.net/luocn99/article/details/39777707 前言 我目前正在从事HTTPS方面的性能优化工作.在HTTPS项目的开展过程中明显 ...
- 【转】为什么我要用 Node.js? 案例逐一介绍
原文转自:http://blog.jobbole.com/53736/ 介绍 JavaScript 高涨的人气带来了很多变化,以至于如今使用其进行网络开发的形式也变得截然不同了.就如同在浏览器中一样, ...
- 转:Web.config配置文件详解(新手必看)
转:http://www.cnblogs.com/gaoweipeng/archive/2009/05/17/1458762.html 花了点时间整理了一下ASP.NET Web.config配置文件 ...