《游戏中的资源打包.doc》由会员分享,可在线阅读,更多相关《游戏中的资源打包.doc(12页珍藏版)》请在金锄头文库上搜索。
1、游戏中的声音资源打包董波介绍在以前的游戏当中,几乎所有的游戏都有将资源打包,无论是图形资源、声音文件等等。现在,越来越多的游戏的声音资源都公开了,通常背景音乐等采用ogg,音效采用wav;但是图形资源绝大部分游戏还是都是打包了的。有的有加密,有的没有。在学习游戏编程的初期我就对这个东西很感兴趣,但是又没有人教,到网上找资料也少得可怜,所以就只好自己摸索了。记得去年也做过类似的工作,但是当时做的感觉很不好,采取了一些投机取巧的方法,虽然看起来是打包了,但是实际上只是一个躯壳而已。随着时间的推移,自己懂得比以前稍微多了一点点,就想做点什么,即使现在还是“菜青虫”水平,“菜鸟”都算不上,呵呵。马上要
2、毕业了,论文也早Over了,所以时间挺多的,因此写点这样的东西,希望现在的“曾经的我”能够从这个文章里边得到一点灵感。这篇文章将介绍一种最简单的声音文件打包并播放的方法。最简单意味着它没有加密没有考虑太多的特殊情况,只实现了最简单的wav打包和播放,流媒体没考虑在内,因为它们的处理毕竟还是有很大的不同的。注意本文中所提到的程序以及附件都使用Visual Studio 2008 编写,项目文件也只能用VS2008打开。另外依赖于boost.filesystem、boost.shared_ptr、boost.unoredered_set,说白了如果您想查看效果的话必须安装boost,boost的安
3、装教程可以参考我写得这个:http:/ 。另外声音播放我使用的Fmod引擎,所以您需要到http:/www.fmod.org/ 去下载最新的fmod引擎sdk安装并配置好VS。我相信VS2005和VS2008在配置正确的情况下应该都能编译通过的 。文件打包文件打包有很多方式的,我采取了一种比较简单的方式,我将打包后的结果分为数据文件和索引文件两部分,这样的好处是什么呢?至少我们追加文件的时候很方便也很快。加入我们采用文件头的形式,即索引在数据文件的头部,那么当我们要添加的新文件的时候,则意味着所有文件的重写,因为操作系统不会提供一个执行“插入”操作的API。这样最直接的好处就是游戏工具执行“保
4、存”动作的时候的快速性。另外,文件打包还可以选择是否加密,是否压缩等等。加密这块我不是很了解,我去年做过一个加了密的,但是后来反思的时候发现并没有什么意义,与其说文件打包是为了保护资源的话,还不如说是为了管理的方便和效率。因为我觉得在一个电脑高手面前,加不加密并没有什么意义,比如说传奇式的”mycrack”大大。压缩个人以为还是有点意义的,至少可以少占不少硬盘,当然,这是需要付出代价的,运行时必须解压。Ogre3D中就支持zip打包,应该也是使用zlib来做的,使用zlib来做这个事情是很容易的,呵呵。它的官方网站是:http:/ dbclass CFilePackpublic:typedef
5、 detail:Node node_type;typedef detail:CFilePackImp:node_vec node_vec;public:CFilePack( const std:wstring& strDataFileName, const std:wstring& strIndexFileName);CFilePack(const std:string& strDataFileName,const std:string& strIndexFileName);CFilePack();public:bool addFile( const std:string& strFileNa
6、me );bool addFile( const std:wstring& strFileName );bool load();bool save() const;const node_vec& getNodes() constreturn m_spImp-getNodes();protected:boost:shared_ptr m_spImp;最终对CFilePack的调用将被转发到detail:CFilePackImp中。提供多种字符串的重载,最终将使用string_shim转换到char调用detail:CfilePackImp的对应的函数:namespace dbnamespace
7、detailclass Nodepublic:enumSIZE = 20;char szNameSIZE;unsigned uOffset;unsigned uSize;public:bool operator = ( const Node& node ) constreturn _stricmp( szName, node.szName ) = 0;bool operator = ( const char* strName ) constreturn _stricmp( szName, strName ) = 0;bool operator ( const Node& node ) cons
8、treturn _stricmp( szName, node.szName )0;class CFilePackImppublic:typedef std:string string_type;typedef unsigned offset_type;typedef std:vector node_vec;public:public:CFilePackImp( const string_type& strDataFileName,const string_type& strIndexFileName );CFilePackImp();public:bool addFile( const str
9、ing_type& strFileName );/bool deleteFile( const string_type& strFileName );public:bool load();bool save() const;inline const node_vec& getNodes() constreturn m_vecNodes;protected:string_type m_strDataFileName; / 数据文件名string_type m_strIndexFileName; / 索引文件名node_vec m_vecNodes;static const size_t uMax
10、SaveBytesOnTime = 1024 * 1024; / 1M;有了这两个类我们就可以这样来生成打包后的数据文件和索引文件,当然下面的Demo代码忽略了错误检测等等:#include filepack.hppint main()/ 下面我们使用这个类把三首歌曲打包成一个数据文件和一个索引db:CFilePack pack( music.data, music.inx );pack.addFile( drumloop.wav );pack.addFile( jaguar.wav );pack.addFile( Lswish.wav );/ pack.load();return 0;实现细
11、节就不说了,大家可以参考附件。声音加载与播放现在我们要做的就是从索引文件中读取出文件信息,然后去数据文件中找我们感兴趣的数据。在上面的代码中我们可以看到,每一个索引节点都由固定长度的文件名字符串、在数据文件中的偏移量和数据的长度组成,现在在管理中就应该先获取这些信息,由于索引文件通常都很小,所以我们在程序运行期间将这些信息保存在内存中,根据是否有boost分别选择散列表unordered_set或者红黑树实现的set来保存。由于在整个系统中通常都只有一个这样的声音文件包,因此我们实现一个简单的单件管理类,这是它的接口类:#pragma once#include #include ISound.
12、hppnamespace dbclass ISoundManagerpublic:typedef std:string string_type;public:virtual bool initialize( const string_type& strDataFile, const string_type& strIndexFile ) = 0;virtual ISound_SP createSound( const string_type& strFile ) = 0;virtual void release()=0;从它我们实现一个Fmod的管理类:#include .pack_basec
13、onfig.hpp#include ISoundManager.hpp#include Singleton.hpp#include .pack_basefilepack.hpp#include #ifdef _DB_WORK_WITH_BOOST_#include #define _SOUND_MANAGER_CONTAINER_IMP_ boost:unordered_setstruct ihash : public std:unary_functionsize_t operator()( const db:detail:Node& data ) constsize_t uSeed = 0;size_t uLen = strlen( data.szName );f