Answers:
这取决于您的游戏范围。对于大型游戏而言,资产管理者绝对必不可少,对于小型游戏而言,资产管理器则至关重要。
对于较大的标题,您必须管理以下问题:
对于较小的标题来说,这些问题就不那么重要了,像XNA这样的框架中都包含资产管理器-重新发明它几乎没有意义。
如果您发现自己需要资产经理,那么实际上并没有一种万能的解决方案,但是我发现一个哈希图,其键为文件名的哈希*(降低并分隔所有“固定”值)对于我从事的项目效果很好。
通常不建议在应用程序中对文件名进行硬编码,通常最好使用另一种数据格式(例如xml)将文件名描述为“ ID”。
(此处尝试避免“不要使用资产管理器”的讨论,因为我认为这是不合时宜的。)
键/值映射是一种非常有用的方法。
我们有一个ResourceManager实现,可以在其中注册不同资源类型的工厂。
“ getResource”方法使用模板为所需的资源类型找到正确的Factory,并返回特定的ResourceHandle(再次使用该模板返回SpecificResourceHandle)。
资源由ResourceManager重新引用(在ResourceHandle内部),并在不再需要时释放。
我们编写的第一个插件是“ reload(XYZ)”方法,该方法使我们可以从正在运行的引擎外部更改资源,而无需更改任何代码或重新加载游戏。(当艺术家在控制台上工作时,这是必不可少的;)
大多数时候,我们只使用ResourceManager的实例,但是有时我们仅为关卡或地图创建一个新实例。这样,我们可以在levelResourceManager上调用“关闭”,并确保没有任何泄漏。
// very abbreviated!
// this code would never survive our coding guidelines ;)
ResourceManager* pRm = new ResourceManager;
pRm->initialize( );
pRm->registerFactory( new TextureFactory );
// [...]
TextureHandle tex = pRm->getResource<Texture>( "test.otx" ); // in real code we use some macro magic here to use CRCs for filenames
tex->storeToHardware( 0 ); // channel 0
pRm->releaseResource( pRm );
// [...]
pRm->shutdown(); // will log any leaked resource
专用的Manager类几乎永远不是正确的工程工具。如果您只需要一次资产(如背景或地图),则只应请求一次,并在完成后使其正常消失。如果需要缓存特定类型的对象,则应使用工厂,该工厂首先检查缓存,然后加载某些内容,将其放入缓存中,然后返回它-该工厂可以只是访问静态变量的静态函数。 ,而不是一种自己的类型。
史蒂夫·叶格(Steve Yegge)(还有许多其他人)写了一个很好的故事,讲述如何通过单例模式结束无用的管理器类。http://sites.google.com/site/steveyegge2/singleton-considered-stupid
我一直认为一个好的资产管理者应该有几种运作方式。这些模式很可能是遵循通用接口的独立源模块。两种基本的操作模式是:
您需要一个可以从共享数据库中获取所有资产并创建生产数据集的工具。
在我作为开发人员的那几年,我从未见过这样的事情,尽管我只为少数公司工作,所以我的观点并没有真正的代表性。
更新资料
好的,请投反对票。我将对此设计进行扩展。
首先,您实际上不需要工厂类,因为如果您有:
TextureHandle tex = pRm->getResource<Texture>( "test.otx" );
您知道类型,只需执行以下操作:
TextureHandle tex = new TextureHandle ("test.otx");
但是然后,我在上面试图说的是,您无论如何都不会使用显式文件名,要加载的纹理将由使用该纹理的模型指定,因此您实际上不需要人类可读的名称,它可以是32位整数值,这对于CPU来说要容易得多。因此,在TextureHandle的构造函数中,您将需要:
if (texture already loaded)
update texture reference count
else
asset_stream = new AssetStream (resource_id)
asset_stream->ReadBytes
create texture
set texture ref count to 1
AssetStream使用resource_id参数查找数据的位置。它执行此操作的方式取决于您所运行的环境:
在开发中:流在数据库中查找ID(例如,使用SQL)以获取文件名,然后打开文件,该文件可以在本地缓存,或者如果本地文件不存在或从服务器拉出,则从服务器中提取过时了。
在Release中:流在键/值表中查找ID,以获取偏移量/大小到大型打包文件(如Doom的WAD文件)中。
我想为资产做的事情是建立一个总经理。受Doom引擎的启发,集总是包含资产的数据片段,存储在集总文件中,该文件声明了集总的名称,长度,类型(位图,声音,着色器等)和内容类型(文件,另一个集总,内部块文件本身)。在启动时,这些块将输入到二叉树中,但尚未加载。每个图(也是一个块)都有一个依赖关系列表,这些依赖关系只是该图需要工作的块名称。除非已加载这些块,否则它们将在加载地图时加载。此外,加载地图的相邻地图的集总(不是同时加载),而是在引擎出于某种原因空转时加载。这样可以使地图无缝连接,并且没有加载屏幕。
我的方法非常适合开放世界地图,但是基于关卡的游戏无法从该方法获得的无缝性中受益。希望这可以帮助!