游戏开发论坛

 找回密码
 立即注册
搜索
查看: 24806|回复: 34

游戏中的资源管理??资源高速缓存

[复制链接]

85

主题

824

帖子

878

积分

高级会员

Rank: 4

积分
878
QQ
发表于 2006-11-23 18:00:00 | 显示全部楼层 |阅读模式
游戏中的资源管理??资源高速缓存

作者:沈明
邮箱:jianguhan@126.com
主页:jianguhan.zzzg.com

1.什么是资源高速缓存
    资源高速缓存的原理与其它内存高速缓存的工作原理是相似的。在游戏的状态转换过程中,有些数据是刚才使用过的,那么直接从资源高速缓存中载入即可。例如,RPG游戏中主角从大地图进入一个房间,探索一番后主角退出房间,此时只要直接从缓存中载入大地图数据即可,节省了从硬盘载入数据的时间,要知道从硬盘载入数据是非常慢的。当然,如果你的游戏所使用的数据文件很少,那么你可以在游戏运行过程中把这些数据完全储存在内存中,而不使用资源高速缓存。

2.一个简单的资源高速缓存管理器
    下面我将向你展示一个比较简单的资源高速缓存管理器,源代码来自我上一个游戏,如果你需要知道更多关于资源高速缓存方面的知识,请参考<<Game Coding Complete>>的第八章。
首先,需要一个机制来唯一标识一个资源,我们用下面这个结构来做资源句柄:
struct ResHandle
{
        ResHandle(std::string &resName, void *buffer, int size)
        {
                m_resName        = resName;
                m_size        = size;
                m_buffer        = buffer;
        }

        ~ResHandle()
        {
                if (m_buffer != 0) delete[] m_buffer;
        }

        std::string   m_resName;        //资源名
        void                        *m_buffer;        //资源句柄所标识的资源
        DWORD                m_size;                //资源所占内存大小
};
好了,现在我们可以从资源名来找出这个资源了,接下来实现这个资源高速缓存管理器:
class CacheManager
{
public:
        CacheManager();
        ~CacheManager();

        //载入资源,resName为资源名,若载入成功size被设为该资源的大小
//注意,管理中的资源不能在管理器外用delete显示的删除它
void*        Load(std::string resName, DWORD *size = 0);
//设置缓存大小,单位MB
        void                SetCacheSize(int sizeMB)        { m_cacheSize = sizeMB * 1024 * 1024; }
        //得到缓存大小,单位MB
        int                GetCacheSize()                        { return m_cacheSize / 1024 /1024; }

private:
        void                Free();                                                //释放lru链表中最后一个资源
        void                *Update(ResHandle *res);                //更新lru链表
        ResHandle        *Find(std::string &resName);        //找出该资源名的资源句柄

private:
        DWORD m_cacheSize;                //缓存大小
        DWORD m_allocated;                //已使用的缓存大小

//lru链表,记录最近被使用过的资源
        std::list<ResHandle*>                                m_lru;       
    //资源标识映射       
        std::map<std::string, ResHandle*>        m_resources;
};

CacheManager:: CacheManager ()
{
        m_cacheSize = 0;
        m_allocated = 0;
}

CacheManager::~ CacheManager ()
{
                while (!m_lru.empty()) Free();        //释放所有管理中的资源
}

void * CacheManager:oad(std::string resName, DWORD *size)
{
        ResHandle *handle = Find(resName);        //查找该资源是否在缓存中

        if (handle != 0) //如果找到该资源句柄,则返回该资源并更新lru链表
        {
                if (size != 0) *size = handle->m_size;
                return Update(handle);
        }
        else
        {
                //先检测资源大小
                DWORD _size = 资源大小;

                //是否有足够空间?
                while (_size > (m_cacheSize - m_allocated))
                {
                        if (m_lru.empty()) break;
                        Free();
                }
                m_allocated += _size;

                buffer = new char[_size];
//在这里用任何你能想到的办法载入资源文件到buffer
                …
                …

//记录当前资源
                ResHandle *handle = new ResHandle(resName, buffer, _size);
                m_lru.push_front(handle);
                m_resources[resName] = handle;
               
                if (size != 0) *size = _size;
                return buffer;
        }

        return 0;
}

void CacheManager::Free()
{
        std::list<ResHandle*>::iterator gonner = m_lru.end();
        gonner--;
        ResHandle *handle = *gonner;
        m_lru.pop_back();
        m_resources.erase(handle->m_resName);
        m_allocated -= handle->m_size;
        delete handle;
}

void * CacheManager::Update(ResHandle *res)
{
        m_lru.remove(res);
        m_lru.push_front(res);
        m_size = res->m_size;
        return res->m_buffer;
}

ResHandle * CacheManager::Find(std::string &resName)
{
        std::map<std::string, ResHandle*>::iterator it = m_resources.find(resName);
        if (it == m_resources.end()) return 0;
        return (*it).second;
}

至此,你已经可以在游戏中缓存任何你想缓存的资源了^_^

3. 资源管理进阶
    至此你已经可以在游戏中缓存任何你想缓存的资源了,但是你的任务还没完成,当你请求的资源存在于缓存之外时,那个闪耀的硬盘灯可能就是玩家最感兴趣的东西了。
因此你必须根据不同的游戏类型使用不同的载入方式:
        一次载入所有东西:适用于任何以界面或关卡切换的游戏
        只在关键点载入资源:很多射击游戏都使用这样的设计,如“半条命”
        持续载入:适用于开放型地图的游戏,如“侠盗猎车手”
如果有可能的话,你还可以使用缓存预测机制,当CPU有额外时间的时候可以把未来可能用到的资源载入到资源高速缓存。
    最后,尽管在游戏的资源管理中资源打包不是必须的,但仍然建议大家把资源文件按类型分别打包到单一的文件中,这将为你节省磁盘空间,从而加快游戏的载入速度。


ps.
潜水潜得太久了,
上来冒个泡^_^

sf_20061123175947.doc

45.5 KB, 下载次数:

36

主题

1047

帖子

1147

积分

金牌会员

Rank: 6Rank: 6

积分
1147
发表于 2006-11-24 11:06:00 | 显示全部楼层

Re:游戏中的资源管理??资源高速缓存

请楼主与我联系。MSN:congyuecy_soft@msn.com QQ:56203523(我已加你)

8

主题

716

帖子

716

积分

高级会员

Rank: 4

积分
716
发表于 2006-11-24 12:33:00 | 显示全部楼层

Re:游戏中的资源管理??资源高速缓存

这只是最基本的stl应用而已
更多关于资源调度的处理并没有涉及

35

主题

370

帖子

376

积分

中级会员

Rank: 3Rank: 3

积分
376
发表于 2006-11-24 21:11:00 | 显示全部楼层

Re:游戏中的资源管理??资源高速缓存

怎样来提高CPU高速缓存命中率呢~?(在高性能要求的地方很重要)

35

主题

370

帖子

376

积分

中级会员

Rank: 3Rank: 3

积分
376
发表于 2006-11-24 22:17:00 | 显示全部楼层

Re:游戏中的资源管理??资源高速缓存

感谢楼主的奉献.下面是我提出的一些讨论, 一图共同进步
组织线形代码,这段改成这个好点吧,意思简单点(符合逻辑执行顺序, 减少一次判断)
while (_size > (m_cacheSize - m_allocated))
{
if (m_lru.empty()) break;
Free();
}
---------------------------------改成下面------------------------------------------------------
while (_size > (m_cacheSize - m_allocated))
{
Free();
if (m_lru.empty()) break;
}
==================================================
下面的跌带器自减运算可以不要吧,要也用前缀自减~
void CacheManager::Free()
{
std::list<ResHandle*>::iterator gonner = m_lru.end();
gonner--;
ResHandle *handle = *gonner;
m_lru.pop_back();
m_resources.erase(handle->m_resName);
m_allocated -= handle->m_size;
delete handle;
}

35

主题

370

帖子

376

积分

中级会员

Rank: 3Rank: 3

积分
376
发表于 2006-11-24 22:33:00 | 显示全部楼层

Re:游戏中的资源管理??资源高速缓存

下面的m_size =..中的m_size是那里来的?..........

void * CacheManager::Update(ResHandle *res)
{
m_lru.remove(res);
m_lru.push_front(res);
m_size = res->m_size;
return res->m_buffer;
}

85

主题

824

帖子

878

积分

高级会员

Rank: 4

积分
878
QQ
 楼主| 发表于 2006-11-25 00:14:00 | 显示全部楼层

Re:游戏中的资源管理??资源高速缓存

//先检测资源大小
DWORD _size = 资源大小;
...
...
//记录当前资源
ResHandle *handle = new ResHandle(resName, buffer, _size);
m_size记录的就是这里的_size
======================= 华丽的分割线 =========================
while (_size > (m_cacheSize - m_allocated))
{
if (m_lru.empty()) break;
Free();
}
这段如果把Free()放到上面,
如果队列为空而要载入的资源大小又大于设定的缓存大小时,
执行m_resources.erase(handle->m_resName);程序会挂掉的,
至于那个迭代器的确可以不用自减的,
这里疏忽了-_-
======================= 华丽的分割线 =========================
感谢smile636的热心回复!
对于游戏中资源管理这块似乎大家讨论还是相对较少的,
发此文就当是抛砖引玉吧,
希望大家多多指教^_^

59

主题

1104

帖子

1199

积分

金牌会员

Rank: 6Rank: 6

积分
1199
发表于 2006-11-25 12:41:00 | 显示全部楼层

Re:游戏中的资源管理??资源高速缓存

....pc上要做的资源管理想想还真是少,windows的虚拟内存帮你管理了很多东西.
现在做console上的应用,资源管理问题上升到让最让我头疼的问题.

35

主题

370

帖子

376

积分

中级会员

Rank: 3Rank: 3

积分
376
发表于 2006-11-25 14:36:00 | 显示全部楼层

Re:游戏中的资源管理??资源高速缓存

我也是想操作系统自己的内存分配在这里会帮些忙,但是不确定能帮多少~

呵呵楼主谦虚了,你的代码其他地方写的很好, 当需要用之际写代码没有那么多时间考虑周全

0

主题

54

帖子

54

积分

注册会员

Rank: 2

积分
54
发表于 2006-11-28 11:41:00 | 显示全部楼层

Re: 游戏中的资源管理??资源高速缓存

为什么那个跌代器的不要自减(gonner--;)?
那个end()指的是最后一个位置后面的指针。你直接使用gonner = end();取的是最后一个元素后面一个位置。实际应该是一个未知的元素。你的*gonner将得到一个什么值?
敬请指教。。。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-25 11:49

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表