libGDX 游戲開(kāi)發(fā)之 - 資源管理

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!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末找岖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子兴革,更是在濱河造成了極大的恐慌,老刑警劉巖杂曲,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件擎勘,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡棚饵,警方通過(guò)查閱死者的電腦和手機(jī)朱转,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)怪与,“玉大人,你說(shuō)我怎么就攤上這事分别〈嬉” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵括授,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我荚虚,道長(zhǎng),這世上最難降的妖魔是什么梯澜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任渴析,我火速辦了婚禮,結(jié)果婚禮上俭茧,老公的妹妹穿的比我還像新娘。我一直安慰自己民傻,他們只是感情好胰默,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布牵署。 她就那樣靜靜地躺著,像睡著了一般奴迅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上取具,一...
    開(kāi)封第一講書(shū)人閱讀 51,578評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音产阱,去河邊找鬼块仆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛悔据,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播科汗,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼怖亭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起棺禾,我...
    開(kāi)封第一講書(shū)人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤峭跳,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蛀醉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脊岳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年割捅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帚桩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡莫瞬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出疼邀,到底是詐尸還是另有隱情召锈,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布烟勋,位于F島的核電站,受9級(jí)特大地震影響卵惦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丛塌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赴邻。 院中可真熱鬧,春花似錦姥敛、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)玄糟。三九已至,卻和暖如春阵翎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背郭卫。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工猪狈, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人雇庙。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓疆前,卻偏偏與公主長(zhǎng)得像聘萨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子米辐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容