如何优雅的管理游戏资源

Posts - 107,
Articles - 0,
Comments - 1721
随笔分类 -网页游戏开发
22:45 by 吴秦, 9815 阅读, ,
SpriteSheet精灵动画引擎 本文介绍Flash中SpriteSheet精灵序列图与其它渲染方式的性能对比、SpriteSheet的原理及注意实现,最后实现了一个精灵序列图的渲染引擎。本文的SpriteSheet引擎及demo可以在github上下载:/saylorzhu/SpriteSheet 动画渲染性能对比 Flash中动画制作方式有多...
00:33 by 吴秦, 2587 阅读, ,
利用CPU缓存 计算机有随机存取存储器RAM(译注:即我们常说的内存),但有更快形式的存储器。如果你希望你的应用程序的快速运行,你需要知道这些其他的存储器。今天的文章中讨论了它们,并给出了两个AS3例子,即使有这样的高级语言,你仍然可以利用它们。 RAM的确很快,但只是与硬盘,固态硬盘,光盘,互联网等等与比较时。RAM与CPU内置的高速缓存相比,它并不快。你可能已经听说过他们,CPU高速...
22:40 by 吴秦, 5506 阅读, ,
游戏中的图像资源 当今游戏早已不再是黑白机的时代,游戏都由色彩丰富、精致的图像,流畅的动画构成。Flash游戏也不例外,Flash既支持矢量图又支持位图,他们各有优缺点。本文的目的即是介绍何时使用矢量图,何时使用位图,如何在两者之间权衡? 1. 前言 首先让我们了解一下何谓矢量图,何谓位图,及各自的优缺点。这些内容与游戏无直接关系,但是了解他们的差异有助于我们在游戏中如何选择。 1.1 矢量图 矢量图(摘自:百度百科)使用直线和曲线来描述图形,这些图形的元素是一些点、线、矩形、多边形、圆和弧线等等,它们都是通过数学公式计算获得的。例如一幅花的矢量图形实际上是由线段形成...
14:00 by 吴秦, 3605 阅读, ,
PureMVC(AS3)剖析:设计模式(二) 模式 上一篇中介绍了PureMVC中使用的3种设计模式:单例模式、观察者模式、外观模式。本篇将继续介绍剩下的3种设计模式: l 使用中介者(Mediator)模式来封装UI与系统中其他对象的交互,使得各对象不需要显示地互相引用,从...
00:56 by 吴秦, 5006 阅读, ,
PureMVC(AS3)剖析:设计模式(一) 模式 PureMVC框架的目标很明确,即把程序分为低耦合的三层:Model、View和Controller。降低模块间的耦合性,各模块如何结合在一起工作对于创建易扩展,易维护的应用程序是非常重要的。PureMVC框架使用多重设计模式来实现解耦彻底...
20:57 by 吴秦, 4893 阅读, ,
PureMVC(AS3)剖析:吐槽 写在前面 世上没有银弹——不存在适用于所有情况的框架,只有适合的框架。再者任何一个好的东西(语言、框架等)最终还取决于用的人,语言和框架本身并不能保证用户的代码清晰、解耦等,当然它只是尽可能地做到这点。所以记住我写这篇不是为了否定PureMVC,相反是为了更好的了解它、使用它。 1. 吐槽一:过于强调解耦 PureMVC引入了多种设计模式、消息机制(使用观察者模式,发布/订阅模式)来解耦各个模块,它确实做到了这点,但是彻底解耦是需要代价的! 1....
12:34 by 吴秦, 12075 阅读, ,
PureMVC(AS3)剖析:实例 实例 上篇介绍了MVC的思维方式“代码重用(code reusability)、关注点分离(separation of concerns,SoC)”,并介绍了PureMVC框架的设计。本篇从一个实例出发,详细介绍PureMVC框架中的元素、推荐的项目目录组...
14:41 by 吴秦, 8431 阅读, ,
回合制页游 之战斗系统 “回合制是游戏的一种方式,全称为回合制策略游戏,所有的玩家轮流自己的回合,只有自己的回合,才能够进行操纵。回合制分类: l 战棋类游戏 n SLG:角色扮演因素较少,战斗以整体策略为主 n SRPG:角色扮演因素为主,战斗为回合制,通常己方人员较少,特别依靠培养系统铸造的强人 l 半即时制:使用行动点数系统,行动点数基于角色行动需要而设定的耗时系...
00:24 by 吴秦, 7175 阅读, ,
PureMVC(AS3)剖析:开篇 缘起 自从事flash webgame开发起,3个项目都使用到了MVC模式:1个自己构建的MVC没有使用外部框架;2个使用的PureMVC框架。对PureMVC也有了一定的深度的认识,是时候来总结、吐槽下。现在网上已经流传很多关于PureMVC的资源,但是...
22:43 by 吴秦, 8428 阅读, ,
页游资源管理 现在页游的规模越来越来大,游戏内容丰富,资源管理变得很重要。现在一款SNS页游的所有资源可达50M,MMO页游更高达几百M,不可能把资源放到一个文件里面、也不可能一次性加载完所有资源。按200kb/s的下载速度来算,50M的资源需要4+分钟,这是绝对不能忍受的事情(更何况大部分人网速比这慢)。 页游资源通常有以下几种格式:图片(jpg、png等)、xml(配置文件)、swf资源、...
14:03 by 吴秦, 65269 阅读, ,
浏览器缓存机制 浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制(如: Expires; Cache-control等)。但是也有非HTTP协议定义的缓存机制,如使用HTML Meta 标签,Web开发者可以在HTML页面的&head&节点中加入&meta&标签,代码如下: html code ...
16:37 by 吴秦, 4559 阅读, ,
楚河汉界 ——战斗系统分析 1. 战斗资源 人物和技能: 楚河汉界中人物和技能是绑定的,放在同一个资源中。人物动画使用位图序列制作,技能效果使用矢量动画使效果更炫,更平滑。 打斗效果: 楚河汉界中战斗时,技能施加到人物身上之后,的效果是与技能独立的。所有的这些效果放在一个资源中,这些效果也是使用矢量动画制作。 战斗中就是轮流播放人物的技能和添加技能伤害效果...
17:15 by 吴秦, 8457 阅读, ,
1. Flex SDK Ant Flex开发者会遇到很多,比如自动构建,在一个有着N多模块,N处源码,构建过程复杂的Flex项目开发中,依赖人力手工构建项目非常不现实(机械重复且枯燥无味的过程,相信哪位开发人员都会避之唯恐不及,而且对于人力是非常大的浪费),而通过使用Ant,我们可以将这些工作交给机器来做,机器最适合干的就是这些程序固定,顺...
15:56 by 吴秦, 22939 阅读, ,
RobotLegs轻量级AS3框架 任何一个好的东西(语言、框架等)最终还取决于用的人 语言和框架本身并不能保证用户的代码清晰、解耦等, 当然它只是尽可能地做到这点。 Robotlegs是一个用来开发Flash,Flex和AIR应用的纯AS3微架构(框架)。Robotlegs专注于将应用程序各层排布在一起并提供它们相互通讯的机制。Robotlegs试图通过提供一种解决常见开发问题的经过时间...
16:51 by 吴秦, 7926 阅读, ,
游戏中的背景音乐和声效 0. 前言 不管是大型客户端游戏还是轻量级的网页游戏,游戏中背景音乐和声效是必不可少的。好的背景音乐、声效会给游戏增色,本文不从策划/设计等角度去考虑,只从程序实现上面讲在网页游戏开发中如何去实现背景音乐、声效。背景音乐和声效有以下几个要求: ü 背景音乐与声效是分开的,可以独立设置开关 ü 背景音乐一般循环播放一直存在 ü 声效点击才触发,这种声...
13:50 by 吴秦, 8935 阅读, ,
游戏中定时器的设计 0. 前言 在游戏开发中计时器/定时器是必须的,而且会在多处用到,如吃药补血每秒回10点且持续1分钟、玩家从一点到达另一点的过程需要多少时间。下面是定时器在七雄争霸中的几个应用场景,直接上图: 场景1:建筑升级时间 场景2:建筑升级时间 场景3:科技研究时间 类似的场景还有很多,就不一一列举了。但有一点可以肯定的就是,不可能每个地方都去new一个定时器各自管理,这样会消耗大量C...
01:39 by 吴秦, 19098 阅读, ,
抽奖转盘 0. 前言 每逢过年过节各大游戏都会搞些小活动来刺激、吸引、黏住玩家,比如转盘抽奖活动,有的公司年底也喜欢搞抽奖活动。本文介绍如何设计一个flash转盘抽奖程序。先上效果,看如下Flash抽奖转盘: 注:转盘看上去比较丑,使出了吃奶劲才弄出这效果,毕竟不是专业美工人员,大家凑合着看。觉得还行鼓鼓掌,按按推荐;觉得不行,也不要拍砖,无视就行了?。 预备知识:事件机制(可以参考走在网页游戏开...
20:53 by 吴秦, 9123 阅读, ,
Flash动画原理 ——动画是将静止的画面变为动态的艺术.实现由静止到动态,主要是靠人眼的视觉残留效应.利用人的这种视觉生理特性可制作出具有高度想象力和表现力的动画影片. 0. 前言 像所有的动画显示一样,Flash的动画原理也是通过不断的刷新屏幕,利用每次屏幕上显示对象位置的不同、大小色彩的变化等产生动画效果。动画编程的关键是一定要有变化,而且该变化需要在一定时间内来完成(以达到欺骗人眼,使分解...
22:17 by 吴秦, 8738 阅读, ,
AS3事件模型 ——AS3的灵魂之一 0. 前言 ActionScript 3.0事件模型使用方便,而且符合标准,它与Adobe Flash Player显示列表(display list)完美集成在一起。ActionScript 3.0的事件模型是基于DOM 3的事件规范[1],是业界标准的事件处理体系结构,为ActionScript 3.0程序员提供了强大而直观的事件处理工具。 为了清晰理解A...
17:14 by 吴秦, 8515 阅读, ,
AS3之类 0. 前言 类:面向对象的基础,类是对象的抽象表示形式,类用来存储有关对象可保存的数据类型及对象可表现的行为的信息。 类的定义: [dynamic] [public | internal] [final] class className [ extends superClass ] [ implements interfaceName[, interfaceName... ] ] { ...
17:22 by 吴秦, 10321 阅读, ,
AS3之函数 0. 前言 函数:完成某个目标任务的代码块,它是代码重用的最小单位。 函数是可在ActionScript中调用的基本代码单位。ActionScript中用户定义的函数和内置函数都由Function对象来表示,该对象是Function类的实例。 类的方法与Function对象略有不同。与普通函数对象不同,方法和与其关联的类对象紧密关联。因此,方法或属性具有在同一类的所有实例中共享的定...
21:19 by 吴秦, 12757 阅读, ,
AS基础过关 0. ActionScript简介 ActionScript是Macromedia(现已被Adobe收购)为其Flash产品开发的,最初是一种简单的脚本语言,现在最新版本3.0,是一种完全的面向对象的编程语言,功能强大,类库丰富,语法类似JavaScript,多用于Flash互动性、娱乐性、实用性开发,网页制作和RIA应用程序开发。 ActionScript是一种基于ECMAScri...
21:26 by 吴秦, 39958 阅读, ,
——此系列谨记录我步入页游开发队伍的历程。 0.写在前面 相信有很多和我一样的人,曾多次问google、问baidu、问各大论坛——如何开发游戏?开发游戏如何入门?由于游戏开发本身其复杂、庞大、涉及东西比较多,始终不得其道,最终激情无情的被时间这把杀猪刀给磨灭。之后又一次激情澎湃,又一次不了了之……
本人喜欢玩游戏,也有幸在研究生毕业能够加入腾讯QQ游戏开发部门,本系列将记录如何步入网页...3568人阅读
cocos2d(41)
在游戏的开发过程中,前期的规划 往往比 后期的“优化”更为重要!比如多分辨率适配,如果前期没有规划好,可能导致的情况是,画面只在当前测试开发机或者一部分机型正常显示。做了多套资源适配,可以使在合适的机型使用对应的图片资源,避免在高清屏幕使用低质量的图片,在低分辨率屏幕因为图片太大而浪费硬件资源。机制与策略分离,可以让你设计出简单有效的接口。模块化的设计可以让你组织好各种逻辑流程,条理分明 ~ 前期的规划工作可以有很多,一叶也在摸索之中,以使游戏的开发尽量变的简单灵活且可控。最简单的也是最容易忽略的地方,跟我们打交道最多的要数精灵了,从图片创建一个精灵,很简单的开端,将以此展开行动
本文使用 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 仓库地址:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:253935次
积分:3829
积分:3829
排名:第8171名
原创:107篇
转载:190篇
(1)(1)(3)(9)(7)(1)(1)(3)(3)(6)(5)(2)(1)(10)(11)(9)(12)(4)(9)(3)(4)(1)(2)(3)(3)(25)(11)(5)(3)(9)(15)(1)(1)(2)(5)(6)(17)(38)(27)(2)(12)(1)(2)(1)}

我要回帖

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

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信