找回密码
注册

QQ登录

只需一步,快速开始

独立游戏 >
独立动画 >
独立音乐 >

期待您的加入

...

腾讯最新的“爆款”手游,又“抄袭”了?

好不容易盼来了五一假期,终于可以舒舒服服在家宅几天了,玩玩游 ...

期待您的加入呦

...

 L e t ’ s  G o ! L e t ’ s  D o ! L e t ’ s S h i n e !

...

 L e t ’ s  G o ! L e t ’ s  D o ! L e t ’ s S h i n e !

...

从零开始学基于ARKit的Unity3d游戏开发系列 一

前言无可置疑的是,对绝大多数的中小游戏团队来说,目前Unity3d ...

新版Prefab的一些梳理

前言Unity的Prefab相信大家一定很熟悉了,但是用起来那叫个又爱 ...

《我叫MT4》游戏测评——简单地从交互设计的角度分析

1、进去游戏后,会先播放一段动画。这段CG做得很不错,镜头、人 ...

Unity导入模型出现多层UV问题解决

在做项目优化的时候发现,游戏中的模型占用了很高的内存,然后就 ...

Substance Painter入门学习笔记 -8 油桶制作

【前言】 上一篇介绍了油桶的制作,以及到SP中如何烘焙 ...

作者: 九艺网
查看: 102|回复: 0
搜索

more +最新主题Download

more +社区更新Forums

more +随机图赏Gallery

期待您的加入
腾讯最新的“爆款”手游,又“抄袭”了?
期待您的加入呦
 L e t ’ s  G o ! L e t ’ s  D o

more +文章更新News

[转帖]游戏中的资源管理――资源高速缓存

[复制链接]
九艺网 发表于 2017-3-10 17:02:21 | 显示全部楼层 |阅读模式
查看: 102|回复: 0

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册

x
游戏中的资源管理――资源高速缓存
作者:沈明
1.什么是资源高速缓存
    资源高速缓存的原理与其它内存高速缓存的工作原理是相似的。在游戏的状态转换过程中,有些数据是刚才使用过的,那么直接从资源高速缓存中载入即可。例如,RPG游戏中主角从大地图进入一个房间,探索一番后主角退出房间,此时只要直接从缓存中载入大地图数据即可,节省了从硬盘载入数据的时间,要知道从硬盘载入数据是非常慢的。当然,如果你的游戏所使用的数据文件很少,那么你可以在游戏运行过程中把这些数据完全储存在内存中,而不使用资源高速缓存。
2.一个简单的资源高速缓存管理器
    下面我将向你展示一个比较简单的资源高速缓存管理器,源代码来自我上一个游戏,如果你需要知道更多关于资源高速缓存方面的知识,请参考的第八章。
首先,需要一个机制来唯一标识一个资源,我们用下面这个结构来做资源句柄:
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 m_lru;
    //资源标识映射
std::map m_resources;
};
CacheManager:: CacheManager ()
{
m_cacheSize = 0;
m_allocated = 0;
}
CacheManager::~ CacheManager ()
{
while (!m_lru.empty()) Free(); //释放所有管理中的资源
}
void * CacheManager::Load(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::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::iterator it = m_resources.find(resName);
if (it == m_resources.end()) return 0;
return (*it).second;
}
至此,你已经可以在游戏中缓存任何你想缓存的资源了^_^
3. 资源管理进阶
    至此你已经可以在游戏中缓存任何你想缓存的资源了,但是你的任务还没完成,当你请求的资源存在于缓存之外时,那个闪耀的硬盘灯可能就是玩家最感兴趣的东西了。
因此你必须根据不同的游戏类型使用不同的载入方式:
 一次载入所有东西:适用于任何以界面或关卡切换的游戏
 只在关键点载入资源:很多射击游戏都使用这样的设计,如“半条命”
 持续载入:适用于开放型地图的游戏,如“侠盗猎车手”
如果有可能的话,你还可以使用缓存预测机制,当CPU有额外时间的时候可以把未来可能用到的资源载入到资源高速缓存。
    最后,尽管在游戏的资源管理中资源打包不是必须的,但仍然建议大家把资源文件按类型分别打包到单一的文件中,这将为你节省磁盘空间,从而加快游戏的载入速度。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

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