libGDX 2D游戲開(kāi)發(fā)之 - 資源管理
原文地址:https://github.com/libgdx/libgdx/wiki/Managing-your-assets.
譯者:重慶好爸爸 game4kids@163.com
謝絕轉(zhuǎn)載
譯者總結(jié) (需要完善)
相關(guān)的類(lèi)
- AssetManager
- AssetLoader
術(shù)語(yǔ)對(duì)照
- Dispose - 處置大磺,釋放
- Asset - 資源
- Loader - 加載器
- TTF - TrueType File 美國(guó)蘋(píng)果公司和微軟公司共同開(kāi)發(fā)的一種電腦輪廓字體(曲線描邊字)類(lèi)型標(biāo)準(zhǔn)
- nitty-gritty parts - 美國(guó)俚語(yǔ)抽碌,一些必不可少的細(xì)節(jié)部分
管理你的資源
為什么要使用AssetManager
AssetManager幫助你加載和管理你的資源亮靴。這是一個(gè)推薦的加載資源的方法掀泳,因?yàn)檫@個(gè)方法有如下諸多優(yōu)點(diǎn):
- 異步完成大多數(shù)資源的加載未辆。所以在資源加載完成前蔽挠,你可以通過(guò)渲染進(jìn)程去顯示一個(gè)loading界面脖咐。==(譯者注:“異步”是指資源的加載可以放在非渲染線程的另外一個(gè)線程中师崎。)==
- 資源是索引計(jì)數(shù)默终。如果資源A和資源B都依賴(lài)于另外一個(gè)資源C,那么在資源A和資源B都被釋放之前犁罩,資源C是不會(huì)釋放的齐蔽。這也說(shuō)明如果多次加載了同一個(gè)資源,實(shí)際上這個(gè)資源在內(nèi)存中是只有1個(gè)實(shí)例的床估。
- 你所有的資源可以放在同一個(gè)地方含滴。
- 允許透明(transparently)的實(shí)現(xiàn)一些功能,比如Caches(見(jiàn)下面的FileHandleResolver)
繼續(xù)把丐巫。
創(chuàng)建一個(gè)AssetManager
創(chuàng)建AssetManager很簡(jiǎn)單
AssetManager manager = new AssetManager();
上面的代碼會(huì)創(chuàng)建一個(gè)標(biāo)準(zhǔn)的AssetManager谈况。代碼執(zhí)行后勺美,libgdx擁有的所有l(wèi)oaders(加載器)都也都創(chuàng)建了。讓我們一起看看這個(gè)加載機(jī)制是如何工作的碑韵。
注意: 不要把AssetManager和其他的資源(比如Texture等)設(shè)置為靜態(tài)變量赡茸,除非你有信心正確的管理他們。例如祝闻,下面的代碼將會(huì)導(dǎo)致問(wèn)題:
public static AssetManager assets = new AssetManager();
這條語(yǔ)句在Andriod上可能會(huì)引發(fā)問(wèn)題占卧。Andriod中的靜態(tài)變量的生命周期和你的APP生命周期可能是不一樣的。(譯者注:關(guān)于靜態(tài)變量這一段不是很理解联喘,你們自行找資料看吧:- 因此屉栓,你的前一個(gè)APP實(shí)例的AssetManager實(shí)例可能被下一個(gè)APP實(shí)例拿去應(yīng)用,然后那些資源其實(shí)都已經(jīng)不可用了耸袜。這樣會(huì)導(dǎo)致黑屏/丟失紋理或者錯(cuò)誤資源的典型問(wèn)題友多。
在Android中,你的Activity的多個(gè)實(shí)例甚至可能被同時(shí)被激活堤框,所以即使你能正確的處理生命周期域滥,你也不一定100%安全。(見(jiàn)Stackflow描述的場(chǎng)景)
加載資源
AssetManager需要知道如何加載特定類(lèi)型的資源蜈抓。這個(gè)功能功過(guò) AssetLoader 來(lái)實(shí)現(xiàn)启绰。AssetLoader有2個(gè)變種:SynchronousAssetLoader(同步資源加載器) 和 AsynchronousAssetLoader(異步資源加載器)。SynchronousAssetLoader在渲染線程中加載所有的資源沟使;AsynchronousAssetLoader在除渲染線程外的另外線程中加載部分資源委可,比如: Pixmap需要一個(gè)Texture,然后在渲染線程中加載OpenGL的依賴(lài)部分腊嗡,但后面需要的資源就可以在其他線程中加載了着倾。(譯者注:原文為 The following resources can be loaded out of the box with the AssetManager as constructed above.)
下面列舉了各種資源的加載器: (譯者注:下面這些加載器都是從同步/異步加載器繼承下來(lái)的)
- Pixmaps: PixmapLoader
- Textures : TextureLoader
- BitmapFonts : BitmapFontLoader
- FreeTypeFonts : FreeTypeFontLoader
- TextureAtlases : TextureAtlasLoader
- Music instances : MusicLoader
- Sound instances : SoundLoader
- Skins : SkinLoader
- Particle Effects : ParticleEffectLoader
- I18NBundles : I18NBundleLoader
- FreeTypeFontGenerator : FreeTypeFontGeneratorLoader
加載特定的的資源也很簡(jiǎn)單,見(jiàn)如下代碼
manager.load("data/mytexture.png", Texture.class);
manager.load("data/myfont.fnt", BitmapFont.class);
manager.load("data/mymusic.ogg", Music.class);
上面的.load()把將要加載的資源放入隊(duì)列燕少。資源將按照.load()方法的調(diào)用順序被依次加載卡者。有的加載器允許你在調(diào)用.load()方法的時(shí)候加入?yún)?shù)。比如說(shuō)客们,我們想在加載texture的時(shí)候指定一個(gè)非默認(rèn)的filter設(shè)置和mipmapping設(shè)置:
TextureParameter param = new TextureParameter();
param.minFilter = TextureFilter.Linear;
param.genMipMaps = true;
manager.load("data/mytexture.png", Texture.class, param);
你可以抽空研究一下上面提到各種loader可用的參數(shù)崇决。
使用AssetHandler加載TTF(TrueType File)
通過(guò)AssetHandler加載TTF需要一點(diǎn)額外的調(diào)整, 因?yàn)樵诩虞dTTF之前,我們需要設(shè)置加載FFT需要的加載器類(lèi)型:
FileHandleResolver resolver = new InternalFileHandleResolver();
manager.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver));
manager.setLoader(BitmapFont.class, ".ttf", new FreetypeFontLoader(resolver));
接下來(lái),我們想要?jiǎng)?chuàng)建一個(gè)FreeTypeFontLoaderParameter底挫, 這個(gè)FreeTypeFontLoaderParameter定義了 1)我們實(shí)際的字體文件 2)我們的字體字號(hào)(size)恒傻。如果你有時(shí)間,你還可以研究下其他的參數(shù)建邓,可以放進(jìn)來(lái)盈厘。
比如說(shuō)我們想創(chuàng)建2種不同的字體: 小一點(diǎn)的sans-serif字體,用作寫(xiě)作的字體涝缝;大一點(diǎn)的serif字體譬重,用作標(biāo)題和其他有趣的東西拒逮。我決定分別使用Arial和Georgia這兩種字體。 以下是我可以使用AssetManager加載它們的方法:
// First, let's define the params and then load our smaller font
FreeTypeFontLoaderParameter mySmallFont = new FreeTypeFontLoaderParameter();
mySmallFont.fontFileName = "arial.ttf";
mySmallFont.fontParameters.size = 10;
manager.load("arial.ttf", BitmapFont.class, mySmallFont);
// Next, let's define the params and then load our bigger font
FreeTypeFontLoaderParameter myBigFont = new FreeTypeFontLoaderParameter();
myBigFont.fontFileName = "georgia.ttf";
myBigFont.fontParameters.size = 20;
manager.load("georgia.ttf", BitmapFont.class, myBigFont);
整齊滩援! 現(xiàn)在我們有兩種不同的字體,mySmallFont和myBigFont玩徊,可以用來(lái)顯示不同的文本租悄。
還沒(méi)有完恩袱,現(xiàn)在字體已經(jīng)".load()"泣棋,但是我們還需要設(shè)置他們:
BitmapFont mySmallFont = manager.get("arial.ttf", BitmapFont.class);
BitmapFont myBigFont = manager.get("georgia.ttf", BitmapFont.class);
截至目前,我們只是把資源放入隊(duì)列畔塔。AssetManager實(shí)際上還沒(méi)有加載任何資源潭辈。為了觸發(fā)加載動(dòng)作,我們需要連續(xù)調(diào)用AssetManager.update()方法澈吨,比如把它放在我們的ApplicationListener.render() 方法中:
public MyAppListener implements ApplicationListener {
public void render() {
if(manager.update()) {
// we are done loading, let's move to another screen!
}
// display loading information
float progress = manager.getProgress()
... left to the reader ...
}
}
只要AssetManager.update()方法還在返回false,你就知道資源加載未完成把敢。要輪詢(xún)具體的加載狀態(tài),您可以使用AssetManager.getProgress()方法谅辣,它返回一個(gè)介于0和1之間的數(shù)字修赞,表示到目前為止加載的資源的百分比。AssetManager中還有其他方法為您提供類(lèi)似的信息桑阶,如AssetManager.getLoadedAssets()或AssetManager.getQueuedAssets()柏副。 你必須調(diào)用AssetManager.update()來(lái)保存加載狀態(tài)。
如果要block并確保所有資產(chǎn)都已加載蚣录,您可以調(diào)用:
manager.finishLoading();
這個(gè)會(huì)block搓扯,直到所有隊(duì)列中的資源完成實(shí)際的加載。Kinda defeats the purpose of asynchronous loading, but sometimes one might need it (e.g., loading the assets needed to display the loading screen itself).
獲取資源
獲取資源也很簡(jiǎn)單
Texture tex = manager.get("data/mytexture.png", Texture.class);
BitmapFont font = manager.get("data/myfont.fnt", BitmapFont.class);
當(dāng)讓我們假定這些資源已經(jīng)被成功加載了包归。如果我們想輪詢(xún)一個(gè)特定的資源是否已經(jīng)成功加載了锨推,我們用下面的方法:
if(manager.isLoaded("data/mytexture.png")) {
// texture is available, let's fetch it and do something interesting
Texture tex = manager.get("data/mytexture.png", Texture.class);
}
處置(釋放)資源
也很簡(jiǎn)單,這里你可以看到AssetManager的威力:
manager.unload("data/myfont.fnt");
如果這個(gè)myfont.fnt是索引到你之前手工加載的一個(gè)Texture公壤,那么這個(gè)texture不會(huì)被銷(xiāo)毀换可!在這種情況下,它是索引計(jì)數(shù)將是2次:1次是來(lái)自bitmap字體的計(jì)數(shù)厦幅,另外1次是來(lái)自它自身沾鳄。只要這個(gè)計(jì)數(shù)不為0,那么這個(gè)texture就不會(huì)被銷(xiāo)毀确憨。
不同通過(guò)手工銷(xiāo)毀AssetManager管理的資源译荞,而是要用AssetManager.upload()去銷(xiāo)毀瓤的。如果你想一次性銷(xiāo)毀所有的資源,那么調(diào)用manager.clear();或者manager.dispose(); 這兩種方法都會(huì)銷(xiāo)毀當(dāng)前所有已經(jīng)加載的資源吞歼,以及銷(xiāo)毀隊(duì)列中還未來(lái)得及完成加載的資源圈膏。AssetManager.dispose()方法會(huì)銷(xiāo)毀AssetManager本身。所有在調(diào)用AssetManager.dispose()后篙骡,就要不能再使用這個(gè)manager了稽坤。
目前基本所有的東西都說(shuō)完了,但是讓我們來(lái)看看另外一些必不可少的細(xì)節(jié)部分糯俗。
問(wèn)題: 我沒(méi)有提供String尿褪,但是AssetManager從來(lái)加載的String資源呢?
每一個(gè)加載器都有一個(gè)指向FileHandleResolver的索引杖玲。這是一個(gè)簡(jiǎn)單的接口淘正,
Every loader has a reference to a FileHandleResolver. That's a simple interface looking like this:
public interface FileHandleResolver {
public FileHandle resolve(String file);
}
默認(rèn)情況下,每個(gè)加載器會(huì)使用一個(gè)InternalFileHandleResolver跪帝。這會(huì)返回一個(gè)FileHandle指向一個(gè)內(nèi)部文件(就像Gdx.files.internal("data/mytexture.png"))。你可以寫(xiě)你自己的resolver!研究一下assets/loaders/resolvers包去看看更多的FileHandleResolver的具體實(shí)現(xiàn)斑唬。一個(gè)例子是Caching系統(tǒng)黎泣,你可以檢查是否有在外部存儲(chǔ)中有一個(gè)新版本已經(jīng)下載,如果它不可用則回退到內(nèi)部存儲(chǔ)抒倚。可能性是無(wú)限多的含蓉。
你可以通過(guò)AssetManager的第二個(gè)構(gòu)造函數(shù)的形式來(lái)設(shè)置將要使用的FileHandleResolver项郊。
AssetManager manager = new AssetManager(new ExternalFileHandleResolver());
這將確保上面列出的所有默認(rèn)加載程序?qū)⑹褂迷摷虞d程序。
編寫(xiě)你自己的加載器
我無(wú)法預(yù)期您要加載哪些其他類(lèi)型的資源着降,所以在某些時(shí)候您可能想要編寫(xiě)自己的加載程序。有兩個(gè)接口叫做SynchronousAssetLoader和AsynchronousAssetLoader可以實(shí)現(xiàn)蓄喇。如果您的資源可以快速加載,請(qǐng)使用SynchronousAssetLoader妆偏;如果您希望展現(xiàn)加載屏幕,則使用AsynchronousAssetLoader楼眷。我建議您的加載器在要基于上面列出的其中一個(gè)裝載機(jī)的代碼上熊尉。MusicLoader是一個(gè)簡(jiǎn)單的SynchronousAssetLoader;PixmapLoader是一個(gè)AsynchronousAssetLoader张吉。BitmapFontLoader是AsynchronousAssetLoader的一個(gè)很好的例子,它在資源可以加載之前需要加載一些依賴(lài)項(xiàng)(在這種情況下肮蛹,指存儲(chǔ)字形Textrue)创南。 你可以做很多事情。
當(dāng)你寫(xiě)完自己的加載器后稿辙,需要告訴AssetManager:
manager.setLoader(MyAssetClass.class, new MyAssetLoader(new InternalFileHandleResolver()));
manager.load("data/myasset.mas", MyAssetClass.class);
從Loading屏幕返回
在Andriod里,你的APP可以paused和resumed. 在這種情況下赋咽,需要重新加載像Texture這樣的托管OpenGL資源吨娜,這可能需要花費(fèi)一些時(shí)間。如果要在resume時(shí)顯示加載屏幕宦赠,則可以在創(chuàng)建AssetManager后執(zhí)行以下操作。
Texture.setAssetManager(manager);
在ApplicationListener.resume()方法中毡琉,您可以切換到加載屏幕阀溶,并再次調(diào)用AssetManager.update()蝴簇,直到所有內(nèi)容恢復(fù)正常虱歪。
如果沒(méi)有像最后一個(gè)代碼片段中所示的那樣設(shè)置AssetManager,那么通常的托管紋理機(jī)制就會(huì)出現(xiàn)笋鄙,所以你不用擔(dān)心任何事情。
這就是大家期待已久的AssetManager文章践美。 good luck!