如何优雅的管理游戏资源

亲,想发表评论请下载哦~
该用户创建的其他应用集:
9736人查看
2116558人查看
8522人收藏
1209980人查看
12488人收藏
顾锦离||半脱
344310人查看
6264人收藏
今天的鸡脖被报警了哦
161257人查看
2998人收藏
圆圆滚滚小木头
1052028人查看
3844人收藏
顾锦离||半脱
341116人查看
2833人收藏
今天的鸡脖被报警了哦
46992人查看
1848人收藏
抑郁魔法使
567203人查看
7246人收藏
3521604人查看
19193人收藏
837624人查看
4161人收藏
我们的产品
客服邮箱:
微博/微信合作QQ:
网游玩家客服QQ:
24小时举报电话号码:
广告合作QQ:
游戏合作QQ:
北京掌汇天下科技有限公司 版权所有
京公网安备39号|如何管理游戏资源
在游戏的开发过程中,前期的规划 往往比 后期的&优化&更为重要!比如多分辨率适配,如果前期没有规划好,可能导致的情况是,画面只在当前测试开发机或者一部分机型正常显示。做了多套资源适配,可以使在合适的机型使用对应的图片资源,避免在高清屏幕使用低质量的图片,在低分辨率屏幕因为图片太大而浪费硬件资源。机制与策略分离,可以让你设计出简单有效的接口。模块化的设计可以让你组织好各种逻辑流程,条理分明 ~ 前期的规划工作可以有很多,一叶也在摸索之中,以使游戏的开发尽量变的简单灵活且可控。最简单的也是最容易忽略的地方,跟我们打交道最多的要数精灵了,从图片创建一个精灵,很简单的开端,将以此展开行动 ~
本文使用 Cocos2d-3.0alpha1 版本,创建了一个 C++ 项目,介绍在 C++ 中,如何处理资源相关的内容,如果读者使用脚本,也可以参考本文中资源管理理念而忽略语言特性,你可以在Github1 上面看到本文所有。(注: 本博文略有更改)
也许你可称之为&命名规范&,但显然它无法表达我所想说的内容,很多人在创建精灵的时候喜欢直接使用资源名称,而没有任何定义,这是一个不好的习惯,如果游戏资源不存在,缺少,或者修改名字,如此你需要在多出引用的地方一一修改。游戏开发中的变数总是无法预料,合理的&名字系统&可以节省很多人力。
我们设定一个文件,这里名为 &Resources.h& 的文件,在其中定义所有的资源名称,在游戏开发中,尽量只 使用此处的名称,如图片名称,字体名称,声音资源等。这样做有以下好处,只是简单说几点:
如果对资源做出修改,我们可以修改此处定义,以保证同步,避免缺失,命名错误,错误引用等问题在图片名定义修改时,编译器会编译出错,并自动帮助我们 &找& 出引用的地方,方便修改由于有常量定义的缘故,我们的 IDE 会自动补全所有以定义变量名称,减少出错的可能,提高效率
使用脚本来自动生成文件常量定义显然是个行之有效的途径,这种机械式的操作交给脚本就行了,它总能出色的完成任务,首先来看看项目的 Resources 目录内容:
以上是资源文件,那么通过脚本所生成的 &Resources.h& 文件又是什么样子的呢,脚本在 Github 仓库中可以找到(注意:资源名中最好不要有空格,以免留下&隐患&):
#ifndef cocos2dx_resource_Resources_h
#define cocos2dx_resource_Resources_h
#include cocos2d.h
// search paths
//static const std::vector searchPaths = {
// images,
static const char si_CloseNormal[]
= CloseNormal.
static const char si_CloseSelected[]
= CloseSelected.
static const char sjs_file_list[]
= file_list.
static const char si_HelloWorld[]
= HelloWorld.
static const char st_MarkerFelt[]
= Marker Felt.
static const char sp_ghosts[]
static const char si_ghosts[]
static const char sp_grossini_family[]
= grossini_family.
static const char si_grossini_family[]
= grossini_family.
static const char si_JungleLeft[]
= JungleLeft.
////// texture //////
// ghosts.plist
static const char si_child1[]
static const char si_father[]
static const char si_sister1[]
= sister1.
static const char si_sister2[]
= sister2.
// grossini_family.plist
static const char si_grossini[]
= grossini.
static const char si_grossinis_sister1[]
= grossinis_sister1.
static const char si_grossinis_sister2[]
= grossinis_sister2.
// json key
static const char file_name[]
static const char file_index[]
static const char texture_name[]
= texture_
static const char texture_plist[]
= texture_
static const char texture_image[]
= texture_
看到通过脚本,我们生成了所有文件的常量定义,这让得我们可以在游戏中任意使用,但是请注意,这里生成的文件名称是没有包含路径的,所以在定义文件之前,也自动生成了目录列表 searchPaths,顾名思义,设定了一个目录列表,以便找寻资源,我们可以在程序的开始处使用 :
CCFileUtils::sharedFileUtils()-&setSearchPaths( searchPaths );
来设定游戏的资源目录列表,这样我们就可以不用关心资源所在的目录了,你甚至可以根据需要合理的调整资源目录。
AppDelegate.cpp
const char* directorys[] =
fonts, images
std::vector searchP
searchPaths.push_back(fonts);
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[]
static const char si_father[]
static const char si_sister1[]
= sister1.
static const char si_sister2[]
= sister2.
// grossini_family.plist
static const char si_grossini[]
= grossini.
static const char si_grossinis_sister1[]
= grossinis_sister1.
此时我们就能用以下代码来创建精灵了,都引用了资源名称定义,并且使用两种方式创建了精灵:
//直接由图片创建精灵
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 同样能够适用,而且能通过脚本自动打包。 所以合理的对图片资源进行打包优化是非常有必要的。但如何处理这个流程确实不好定夺,因为不同资源的使用方式不同,因为这两种方式的存在,导致我们编写代码的逻辑不同,这需要提前预定好,所以我们考虑如下开发流程:
在游戏开发前,对所有资源打包后提供给 编写游戏人员,也就是说在写程序之前,游戏资源就已确定,那些以打包,哪些未打包都已经知道,如前面一样,通过两种方式创建精灵。但是这样的结果是,前期规定好了的,后期就无法改动,或者说很难改动,牵一发而动全身啊 ~ 这就需要加大 前期的规划 力度,以确保后期不会出现太大太多事与愿违的情形。这种情况下的 后期优化 将会非常蹩脚。况且加大前期规划的力度,可能会对整个项目的进程有所影响,如比编写人员的动工会稍缓,人力资源分配不合理。
若是使用脚本的朋友,实现方式类似的。后使用快捷导航没有帐号?
平板/笔记本
云服务专区
画风优雅清新的飞行游戏——超速纸飞机Vector Jet
&略有小成&
来自:浏览器
05.jpg (7.85 KB, 下载次数: 0)
09:51 上传
纸飞机是许多人的童年记忆,如今的孩子已经很少玩这样的游戏了。笔者在逛app商店时发现了这样一款名为“超速纸飞机Vector Jet”的游戏,清新的画风、简单的玩法正好可以让我们在手机上重新找寻过去的美好。
04.jpg (19.49 KB, 下载次数: 0)
09:51 上传
02.jpg (18.23 KB, 下载次数: 0)
09:51 上传
超速纸飞机的界面基本就两种颜色,总体感觉就是简约有趣的画面配上优雅动听的轻音乐。游戏中,玩家需要提前设计好飞机的飞行路线,从而让飞机在飞行中躲开重重关卡后过关。
03.jpg (15.06 KB, 下载次数: 0)
09:51 上传
画面清新,玩法简单动线路中的节点就可以变化路线,拥有50个关卡,关卡越高难度也越大。玩家在每个关卡中都要收集星星,以便解锁跟多的关卡,游戏操作方式简单,左边屏幕是控制上升和下降,右边屏幕的加速。
01.jpg (18.86 KB, 下载次数: 0)
09:51 上传
关卡增多难度增大笔者亲自尝试以后发现,虽然玩法简单,但想要过关却颇有难度。要熟练地运用飞机的上升下降和加速来躲避障碍,随着关卡增多,难度也有明显上升。
width:100%">
&禁止访问&
来自:浏览器
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
width:100%">
&禁止访问&
来自:浏览器
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
width:100%">
秋摄宜人秋色(六)初夏的塘河古镇品尝金秋的美酒龙脊梯田的日与夜印象普陀 2017 (一)
花粉客户端
Make it Possible
Make your device special
华为云服务
Huawei cloud services
音乐播放器
Huawei Music
Huawei Vmall
没有最新动态
关注花粉俱乐部
举报邮箱:
|关注花粉俱乐部:
Copyright (C)
华为软件技术有限公司 版权所有 保留一切权利cocos2d:如何优雅的管理游戏资源 - CSDN博客
cocos2d:如何优雅的管理游戏资源
在游戏的开发过程中,前期的规划 往往比 后期的“优化”更为重要!比如多分辨率适配,如果前期没有规划好,可能导致的情况是,画面只在当前测试开发机或者一部分机型正常显示。做了多套资源适配,可以使在合适的机型使用对应的图片资源,避免在高清屏幕使用低质量的图片,在低分辨率屏幕因为图片太大而浪费硬件资源。机制与策略分离,可以让你设计出简单有效的接口。模块化的设计可以让你组织好各种逻辑流程,条理分明 ~ 前期的规划工作可以有很多,一叶也在摸索之中,以使游戏的开发尽量变的简单灵活且可控。最简单的也是最容易忽略的地方,跟我们打交道最多的要数精灵了,从图片创建一个精灵,很简单的开端,将以此展开行动
本文使用 Cocos2d-3.0alpha1 版本,创建了一个 C++ 项目,介绍在 C++ 中,如何处理资源相关的内容,如果读者使用脚本,也可以参考本文中资源管理理念而忽略语言特性,你可以在 Github[^1] 上面看到本文所有源码。
也许你可称之为“命名规范”,但显然它无法表达我所想说的内容,很多人在创建精灵的时候喜欢直接使用资源名称,而没有任何定义,这是一个不好的习惯,如果游戏资源不存在,缺少,或者修改名字,如此你需要在多出引用的地方一一修改。游戏开发中的变数总是无法预料,合理的“名字系统”可以节省很多人力。
我们设定一个文件,这里名为 “Resources.h” 的文件,在其中定义所有的资源名称,在游戏开发中,尽量只&使用此处的名称,如图片名称,字体名称,声音资源等。这样做有以下好处,只是简单说几点:
如果对资源做出修改,我们可以修改此处定义,以保证同步,避免缺失,命名错误,错误引用等问题在图片名定义修改时,编译器会编译出错,并自动帮助我们 “找” 出引用的地方,方便修改由于有常量定义的缘故,我们的 IDE 会自动补全所有以定义变量名称,减少出错的可能,提高效率这个文件列表显然可以写一个如 python 脚本自动生成
使用脚本来自动生成文件常量定义显然是个行之有效的途径,这种机械式的操作交给脚本就行了,它总能出色的完成任务,首先来看看项目的 Resources 目录内容:
[Resources]~ ./tree
├── CloseNormal.png
├── CloseSelected.png
├── HelloWorld.png
├── file_list.json
├── fonts
│&& └── Marker\ Felt.ttf
└── images
├── JungleLeft.png
├── ghosts.plist
├── ghosts.png
├── grossini_family.plist
└── grossini_family.png&
以上是资源文件,那么通过脚本所生成的 “Resources.h” 文件又是什么样子的呢,脚本在 Github 仓库中可以找到(注意:资源名中最好不要有空格,以免留下“隐患”):
#ifndef _AUTO_RESOURCES_H_
#define _AUTO_RESOURCES_H_&
// search paths
static const std::vector<std::string> searchPaths = {
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&; &
#endif // _AUTO_RESOURCES_H_
看到通过脚本,我们生成了所有文件的常量定义,这让得我们可以在游戏中任意使用,但是请注意,这里生成的文件名称是没有包含路径的,所以在定义文件之前,也自动生成了目录列表&searchPaths,顾名思义,设定了一个目录列表,以便找寻资源,我们可以在程序的开始处使用&FileUtils::getInstance()-&setSearchPaths(searchPaths);&来设定游戏的资源目录列表,这样我们就可以不用关心资源所在的目录了,你甚至可以根据需要合理的调整资源目录。
注意:通过设置 searchPaths 可以让我们不用关系资源的路径所在,那么意味着资源名称必须唯一,否则可能会出现引用问题。其次,是如果使用了多套资源方案,请注意 searchPaths 的先后顺序关系。本文暂不考虑多套资源。关于忽略资源目录的做法,如果有不同看法者,欢迎留言讨论,对我来说,忽略路径是利大于弊的 ~
以上通过脚本自动生成了文件列表,但是这显然不够,我们看到资源当中有两张&打包&资源图片(可以使用 TexturePacker 对图片资源进行打包,具有占用更小空间,优化运行效率等诸多好处,后面还会介绍此点) plist 文件。我们当然也是需要使用打包中资源的,所以脚本需要能够自动解析 plist 文件,并提取出 TexturePacker 打包的资源名称,请看如下定义,同样是自动生成在 “Resources.h”
文件之中:
////// 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&;
此时我们就能用以下代码来创建精灵了,都引用了资源名称定义,并且使用两种方式创建了精灵:
// 直接由图片创建精灵
auto hello = Sprite::create(si_HelloWorld);&
// 从打包资源创建精灵
SpriteFrameCache::getInstance()->addSpriteFramesWithFile(sp_grossini_family, si_grossini_family);
auto sister = Sprite::createWithSpriteFrameName(si_grossinis_sister1);
上面我们使用两种方式创建精灵,为什么会有两种方式?也许你可以看看&&翻译的文章&其中详细的介绍了图片资源打包优化的相关细节问题,一个游戏最多的就是图片资源,优化空间最大的也是图片资源,里面详细的介绍了优化图片资源占用空间 50% 以上,如何使游戏运行内存占用优化近 50%,以 cocos2d 为例,但 cocos2d-x 同样能够适用,而且能通过脚本自动打包。 所以合理的对图片资源进行打包优化是非常有必要的。但如何处理这个流程确实不好定夺,因为不同资源的使用方式不同,因为这两种方式的存在,导致我们编写代码的逻辑不同,这需要提前预定好,所以我们考虑如下开发流程:
在游戏开发前,对所有资源打包后提供给 编写游戏人员,也就是说在写程序之前,游戏资源就已确定,那些以打包,哪些未打包都已经知道,如前面一样,通过两种方式创建精灵。但是这样的结果是,前期规定好了的,后期就无法改动,或者说很难改动,牵一发而动全身啊 ~ 这就需要加大&前期的规划&力度,以确保后期不会出现太大太多事与愿违的情形。这种情况下的&后期优化&将会非常蹩脚。况且加大前期规划的力度,可能会对整个项目的进程有所影响,如比编写人员的动工会稍缓,人力资源分配不合理。
前文提到,我们使用了 searchPaths 变量,以用忽略资源的路径,一个存在的东西,看起来好像不存在一样,我们称之为 “透明”,”透明” 在软件领域中也是重要的概念,它也强调着封装的重要性,隐藏细节的必要性。这里的资源路径就是如此,我们可以说&对于资源的使用来说,它的路径是透明的,有没有路径,路径为何?那不重要,重要的是你能通过资源名称获取想要的资源。
也许你已经发现了,我想说的不是路径问题,而是图片资源问题。对于图片资源的使用来说,它’是否是打包资源’ 应该是透明的。也既是在使用图片资源的时候,你不应该关心它是不是打包后的资源,是也好,不是也罢,这不应该影响你对资源的请求和使用。”打包” 这个过程对你来说,不存&~
图片资源类型的
“透明化” 处理
先来段代码,看看没有 “透明化” 处理时的一般使用方式:
auto jungle = Sprite::create(si_JungleLeft);&
SpriteFrameCache::getInstance()->addSpriteFramesWithFile(sp_grossini_family, si_grossini_family);
auto sister = Sprite::createWithSpriteFrameName(si_grossinis_sister1);
以上我们看到,同样是创建精灵,&si_JungleLeft&是普通的&文件资源,而&si_grossinis_sister1&是&打包资源,这决定着两者的使用方式不同,那么怎么 “透明化” 处理呢:
// 不论图片属于 文件资源 还是 打包资源 使用方法相同
auto jungle = AssetLoader::createSprite(si_JungleLeft);
auto jungle = AssetLoader::createSprite(si_grossinis_sister1);
我们提供了一个类&AssetLoader,它有一个方法&createSprite(const std::string& name)。不论我们是不是打包资源,我们都通过这个方法来创建精灵,显然它的内部工作原理是根据图片的实际类型,动态判断并创建,之后返回,要实现这样一个功能是可行的,并且没有多复杂,实现以后。我们在使用图片资源的使用就再也用关心它是什么类型的资源了。
这也意味着你可以以一个理想的方式来管理开发流程。&图片资源可以和游戏编写同时进行,不停的添加图片资源,不停的编写游戏逻辑,而不用考虑图片是否已经优化的问题了,此时可以提供一些零散的图片,以供使用(图片命名最好还是固定),当然也可以提前把关联性比较强的图片提前打包处理,这并不影响使用,因为对程序来说,它&是透明的,”不存在”的。在后期,我们可以集中的在后期对游戏资源优化,打包处理等(关于此点,文章后面也会给出相对合理的处理流程)。
功能的实现方案与流程
在开始之前,一叶通常会将其流程在心中演算一遍,使其不会出现太大的纰漏,对于不合理的所在,可以重新拟定方案。然后实现之 ~ 要使得 AssetLoader 的 createSprite 方法完成其功能,那么它需要知道,当前请求的&图片资源&是否是&文件资源(以&文件资源&和&打包资源&区分两者),如果是,直接由前文&方式一&创建精灵返回,如果不是,则从
打包资源 里面找寻,找到就通过&方式二&创建精灵并返回,如果还没找到,就返回空指针喽 ~ 由此我们知道 AssetLoader 它内部需要完成以下功能:
能够判断一个资源是否是文件资源能够根据打包资源图片名称返回实际的 plist 文件(打包资源描述文件)和 图片文件
要完成以上功能,那就需要让 AssetLoader 知道有哪些文件资源,还要知道有哪些打包资源,我们可以在 AssetLoader 里面定义几个字典用以保存这些数据:
class AssetLoader: public Object{
static Sprite* createSprite(const std::string& name);&
static AssetLoader* getInstance();
bool init();&
bool fileExists(const std::string& filename);
std::string getTexturePlist(const std::string& name);
std::string getTextureImage(const std::string& name);&
Dictionary* _fileDict;
// 文件列表
Dictionary* _texturePlistDict;
// 打包资源到文件的映射
Dictionary* _textureImageDict;
// 打包资源plist 到图片的映射
如以上的定义实现,它有三个字典,&_fileDict&的 key 保存着所有文件资源,value 保存文件资源的&编号&,这样我们就能够随时判断一个图片是否是文件资源了。_texturePlistDict&的 key 保存着打包资源的名称,value 保存打包资源所在 Plist 文件的编号,通过它我们能通过打包资源获取到它
Plist 所在的文件。&_textureImageDict&也是类似,key 保存打包资源名称,value 保存打包资源所在的真实 图片文件的引用。
功能已经定义完毕,现在的问题是我们如何去为这几个字典填充数据?显然程序初始化手动填充不靠谱,前文的文件名等信息都已经是自动定义了,此处我们当然也希望有一个方案&自动填充&了。这里的做法是,在使用 python 生成资源定义的时候,同时生成一个 json 文件,这个文件里面包含了所有此处字典中所需要的数据,然后 AssetLoader 初始化的时候读取这个 json 文件,以完成自动填充数据的功能。先来看看自动生成的
json 文件长什么样纸:
题外话:使用 json 来存储这样一个中转的数据格式是最后定下来的方案,设计之初考虑过几种方案,比如想到可以用一个 sqlite 数据来保存各种数据,这样数据的操作就非常统一,对后期的数据统计分析也会非常方便,曾与朋友 子龙山人 讨论过这之间的详细细节,以及各种实现方案的利弊分析。使用 sqlite 的好处是更为灵活,后期扩展功能会非常方便,适合稍微大点的项目,但是如果一个项目本身没有使用 sqlite 数据库,如果为这里的方案而硬添加一个扩展库实现 sqlite,可能就会非常的不友好,不通用。
&file_name&: [
&CloseNormal.png&,
&CloseSelected.png&,
&file_list.json&,
&HelloWorld.png&,
&Marker Felt.ttf&,
&ghosts.plist&,
&ghosts.png&,
&grossini_family.plist&,
&grossini_family.png&,
&JungleLeft.png&
&file_index&: [
&1&, &2&, &3&, &4&, &5&, &6&, &7&, &8&, &9&, &10&
&texture_name&: [
&child1.gif&,
&father.gif&,
&sister1.gif&,
&sister2.gif&,
&grossini.png&,
&grossinis_sister1.png&,
&grossinis_sister2.png&
&texture_plist&: [
&6&, &6&, &6&, &6&, &8&, &8&, &8&
&texture_image&: [
&7&, &7&, &7&, &7&, &9&, &9&, &9&
以上是自动生成的 json 数据文件内容,为了在这里展示,做了点格式化和缩进,更为友好一点。通过&file_name&和&file_index&可以创建文件资源列表字典,通过&texture_name&和&texture_plist&可以创建打包资源和文件资源之间的映射,&texture_image&也是同样。
file_name 包含了所有文件资源,file_index 为文件资源做了编号,这两个数据项的个数是相同的。 texture_name 定义了所有打包资源的定义,texture_plist 和 texture_image 则保存了 打包资源所在的 plist 文件和图片文件的引用,它们的数据项个数也是相同的。只要保证这里生成的内容没有错误,那么我们就正确的将其填充到 AssetLoader 的字典里面,以实现想要的功能。
为什么数据会长这个样子?一叶本来的设计 json 文件,多层嵌套更具描述性(各种对象,各种属性,一目了然),但是发现 解析的时候稍显麻烦,在 新版 cocos2d-x 的 gui 库中,已经封装好了一些常用的 json 解析功能,本着&拿来注意(尽可能的寻找可用的资源来简化自身的流程) 的思想,为使解析过程简单,所以数据格式就定义成那个样子了 - =。现在只是用了五个数组(更平面化的数据组织,像是数据库表),保存所有数据。只能说,这样做是为了迎合代码的编写,让本来复杂的
json 解析过程变得更为简单。现在看来,但到也简单清晰,看看填充字典的关键代码实现(如果有其它更好的方式,修改也不麻烦,修改生成的数据格式,再修改代码中数据的填充方法就行了):
JsonDictionary *jsonDict = new JsonDictionary();
String* fileContent = String::createWithContentsOfFile(sjs_file_list);
jsonDict->initWithDescription(fileContent->getCString());&
DictionaryHelper* dicHelper = DICTOOL;&
_fileDict = Dictionary::create();
int file_idx = dicHelper->getArrayCount_json(jsonDict, file_name);
for (int i = 0; i < file_idx; i++){
std::string name = dicHelper->getStringValueFromArray_json(jsonDict, file_name, i);
std::string index = dicHelper->getStringValueFromArray_json(jsonDict, file_index, i);
_fileDict->setObject(String::create(index), name);
log(&file count: %d&, file_idx);&
_texturePlistDict = Dictionary::create();
int texture_idx = dicHelper->getArrayCount_json(jsonDict, texture_name);
for (int i = 0; i < texture_idx; i++){
std::string name = dicHelper->getStringValueFromArray_json(jsonDict, texture_name, i);
std::string plist = dicHelper->getStringValueFromArray_json(jsonDict, texture_plist, i);
_texturePlistDict->setObject(String::create(plist), name);
log(&texture count: %d&, texture_idx);&
_textureImageDict = Dictionary::create();
for (int i = 0; i < texture_idx; i++){
std::string name = dicHelper->getStringValueFromArray_json(jsonDict, texture_name, i);
std::string image = dicHelper->getStringValueFromArray_json(jsonDict, texture_image, i);
_textureImageDict->setObject(String::create(image), name);
CC_SAFE_DELETE(jsonDict);
这里能看到一些陌生的内容&JsonDictionary、DictionaryHelper类型和其操作方式,这里的使用方法不是本文的重点,有兴趣的朋友看看源码实现。以很简洁的方式,填充了我们需要的字典数据内容。有了这些字典数据,我们就很容易的判断一个图片是否是文件资源了,如果是打包资源,也能够很容易找出打包资源所在的 Plist 文件和 图片文件,最后看一下&createSprite&方法的实现:
Sprite* AssetLoader::createSprite(const std::string& name){
if (AssetLoader::getInstance()->fileExists(name)){
return Sprite::create(name);
log(&create sprite: %s&, name.c_str());
std::string plistfile = AssetLoader::getInstance()->getTexturePlist(name);
std::string imagefile = AssetLoader::getInstance()->getTextureImage(name);
log(&plist: %s, image: %s&, plistfile.c_str(), imagefile.c_str());
if (plistfile != && && imagefile != &&){
SpriteFrameCache::getInstance()->addSpriteFramesWithFile(plistfile, imagefile);
return Sprite::createWithSpriteFrameName(name);
return nullptr;
至此我们便完成了&图片资源类型的 “透明化” 处理&。这样一个解决方案,很好的解决了在开发过程中图片资源的管理过程,后期优化,都不冲突。能够通过此提供一个较为合理的开发流程。 本文所使用的源码,脚本等都可以在 Github 上面找到 『』,但是要清楚,我这里提供的只是按照我这种流程下来的一种实现而已,对于程序本身而言,也还有很多可以改进的所在
~ 思路同样,每个人实现的具体细节可能不一样,不论你使用 C++ 还是脚本语言,都不影响你 “透明化” 图片资源类型。
如何优雅的管理游戏资源
我们解决了一些问题,提供了一些解决方案,但总有更多的问题等着我们去解决,更多的优秀解决方案,好的工作模式,处理流程。我们会把开发中一些&变动&的所在找寻出来,对它灵活的处理,使它能够适应各种不同的&险恶环境。哪些是不变的,哪些是容易变动的,尽量做到&以不变应万变。现在新的问题和需求又来了,哈
继续前文内容,我们可以使用 AssetLoader 来加载图片资源,创建精灵,实现游戏玩法逻辑等。但是我们通常会在一个场景进入时就预先缓存所有图片资源(声音资源亦是同样),甚至在游戏开始时,预先加载所有的图片资源,以&保证游戏画面的流畅性。如果没有预先缓存图片资源,那么在游戏中用到的时候,实时加载可能&会使游戏画面卡顿,这不是我们想看到的结果。如果一个游戏不大,资源总和也没多少,那么可以直接在游戏开始时全部加载完毕,这种情况处理起来比较简单,直接把所有资源加载就可以了。但是如今的游戏动辄几十兆,几百兆,显然游戏资源一次性加载是不科学的,这时我们可以分场景,在加载一个场景的时候,清空前一个场景所使用的图片缓存资源,然后预先加载当前场景的游戏资源,以达到最优的内存占用。
通常我们都是人为的,定义了一个方法在开始场景前做一些准备工作,清空缓存,预加载游戏资源,如这里有一个需要预加载的资源列表,而前文我们提到,在游戏开发的过程中,我们的图片资源可能会有所改动,这就需要我们去&人为的同步去手动维护这个列表,而这样的工作费时费力,还容易出现很多错误,如果我们能够把这一步的操作自动化,根据实际情况生成其列表,并且列表资源的加载顺序也是做过优化的(根据文件大小,或者分辨率大小,优先加载大的资源,使游戏减少因占用内存过多而崩溃的可能性),那将使我们能有&更多的精力花在更值得的地方。如果结合到本文之前的实现方案就是,在开始一个场景时,我们对
AssetLoader 做一个标记,在这个标记之后所请求的图片资源都是当前场景的资源,我们可以在内部将其记录下来,以任何方式都行,这样我们就能够非常容易的收集并生成当前场景所使用的图片资源了。如果我们将这个列表做成动态可维护的,自动记录以便下次运行时预先加载,这样一种实现从逻辑上来说时可行。如何优雅得管理游戏资源?但是实现比&优雅&更重要,在实现的过程中,尽量使开发变得简单,流程变得清晰,也是一叶努力的方向 ~
以上只是对预加载资源列表的动态维护,提供了一个简单的思路,其中还有很多细节值得推敲。但我想实现这样一种流程对游戏的开发是非常有帮助的,对于这个部分的内容,一叶还没有给出一个具体的实现方案,但将继续之前的流程往下实现,并分享在 Github 上面,同时你也可以参与进来。也算是在这里集思广益,如果你有什么好的想法,对本文实现有什么改进,都可以一起交流。如果你遇到了相同的问题,也可以说说你是怎么处理这些问题的,欢迎分享 ~
[^1]: 本文源码 Github 仓库地址:
本文已收录于以下专栏:
相关文章推荐
关于游戏的优化的文章已经非常多和详尽了,包体大小、合图压缩、音频压缩等,所有的优化都是围绕着cpu和gpu开展。
目前的硬件水平足以支持大部分非3D游戏,drawcall的场景基本上不会有超过一百的情...
在游戏的开发过程中,前期的规划 往往比 后期的“优化”更为重要!比如多分辨率适配,如果前期没有规划好,可能导致的情况是,画面只在当前测试开发机或者一部分机型正常显示。做了多套资源适配,可以使在合适的机...
[叶落归根]: /archives/.html
在游戏的开发过程中,前期的规划 往往比 后期的“优化”更为重要!比如多分辨率适...
这篇文档将介绍Cocos2d-JS 3.0的一个重量级新特性:资源管理器(仅支持JSB)。资源管理器是为游戏运行时的资源热更新而设计的,这里的资源可以是图片,音频甚至游戏脚本本身。使用资源管理器,你将...
避免一个接一个地加载PNG和JPG纹理(他们之间至少等待一帧)
cocos2d里面纹理加载分为两个阶段:1.从图片文件中创建一个UIImage对象。2.以这个创建好的UIImage对象来创建 C...
在游戏的开发过程中,前期的规划 往往比 后期的“优化”更为重要!比如多分辨率适配,如果前期没有规划好,可能导致的情况是,画面只在当前测试开发机或者一部分机型正常显示。做了多套资源适配,可以使在合适的机...
在游戏的开发过程中,前期的规划 往往比 后期的“优化”更为重要!比如多分辨率适配,如果前期没有规划好,可能导致的情况是,画面只在当前测试开发机或者一部分机型正常显示。做了多套资源适配,可以使在合适的机...
本站文章均为 李华明Himi 原创,转载务必在明显处注明:转载自【黑米GameDev街区】 原文链接: /cocos2dx-v2-0/997.html  ...
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 优雅女子培训 的文章

 

随机推荐