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有额外时间的时候可以把未来可能用到的资源载入到资源高速缓存。 最后,尽管在游戏的资源管理中资源打包不是必须的,但仍然建议大家把资源文件按类型分别打包到单一的文件中,这将为你节省磁盘空间,从而加快游戏的载入速度。 |