在游戏的开发过程中,前期的规划 往往比 后期的“优化”更为重要!比如多分辨率适配,如果前期没有规划好,可能导致的情况是,画面只在当前测试开发机或者一部分机型正常显示。做了多套资源适配,可以使在合适的机型使用对应的图片资源,避免在高清屏幕使用低质量的图片,在低分辨率屏幕因为图片太大而浪费硬件资源。机制与策略分离,可以让你设计出简单有效的接口。模块化的设计可以让你组织好各种逻辑流程,条理分明 ~ 前期的规划工作可以有很多,一叶也在摸索之中,以使游戏的开发尽量变的简单灵活且可控。最简单的也是最容易忽略的地方,跟我们打交道最多的要数精灵了,从图片创建一个精灵,很简单的开端,将以此展开行动 ~
本文使用 Cocos2d-3.0alpha1 版本,创建了一个 C++ 项目,介绍在 C++ 中,如何处理资源相关的内容,如果读者使用脚本,也可以参考本文中资源管理理念而忽略语言特性,你可以在Github1 上面看到本文所有源码。(注: 本博文略有更改)
使用脚本来自动生成文件常量定义显然是个行之有效的途径,这种机械式的操作交给脚本就行了,它总能出色的完成任务,首先来看看项目的 Resources 目录内容:
以上是资源文件,那么通过脚本所生成的 “Resources.h” 文件又是什么样子的呢,脚本在 Github 仓库中可以找到(注意:资源名中最好不要有空格,以免留下“隐患”):
#ifndef cocos2dx_resource_Resources_h #define cocos2dx_resource_Resources_h #include <iostream> #include <vector> #include "cocos2d.h" using namespace std; //using namespace std; // search paths //static const std::vector<std::string> searchPaths = { // "fonts", // "images", //}; // files static const char si_CloseNormal[] = "CloseNormal.png"; static const char si_CloseSelected[] = "CloseSelected.png"; static const char sjs_file_list[] = "file_list.json"; static const char si_HelloWorld[] = "HelloWorld.png"; static const char st_MarkerFelt[] = "Marker Felt.ttf"; static const char sp_ghosts[] = "ghosts.plist"; static const char si_ghosts[] = "ghosts.png"; static const char sp_grossini_family[] = "grossini_family.plist"; static const char si_grossini_family[] = "grossini_family.png"; static const char si_JungleLeft[] = "JungleLeft.png"; ////// texture ////// // ghosts.plist static const char si_child1[] = "child1.gif"; static const char si_father[] = "father.gif"; static const char si_sister1[] = "sister1.gif"; static const char si_sister2[] = "sister2.gif"; // grossini_family.plist static const char si_grossini[] = "grossini.png"; static const char si_grossinis_sister1[] = "grossinis_sister1.png"; static const char si_grossinis_sister2[] = "grossinis_sister2.png"; // json key static const char file_name[] = "file_name"; static const char file_index[] = "file_index"; static const char texture_name[] = "texture_name"; static const char texture_plist[] = "texture_plist"; static const char texture_image[] = "texture_image"; #endif
看到通过脚本,我们生成了所有文件的常量定义,这让得我们可以在游戏中任意使用,但是请注意,这里生成的文件名称是没有包含路径的,所以在定义文件之前,也自动生成了目录列表 searchPaths,顾名思义,设定了一个目录列表,以便找寻资源,我们可以在程序的开始处使用 :
CCFileUtils::sharedFileUtils()->setSearchPaths( searchPaths );
来设定游戏的资源目录列表,这样我们就可以不用关心资源所在的目录了,你甚至可以根据需要合理的调整资源目录。
AppDelegate.cpp
const char* directorys[] = { "fonts", "images" }; std::vector<std::string> searchPaths; for ( int i = sizeof(directorys)/sizeof(directorys[0])-1; i >= 0; i-- ) { searchPaths.push_back(directorys[i]); } CCFileUtils::sharedFileUtils()->setSearchPaths( searchPaths );
注意:通过设置 searchPaths 可以让我们不用关系资源的路径所在,那么意味着资源名称必须唯一,否则可能会出现引用问题。其次,是如果使用了多套资源方案,请注意 searchPaths 的先后顺序关系。本文暂不考虑多套资源。关于忽略资源目录的做法,如果有不同看法者,欢迎留言讨论,对我来说,忽略路径是利大于弊的 ~
以上通过脚本自动生成了文件列表,但是这显然不够,我们看到资源当中有两张 打包 资源图片(可以使用 TexturePacker 对图片资源进行打包,具有占用更小空间,优化运行效率等诸多好处,后面还会介绍此点) plist 文件。我们当然也是需要使用打包中资源的,所以脚本需要能够自动解析 plist 文件,并提取出 TexturePacker 打包的资源名称,请看如下定义,同样是自动生成在 “Resources.h” 文件之中:
// ghosts.plist static const char si_child1[] = "child1.gif"; static const char si_father[] = "father.gif"; static const char si_sister1[] = "sister1.gif"; static const char si_sister2[] = "sister2.gif"; // grossini_family.plist static const char si_grossini[] = "grossini.png"; static const char si_grossinis_sister1[] = "grossinis_sister1.png";此时我们就能用以下代码来创建精灵了,都引用了资源名称定义,并且使用两种方式创建了精灵:
//直接由图片创建精灵 CCSprite * hello = CCSprite::create(si_ghosts); hello->setPosition(ccp(size.width/2,size.height/2)); this->addChild(hello); // 从打包资源创建精灵 CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(sp_grossini_family, si_grossini_family); CCSprite * sprite = CCSprite::createWithSpriteFrameName(si_grossinis_sister1); sprite->setPosition(ccp(size.width/2,size.height/2)); this->addChild(sprite);上面我们使用两种方式创建精灵,为什么会有两种方式?也许你可以看看 『子龙山人』 翻译的文章 『在cocos2d里面如何使用Texture Packer和像素格式来优化spritesheet』
其中详细的介绍了图片资源打包优化的相关细节问题,一个游戏最多的就是图片资源,优化空间最大的也是图片资源,里面详细的介绍了优化图片资源占用空间 50% 以上,如何使游戏运行内存占用优化近 50%,以 cocos2d 为例,但 cocos2d-x 同样能够适用,而且能通过脚本自动打包。 所以合理的对图片资源进行打包优化是非常有必要的。但如何处理这个流程确实不好定夺,因为不同资源的使用方式不同,因为这两种方式的存在,导致我们编写代码的逻辑不同,这需要提前预定好,所以我们考虑如下开发流程:
在游戏开发前,对所有资源打包后提供给 编写游戏人员,也就是说在写程序之前,游戏资源就已确定,那些以打包,哪些未打包都已经知道,如前面一样,通过两种方式创建精灵。但是这样的结果是,前期规定好了的,后期就无法改动,或者说很难改动,牵一发而动全身啊 ~ 这就需要加大 前期的规划 力度,以确保后期不会出现太大太多事与愿违的情形。这种情况下的 后期优化 将会非常蹩脚。况且加大前期规划的力度,可能会对整个项目的进程有所影响,如比编写人员的动工会稍缓,人力资源分配不合理。
有关图片资源类型的“透明”处理,可参考http://blog.leafsoar.com/archives/2013/11-27.html
若是使用脚本的朋友,实现方式类似的。