libGDXのテクスチャをdisposeするためだけにフィールド変数作るのめんどくさいので、管理クラスあってもいいんじゃないかなあ、という話
追記2(2015-06-18 14:47)
AssetManager
を使うと、本稿の問題は解決できました!僕が管理クラスの存在を知らなかっただけでした。
調べたのでサンプルコードを載せておきます。
public class MyGdxGame extends ApplicationAdapter { // 読み込むファイルのパス private static String FILE_MYFILE = "myfile.png"; private AssetManager am = new AssetManager(); private SpriteBatch batch; private Animation anim; private float time = 0.f; @Override public void create() { batch = new SpriteBatch(); // 読み込ませる am.load(FILE_MYFILE, Texture.class); // 非同期で読込み中であるため、読込みが全て終わるまで待つ am.finishLoading(); // 読み込んだテクスチャを取得 Texture texture = am.get(FILE_MYFILE, Texture.class); TextureRegion[][] split = TextureRegion.split(texture, 64, 64); anim = new Animation(0.05f, split[0]); } @Override public void render() { Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); time += Gdx.graphics.getDeltaTime(); batch.begin(); batch.draw(anim.getKeyFrame(time), 10, 10); batch.end(); } @Override public void dispose() { am.dispose(); // 破棄 } }
- 参考元
AssetManager
を使うと、テクスチャの読み込みから破棄までを管理してくれるようです。
さらに、読み込みを非同期で行う仕組みがあり、テクスチャの読み込みに時間がかかる場合にも使えそうな感じです。
どうやってAssetManager#dispose()
時に各クラスのdispose()
メソッド呼んでるのかなと思ってソース見ると、Disposable
インターフェースを継承してる場合はdispose()
メソッド呼ぶみたいな処理になってました。なるほど。
ついでに会社ブログの実装の方も修正しておこう…
追記(2015-06-17 14:24)
@esperia09 イマイチよくわかってなくて申し訳ないのですが、 AssetManager では解決しないですかね?
— Junji Takakura (@snakeman) June 17, 2015
AssetsManager知らなかった。。標準であるもんですね!まだちょっと使ってみてはいないんですが、僕の欲しいもの+αっぽいです。 使ったら追記します!
本題
使えるかどうか分かんないんですが。
libGDXで遊んでて思ってたんですけど、Texture
とかBitmapFont
とかって、newして他のクラス渡したり、TextureRegion
へ分割したりした後、最後にdispose(破棄)するためだけにフィールド変数に持ってる場合ってわりとある気がしてるんですね。
例えばこんな感じ。
public class MyGdxGame extends ApplicationAdapter { private Texture texture; // disposeのためだけに持ってる private SpriteBatch batch; private Animation anim; private float time = 0.f; @Override public void create() { batch = new SpriteBatch(); texture = new Texture(Gdx.files.internal("myfile.png")); // 読み込み TextureRegion[][] split = TextureRegion.split(texture, 64, 64); anim = new Animation(0.05f, split[0]); } @Override public void render() { Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); time += Gdx.graphics.getDeltaTime(); batch.begin(); batch.draw(anim.getKeyFrame(time), 10, 10); batch.end(); } @Override public void dispose() { texture.dispose(); // 破棄 } }
そうすると、dispose()
呼ぶためだけに、Textureインスタンスをフィールド変数に保持しておかなきゃならない。だったら、それらをまとめて配列みたいなので管理させておいて、disposeするべきタイミングで一気にdispose、ってのもありなんじゃないのかなあと思ったりしたのです。
実装してみる
例えば、こんなクラスを作っておいて。
package com.esperia09.libgdx.utils; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Disposable; public class DisposeRegister implements Disposable { private final Array<Disposable> disposables = new Array<Disposable>(); public <T extends Disposable> T reg(T obj) { disposables.add(obj); return obj; } @Override public void dispose() { for (Disposable d : disposables) { d.dispose(); } disposables.clear(); } }
そして、上記クラスをこう使います。
public class MyGdxGame2 extends ApplicationAdapter { private DisposeRegister dr; // 追加 private SpriteBatch batch; private Animation anim; private float time = 0.f; @Override public void create() { batch = new SpriteBatch(); dr = new DisposeRegister(); // 追加 Texture texture = dr.reg(new Texture(Gdx.files.internal("myfile.png"))); // 変更 TextureRegion[][] split = TextureRegion.split(texture, 64, 64); anim = new Animation(0.05f, split[0]); } @Override public void render() { Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); time += Gdx.graphics.getDeltaTime(); batch.begin(); batch.draw(anim.getKeyFrame(time), 10, 10); batch.end(); } @Override public void dispose() { dr.dispose(); // 変更 } }
こうすると、new Texture(...)
をdr.reg(new Texture(...))
みたいに囲むだけで、配列に登録し、任意の箇所で一気にdispose
できます。上記ではTexture一つだけですが、複数になると結構コード量変わってくると思います。
こんな感じで、disposeさせるためにインスタンス管理するのってありなんじゃないかなあと思っている次第です。
一抹の不安
ただ、これがベストなんだったら、標準で用意されてたり、他でもこういうの普通にされてるんじゃないかなと思ったりはします。なので、僕がありかなと思ってるだけで、実はタブーだったり、Textureの管理の仕方がヘタクソだったりするのかなあとも思ってます。ちなみにQiitaに投稿しなかったのはこの辺りが理由。
シンプルなコード書くの難しいですね。