一、简单介绍
卡牌类游戏一直以短周期、低成本、高风险、高利润著称,这样的特征吸引了众多冒险者前来开拓这片崭新的领域。
介于我所在的项目中使用Cocos2D-x引擎进行开发。但该引擎无论在CPU利用率,场景资源管理,以及UI控件开发效率上均有欠缺,不能很好的满足卡牌游戏的需求。
1.优化引擎渲染模块。卡牌类游戏是一种低交互,长时间在线的游戏。而Cocos2D-x引擎为单线程引擎,并不能充分利用手机的多核CPU。下文分析了几种多线程渲染引擎的特点,以及游戏循环时间同步方式,在详细研究原渲染模块结构之后,改写了当前的渲染模块,实现游戏线程和渲染线程的分离。提高游戏运行时的CPU利用率,游戏运行帧数。
2.优化场景管理模块。Cocos2D-x引擎不能满足卡牌游戏复杂场景的切换需求,利用双层状态机的思想管理场景的加载和释放,减少了游戏开发难度,同时优化了场景资源的资源管理流程。
3.构建新版UI系统。Cocos2D-x的UI系统在屏幕适配,扩展性和开发流程上均存在缺陷。针对卡牌类游戏
二、手机游戏引擎研究
除了各个公司的自研引擎外,市场上的手游引擎主要有Unity和Cocos2D-x.相较于Coscos2D-x,Unity是一套完整的解决方案,相关工具齐全,并且提供了相对应的上层脚本语言,极大加快了开发速度。但是内部代码并非开源。所以对于Unity来说,如果需要在后期根据具体游戏对引擎内部进行优化,是不可能完成的任务。Cocos2D-x相较于Unity,只能说是一个基本的代码库,自身不含有编辑器,也没有形成一套完整的开发工具链。但是相较于Unity,Cocos2D-x的包体更小,并且引擎是开源的,适合卡牌类这种需要较小包体,在渲染和功能上要求不高的游戏。在实际开发过程中,开发者可以在Cocos2D-x引擎的基础上,针对所开发游戏,对引擎内部代码进行适当的修改,并在其上封装一套自己的框架。
三、卡牌类游戏的需求
卡牌游戏是一种低强度的游戏类型。卡牌游戏的中心一般放在卡牌的收集和卡牌的升级上。尤其在手游端,卡牌类游戏多以回合制为主,仅提供极少量可供玩家操作的功能,针对这种游戏模式,游戏不需要有太高帧率,一般20帧左右足够。同时没有必要设计类似于动作类或射击类游戏复杂的同步机制。但在此同时,卡牌类游戏属于大量耗费时间的游戏类型,玩家需要每天花费巨额的时间做任务,收集卡片,升级卡片上。所以在游戏运行时,尽量减少电量的消耗,提高手机硬件的利益效率,减少不必要的资源加载。
四、Cocos2D-x游戏引擎
Cocos2D-x是一个开源2D游戏引擎(也有3D版本)。在MIT许可证下发布的。以Cocos2D-x为引擎的游戏具有开发快速,简易等优点。Cocos2D-x由cocos2d-iphone进行而来,作者重写了原引擎中的OC代码,把原先OC代码重构C++代码。以Cocos2D-x引擎为核心,使用C++代码作为平台代码,可以很容易的建立和运行在IOS,Android,黑莓Blackberry等操作系统之上。Cocos2D-x还支持Windows,Mac和Linux等桌面操作系统,因此开发者编写的源代码可以很容易在桌面操作系统中编译和调试。为了加快开发速度,Cocos2D-x还提供了lua,JS,Html版本。
Cocos2D-x相较于其他引擎,最大的优点在于他的简单可靠。在实际的C++使用中,动态内存分配是一把双刃剑,一方面动态内存提高了应用程序的性能及内存使用的灵活性,但由于程序没有正确地分配和释放会造成内存泄露,所以Cocos2D-x仿造了Object-c语言的引用计数式内存管理方式。实际使用时,只要继承了Ref类,改对象会自动被引擎管理,大大简化了C++的使用难度。
五、Cocos2D-x的结构
Cocos2D-x是一个跨平台2D游戏引擎,底层代码使用C++编写,通过C++代码调用平台代码,上层可以选用Lua或者js。支持主流的移动的PC平台,如IOS ,Android,Win32等。Cocos2D-x使用了一系列第三方开源库,这些库支持了文件解压,图片解析,网络支持,物理引擎,音频等功能,从而使得Cocos2D-x能更加专注于整体架构和渲染部分开发。
在此基础上,Cocos2D-x封装了一些与平台无关的接口,如文件的加载,纹理的解析,线程操作等,这使渲染和其他系统的设计可以与平台无关。此外,Cocos2D-x封装了一些基础功能模块,这些功能可以供上层游戏系统使用,包括内存管理模型,纹理资源的加载和缓存,Cocos2D-x还提供了一组数据容器,使STL中的容器可以与Cocos2D-x的内存管理模型相融合。
渲染系统是Cocos2D-x的核心部分,它包括场景中元素的层级结构,提供元素的管理,遍历,绘制等功能。这些元素包括Node,Sprite,Layer,TileMap,Particle等。 这一层是与OpenGLES交互部分。
Cocos2D-x有一套游戏的动画系统,它不仅支持一些第三方设计工具,使用起来非常方便。Cocos2D-x将一些非动画的特性与动画结合起来,大大简化了游戏的开发工作,甚至连苹果公司的Sprite Kit都借鉴了Cocos2D-x中动画系统的设计,这也是Cocos2D-x在2D领域非常出色的原因。
Cocos2D-x支持非常丰富的第三方工具,如TexturePacker,SpriteHelper,Tiled,zwoptex,ParticleDesigner,CocosBuider等。而Cocos2D-x可以使用可视化GUI进行开发,它继承了场景编辑,动画设计,粒子特效,骨骼等Cocos2D-x的大部分功能,还在朝着与Cocos2D-x深度集成的方向前进。
六、Cocos2D-x工作流
Cocos2D-x把渲染模块和gameplay分开,中间通过命令模式连接在一起。分开处理游戏引擎最重要的两大部分,有利于后期整体做优化,减少每帧渲染时的DrawCall。

上图是Cocos2D-x引擎的工作流。每一帧最开始时,分发上一帧触发的所有事件。在前一帧到下一帧的过程中,前一帧触发的事件先暂存在一个队列中,之后在这帧结束时统一分发。Cocos2D-x引擎把所有的Input全部封装成事件的形式,外加引擎不同模块之间的少量调用做成的自定义事件。使用EventDispatcher分发所有的事件。监听器功能全部封装EventListener中,需要提前注册到逻辑代码中。第二步是逻辑更新。逻辑更新依据提前定义的更新顺序来制定执行的顺序,由Schedule统一管理。Cocos2D-x把动画计算和物理引擎模拟全部放在逻辑更新模块中。只不过动画以及物理引擎被制定一个特殊的优先级,PRIOPRITY_SYSTEM和PRIORITY_SYSTEM+1,PRIORITY_SYSTEM取最小整数。所以在实际使用时,保证动画和物理引擎模块的刷新会优先执行。第三步渲染部分,主要包含三个步骤:生成绘制命令,对绘制命令进行排序,执行绘制命令。渲染结束以后交换前后缓冲区,等待待定时间以后执行下一帧。
七、Cocos2D-x的渲染模块
Cocos2D-x支持在屏幕是哪个绘制精灵,文本,形状,粒子,地图等。所有的这些元素继承于Node类。通过UI渲染树把他们联系在一起。
一个场景中的元素天然的适合用树来表示,树的根节点为Scene类,UI树的每个节点都是一个Node的实例对象。每个Node节点具有一个children集合及一个parent节点。其中Scene的parent节点为空。通过这样构建UI树,可以很容易的添加,删除,修改场景中的元素。并且方便游戏模块和渲染模块的分离。渲染分为三个步骤,生成绘制命令,对绘制命令进行排序,不同Node节点绘制的先后顺序通过逻辑深度localZOrder来指定,执行绘制命令。采用中序的深度优先算法进行遍历。同时在此过程中生成MV矩阵。遍历过得节点根据具体的节点类型,把他们基本属性以及对应的MV矩阵封装到一个RenderCommand中,RenderCommand作为一个绘制命令,它定义了如何绘制一个UI元素。在执行绘制命令之前,引擎对栈上的绘制命令进行排序。在执行绘制命令的过程中,相同纹理,相同着色器,同混合方式的绘制命令在渲染过程中可以合并。合并之后的命令统称为一个Batch。

Cocos2D-x3.0版本对渲染模块进行了大量更新。相比2.0版本,更新之后的引擎实现了渲染部分和游戏部分的分离,对引擎进行集中优化更方便。在2.0版本引擎中,如果场景需要大量渲染同一纹理图片,必须使用Batch。但更新之后的渲染模块,引擎在渲染前会自动对渲染队列排序,借此实现了自动Batch。这么做加快了渲染效率,同时降低了使用难度。但受限于引擎框架,Cocos2D-x的工作流仍然是单线程。
八、Cocos2D-x的场景管理模块
Cocos2D-x自带场景管理系统,一个场景是一个以Scene为根节点的UI树,Scene中包含一个场景以及所有UI控件,如按钮,图片,精灵等。Cocos2D-x中场景类分为Scene和Layer,其中一个Scene下可以挂载任意个Layer,Layer下也可以继续挂载任意个Layer。通过一个公共的栈来控制Scene的加载,UI渲染树每次只渲染栈顶场景。使用过程中异步加载场景类中的所有数据,并把改场景类的指针存在栈中。在实际使用过程中,有可能切换到的场景只是短暂显示,之后还需要切换回切换前的场景。比如配置场景中,在完成配置修改后,还需要切回前一个场景。这种情况下,没有必要释放当前场景的资源,所以把当前的Scene保留在栈中,向栈中压入新的Scene指针,同时加载新的Scene资源。当需要切换回原先的Scene时,再把当前场景出栈。Cocos2D-x对于场景管理主要提供了三个API。ReplaceScene()直接删除当前的场景,并且把心的场景压栈。PopScene()直接把栈顶场景出栈。PushScene()把新的场景入栈,不管之前的场景。
该场景在设计上有自己的好处,首先符合Cocos2D-x自己的内存管理模式,从栈中删除的场景资源,被GC自动回收。利用单层状态机去控制场景切换,整体设计简单,在调试的过程中可以在场景进出栈的时候打log。但在卡牌类游戏中,界面的场景切换相比而言更复杂,在单个Scene中,需要保证数个Layer不动的,切换其他Layer。如果使用原有的场景管理模块,势必在编写gameplay代码时带来极大的不便。
九、Cocos2D-x的事件分发模块
Cocos2D-x的事件分发模块,基于订阅者模式设计。订阅者模式可以减少软件内模块间的耦合,同时保持模块之间高效通信。游戏过程中,需要随时处理外界的Input,比如说触摸点击,键盘输入,加速球移动等等。所有外界的Input全部是由事件管理模块分发。并且也可以定义引擎独有事件。
订阅者模式主要包括三个部分,订阅者,事件以及分发者。Cocos2D-x中订阅者统一继承于EventListener,每个EventListener由回调函数,订阅者类型type,以及一个ListenerID组成。当然回调函数可能不止一个,比如说Touch事件的订阅者提供了onTouchBegin,onTouchMoved,onTouchEnded三个回调函数。listenerID对应着一个事件源,分发过程中根据事件源找到相应的listenerID。要是用订阅者首先应该新建相应的订阅者同时注册它的回调函数。并使用分发者的API把他添加到分发者的队列中。Cocos2D-x有唯一的分发者类EventDispatcher,这个类负责添加,删除订阅者,向订阅者分发事件。订阅者保存在分发者的队列中,在一次完整的时间分发过程中,首先从IOS或者安卓层主要调用函数,把事件的相关信息传入到C++层,之后依据信息新建相应的事件,通过EventDispatcher的分发函数进行分发,传给对应的listenerID的订阅者上。在分发过程中一个listenerID可能对应对个订阅者,多个订阅者依据自身事件的优先级,或者所把绑定Node在UI渲染树中的位置去判断分发顺序。
本文围绕卡牌类游戏展开,分析了Cocos2D-x引擎在开发中的不足,并对其渲染、场景管理和UI系统进行优化。同时对比了Unity和Cocos2D-x引擎的特点,介绍了Cocos2D-x的结构、工作流、各模块功能,如渲染、场景管理和事件分发模块等。
&spm=1001.2101.3001.5002&articleId=110481910&d=1&t=3&u=f979680dbcab45c685e8d7c014812218)
1万+

被折叠的 条评论
为什么被折叠?



