ゲーム開発日記　～libGDXAPI解説２～

#前回の捕捉
前回から解説しているコードは、少し前のバージョンのlibGDXで自動生成されるものになおり、現在はもっとシンプルになっています。

使用されているクラスなど、以前のものの方が解説しやすそうなので、少し古いサンプルですがこちらで解説していこうと思います。


#今回のコード
```java:MyGdxGame.java
package com.me.mygdxgame;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class MyGdxGame implements ApplicationListener {
	private OrthographicCamera camera;
	private SpriteBatch batch;
	TextureRegion region;
	private Texture texture;
	private Sprite sprite;

	@Override
	public void create() {
		float w = Gdx.graphics.getWidth();
		float h = Gdx.graphics.getHeight();
		 camera = new OrthographicCamera(1, h/w);
		batch = new SpriteBatch();
		texture = new Texture(Gdx.files.internal("data/libgdx.png"));
		texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);

		region = new TextureRegion(texture, 0, 0, 512, 275);

		sprite = new Sprite(region);
		sprite.setSize(0.9f, 0.9f * sprite.getHeight() / sprite.getWidth());
		sprite.setOrigin(sprite.getWidth() / 2, sprite.getHeight() / 2);
		sprite.setPosition(-sprite.getWidth() / 2, -sprite.getHeight() / 2);
		Gdx.app.log("Sprite", sprite.getX() + ", " + sprite.getY());

		camera.position.set(camera.viewportWidth / 2,camera.viewportHeight / 2, 0);
		camera.update();
	}

	@Override
	public void dispose() {
		batch.dispose();
		texture.dispose();
	}

	@Override
	public void render() {
		Gdx.gl.glClearColor(1, 1, 1, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

		batch.setProjectionMatrix(camera.combined);
		batch.begin();
		 batch.draw(region, 0, 0, .9f,
		 .9f * region.getRegionHeight() / region.getRegionWidth());
//		sprite.draw(batch);
		batch.end();
	}

	@Override
	public void resize(int width, int height) {
	}

	@Override
	public void pause() {
	}

	@Override
	public void resume() {
	}
}
```


##Texture,TextureRegion
●Texture
今回はまず最初に、Textureクラスを見て行きましょう。

このクラスは名前の通り、テクスチャを扱うクラスとなっています。

それでは、Textureインスタンスの取得方法ですが、このコードでは以下のようになっています。

```java:
texture = new Texture(Gdx.files.internal("data/libgdx.png"));
```

ここでは、引数としてFileHandleインスタンスを指定しています。
FileHandleクラスは、これまた名前の通りファイルを扱うクラスで、GdxAPIから取得できます。

以前も出てきましたが、今回もGdxが出てきました。
今回は、Gdx.filesで、Filesクラスのメソッドを呼び出しています。
Filesクラスはアプリケーションのアセットファイル、クラスパス、SDカード等のファイルシステムにアクセスできるように設計されています。

上記では、Gdx.files.internal("data/libgdx.png")をしていますが、これは「プロジェクトのassetsフォルダ内のdata/libgdx.pngのFileHandler」を取得しているということです。

ファイルシステムの詳しい説明は[公式Wiki](https://github.com/libgdx/libgdx/wiki/File-handling)に乗っていますのでこちらもご覧下さい。

また、画像のサイズは縦横、それぞれ２のn乗となるようにしてください。256×256とか、1024×2048などです。

OpenGLの仕様上、こういったサイズでないと画像を読み込めず、エラーとなってしまいます。

●TextureRegion
次はTextureRegionです。
フィールドにはありませんが、create()内にあります。

```java:
TextureRegion region = new TextureRegion(texture, 0, 0, 512, 275);
```

このTextureRegionクラスは、Textureでの位置を示します。
上で、画像サイズは縦横２のn乗になるようにと説明しましたが、そうなると以下の様な場合があります。

![Texture説明.png](https://qiita-image-store.s3.amazonaws.com/0/36379/70ee34ac-65fe-1fad-5e75-1c7107f7b770.png)

この様に、サイズが指定されたもの以外使用できないため、このまま画像を使用すると、実際に描画したい部分以外にも余計なスペースを描画してしまうことになります。

余白が出ないように、全ての画像を２のn乗ピッタリにするという方法も取れますが、現実的でないし実用性もありません。

そこでTextureRegionクラスを使用します。
これを使用することで、Texture内のどの部分を描画するかを指定できるようになります。

こんな感じです。

![Texture説明2.png](https://qiita-image-store.s3.amazonaws.com/0/36379/6fe9fa7a-a632-6b23-33bb-43b8e8951cf2.png)

上の画像のように、Texture内での描画した部分をしていできます。
これにより、描画の際に無駄な余白を無くす事ができるようになる他、１つのテクスチャに複数の画像をまとめることで、リソースの削減できる等の利点もあります。

さて、とりあえずこれでアセットファイルから画像を取得することが出来ました。

それでは次に取得した画像を描画する方法を見ていきます。

##SpriteBatch
画像を描画するのに使用するのはSpriteBatchです。

通常、OpenGLで画像を描画するのはかなり面倒くさいのですが、このクラスを使用することでとても簡単に実行することができるようになります。

サンプルコードでは普通にインスタンスを生成しています。
SpriteBatchには他にもコンストラクタはありますが２Dでテクスチャを描画する際には、サンプルコードと同様にデフォルトコンストラクタからインスタンスを生成して大丈夫かと思います。

実際に描画を行っている場所はrender()メソッド内です。
このメソッドは、毎フレーム呼び出される、libGDXのメインループメソッドとなっています。
そのため、このメソッドでモデルの更新や描画処理等を実装していくことになります。

ではSpriteBatchがどのように使用されているか見てみましょう。
render()メソッドのこの部分ですね。

```java:
batch.setProjectionMatrix(camera.combined);
batch.begin();
sprite.draw(batch);
batch.end();
```

最初の行から見ていきます。
これは、SpriteBatchインスタンスに平行投影行列を設定しています。
OrthographicCamera.combinedから取得することができ、簡単に言うと、引数にこれを指定することで前回解説したような描画を行うことができるということです。

次はbatch.begin()です。
このbegin()メソッドは、描画を開始する前に必ず呼び出す必要があります。
ここでOpenGLのテクスチャのバインドを自動でしてくれます。

一行飛ばして、batch.end()メソッドがあります。
これも各Batchの描画が終わったら必ず呼び出します。ここでバインドを解除しないと、違う描画APIの使用ができません。

begin()とend()は必ずセットで呼び出すので忘れないようにしましょう。

それでは、飛ばした行も見てみます。
sprite.draw(batch)です。
ここで実際に描画しているわけですが、今回はSpriteインスタンスがSpriteBatchインスタンスを使用して描画しています。

ここを以下のように書き換えてみます。

```java:
batch.draw(region, 0, 0, .9f,.9f * region.getRegionWidth() / region.getRegionHeight());
```

SpriteBatchインスタンスでTextureRegionを描画しています。
引数として、描画する左下角の座標、描画する幅と高さを指定します。
この例では、(0, 0)に、幅0.9f、高さ0.9×TextureRegionの縦横比に設定しています。

これにして実行してみます。
以下実行結果です。

![スクリーンショット 2014-07-29 14.59.41.png](https://qiita-image-store.s3.amazonaws.com/0/36379/25c11679-db63-125a-9e9a-067d126c40e4.png)

いちおう描画できたはいますが、何故か画像が右上の方に行ってしまっています。

これはCameraの位置の問題です。
OrthographicCameraを生成した際、その位置は(0, 0)に設定されています。
これは、左下の座標ではなく、中心の座標になっています。

つまりこういうことです。

![SpriteBatcher説明.png](https://qiita-image-store.s3.amazonaws.com/0/36379/93532fe0-a5c8-bb3a-f45d-febb4c974980.png)

このため、画像が右上よってしまったのです。
これを修正してみましょう。

以下を追加ます。

```java:
camera.position.set(camera.viewportWidth / 2,camera.viewportHeight / 2, 0);
camera.update();
```

カメラの座標を、(幅/２, 高さ/２)に設定します。
その後のcamera.updata()です。
このメソッドを呼び出さないと、カメラの座標等のパラメータが変化しても、それが反映されません。
なので、このcamera.updata()はrender()メソッド内で呼び出すようにします。

この修正を加えた後の実行結果は以下のものです。

![スクリーンショット 2014-07-29 15.22.05.png](https://qiita-image-store.s3.amazonaws.com/0/36379/180c613e-f0d1-e708-9c3d-08d5bd68be0b.png)

画像が、描画の際に指定したように、左下角(0, 0)の位置に描画されるようになりました。

以上が基本的なテクスチャの描画方法になります。

残すは、Spriteクラスになりますが、だいぶ長くなってしまったので、次回解説していこうと思います。


[libGDX公式サイト](http://libgdx.badlogicgames.com/)
[公式Wiki](https://github.com/libgdx/libgdx/wiki)
[APIリファレンス](http://libgdx.badlogicgames.com/nightlies/docs/api/)

[私が制作したゲーム](https://play.google.com/store/apps/details?id=game.edh)