AndEngine講座‎ > ‎

第4回:Spriteで画像の表示

作成日:2015/01/11


動画版

Youtube版

AndEngineでAndroid2Dゲーム開発 part4 AndEngineで画像を表示


ニコニコ版

AndEngineでAndroid2Dゲーム開発 part4 AndEngineで画像を表示

前回のあらすじと概要

前回:第3回:ゲームループとシーン

前回はAndEngineがゲームループをどのように処理しているのかを紹介しました。 厳密には違う点も多いのですが、
大雑把でもイメージを持っていたほうが開発がスムーズになると思います。
今回はAndEngineで画像を表示させてみようと思います。 画像と文字が表示できて、タッチ操作が出来て、画面を動かすことが出来たら、
簡単なゲームは作れると思います。 今回はその第一歩です。

正直にいうとAndEngineの画像の扱いは若干面倒くさいです。逆に言うと、その部分は使い方によっていくつかの選択肢があるともいえます。
パフォーマンス等の最適化が必要になった場合、ゲームに応じて調整する余地がある訳ですね。

おおまかな流れ

おおまかな手順は以下のとおりです。

  1. TextureAtlasを用意する
  2. TextureAtlasに画像ファイルを読み込む。
    • この時にTextureRegionを取得する
  3. TextureRegionを用いてSpriteを作成する
  4. SpriteをSceneに配置する。

いきなり英語がたくさん出てきましたが、順を追って説明します。

TextureAtlas

テクスチャアトラスです。単にTextureとも言います。これは読み込んだ画像データを格納しているオブジェクトと考えてください。

イメージとしてはホワイトボードのような感じです。

このTextureAtlasに画像データを貼り付けていくことで、AndEngineで画像データを利用できるようにします。
1つのTextureAtlasには複数の画像データを読み込むもできます。その場合は、画像同士が重ならないように座標を指定して読み込む必要があります。

TextureAtlasには、幅と高さのサイズがあります。このサイズには決まりがあり、2のn乗でなければいけません。
64x64であったり、256x256、1024x1024等です。最大サイズは端末によって異なるようですが詳しいことはわかりません。
2014年12月現在では、2048x2048までなら一般的に利用可能な様子です。 また、正方形でなければならない、という機種もあるようです。
なので、使うときは縦横の長さが2のn乗の正方形を指定するのがよさそうです。

TextureRegion

テクスチャリージョンです。直訳するとテクスチャ領域です。これは、TextureAtlas上の領域をあらわすオブジェクトです。
TextureAtlasに画像データを読み込むことは、ホワイトボードに写真を貼り付けるようなイメージに例えることができます。
写真を貼り付けたとき、ホワイトボード上の四角い領域を、その写真が占めているということになります。
その領域を格納しているのがTextureRegionです。

Sprite

スプライトです。これは前回の講座で出てきたEntityの一種です。
AndEngineでは画面上に現れる全てのオブジェクトはEntityと呼びます。 Spriteは、様々な種類があるEntityの中で、
テクスチャを表示することができるEntityです。
Spriteを作成するにはTextureRegionが必要です。画像データをTextureAtlasに読み込んだときに得られるTextureRegionを使って、
その画像を表示するSpriteを作成します。そして、作ったSpriteをSceneに配置することで、画面に画像を表示させます。


手順

第2回で作ったHelloAndEngineプロジェクトに追加して、Spriteを表示させてみましょう。

画像ファイルの用意

まずは画像を用意します。今回は以下の画像を用意しました。


ファイル名は「face.png」です。縦横のサイズは100px×100pxです。 使えるファイル形式はbmp, jpeg, pngです。
今後はpng形式のものを使っていきます。

このファイルをEclipseのパッケージエクスプローラを使ってプロジェクトにコピーします。

HelloAndEngineプロジェクトの「assets」フォルダに「gfx」というフォルダを作ってそこにコピーします。
「assets」フォルダは、AndEngineでリソースを格納する際の基本となるフォルダーです。 「gfx」はグラフィックスの略で画像ファイルを格納します。
フォルダ分けをしておいたほうが、 音声とかフォントとかを追加する際に混乱しないと思いフォルダを作りました。
なので、特にgfxというフォルダ名にする必要は無いです。


onCreateResourcesの中で画像の用意

ゲームで使うリソースはonCreateResourcesメソッドの中で用意します。 利用する直前に読み込む方法もありますが、
基本的にここで全て読み込んだほうが開発は楽です。 大規模なゲームを作るなら色々考えなければなりませんが。。

まず、画像を読み込んだ際に得られるTextureRegionは、シーンに追加するときに利用できるように、 メンバ変数として用意しておきます。

メンバ変数の用意

private TextureRegion faceTextureRegion

そして、onCreateResouresの中で以下のように書きます。

画像の用意

final BitmapTextureAtlas faceTexture = new BitmapTextureAtlas(
  getTextureManager(), 128, 128);
  faceTextureRegion = BitmapTextureAtlasTextureRegionFactory
  .createFromAsset(faceTexture, this, "gfx/face.png", 0, 0);
  faceTexture.load();

TextureAtlasの一種であるBitmapTextureAtlasを作成します。

  • AndEngineのアクティビティ(正確にはEngine)が保持しているTextureManager
  • 高さ
のパラメーターを与えます。TextureManagerはおまじないとして考えて良いです。

そのあと、BitmapTextureAtlasTextureRegionFactoryというクラスを使って画像を読み込みます。
長いですが、「BitmapTextureAtlas」を使って「TextureRegion」を作る工場と言う意味で、名前が役割を説明しているだけです。
assetsフォルダ内の画像を読み込む、createFromAssetメソッドを使います。

引数は、

  • 読込先のBitmapTextureAtlas
  • ゲームに使うActivity
  • assetsフォルダ以下のファイルの場所
  • BitmapTextureAtlas上のx座標
  • BitmapTextureAtlas上のy座標
    • 画像の読込先の位置になります。この指定した座標が画像の左上になるように画像が読み込まれます。

読み込んだ後にTextureAtlasにloadメソッドを使いましょう。これはFontの時にもありました。忘れると画像が正しく表示されません。

onCreateSceneの中でシーンにSpriteの配置

シーンにSpriteを追加しましょう。 onCreateScene内で以下のような処理を追加します。ただし、Sceneの作成の後です。

Spriteの作成とSceneへの配置

Sprite face = new Sprite(200,100, faceTextureRegion, getVertexBufferObjectManager());
scene.attachChild(face);

まず、faceというSpriteを作っています。引数は

  • x座標
  • y座標
  • 利用するTextureRegion
  • 頂点バッファオブジェクトマネージャー
を指定します。最後のものはHello worldの時同様におまじないとして考えて良いです。

そのあと、シーンにfaceを追加しています。

実行結果

画像のようになります。 Hello worldに続けて追加したので、SpriteがTextに重なって表示されています。


まとめ

画像を表示する手順は

  1. TextureAtlasを用意する
  2. TextureAtlasに画像ファイルを読み込む。
  3. この時にTextureRegionを取得する
  4. TextureRegionを用いてSpriteを作成する
  5. SpriteをSceneに配置する。

です。

ソースコード

今回使ったアクティビティのソースコードは以下のようになります。

MainActivity.java

package com.example.helloandengine;

import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.text.Text;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.font.FontFactory;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.TextureRegion;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import org.andengine.util.color.Color;

public class MainActivity extends SimpleBaseGameActivity {

	private Font font;
	private TextureRegion faceTextureRegion;

	@Override
	public EngineOptions onCreateEngineOptions() {
		Camera camera = new Camera(0, 0, 480, 800);
		return new EngineOptions(true, ScreenOrientation.PORTRAIT_FIXED,
				new RatioResolutionPolicy(480, 800), camera);

	}

	@Override
	protected void onCreateResources() {
		font = FontFactory.create(getFontManager(), getTextureManager(), 256,
				256, 32, true, android.graphics.Color.WHITE);
		font.load();

		// 画像の用意
		final BitmapTextureAtlas faceTexture = new BitmapTextureAtlas(
				getTextureManager(), 128, 128);
		faceTextureRegion = BitmapTextureAtlasTextureRegionFactory
				.createFromAsset(faceTexture, this, "gfx/face.png", 0, 0);
		faceTexture.load();
	}

	@Override
	protected Scene onCreateScene() {
		Scene scene = new Scene();
		scene.setBackground(new Background(Color.CYAN));

		Text text = new Text(100, 100, font, "Hello AndEngine!",
				getVertexBufferObjectManager());
		scene.attachChild(text);

		// 画像の追加
		Sprite face = new Sprite(200, 100, faceTextureRegion,
				getVertexBufferObjectManager());
		scene.attachChild(face);


		return scene;
	}

}

次回予告

次回はようやくゲームを作っていきます。まずは、今までの知識+αの方法でゲーム画面を作ります。

次回:第5回:ゲーム作成開始!

おまけ

おまけです。色々予想される疑問とか、追加情報です。

なぜTextureAtlasを利用するのか?

素朴な疑問です。画像ファイルを指定したらすぐにシーンに追加できるようにしたらいいのに。と思うことだと思います。

確かに、それでも簡単なゲームなら問題ないと思います。 日本で広く知られているAndEngineの本でも、
簡単にSpriteを作れるように、ファイル名を指定して、TextureAtlas、TextureRegionを自動で作成する方法が紹介されています。
そこでは、1つのTextureAtlasに対して1つの画像ファイルを読み込む形になっています。

TextureAtlasを使う理由は、高速化です(他にも理由はあるかもしれませんが、知ってるものでは)。
複数の画像を1つのTextureAtlasにまとめ、そのTextureAtlasから作られる大量のSpriteを高速に描画する。
という方法がAndEngineには用意されています。

SpriteBatchやSpriteGroupという方法です。 使い方によっては、fpsが2~10倍にもなります。
拙作「無限もぐら」でも、1500個のSpriteを遊べる程度の速度で表示するためにSpriteGroupを使っています。


TextureAtlasに画像をまとめる方法

最適化に迫られて複数の画像を1つのTextureAtlasにまとめたい場合以下のような方法があります。
素直な方法から順に紹介したいと思います。紹介だけです。具体的な方法は今後まとめるかもしれません。

1. 自分で配置

複数の画像を含めることが出来るサイズのTextureAtlasを作成して、 BitmapTextureAtlasTextureRegionFactoryに指定する座標を自分で計算する方法です。
今回の例では100x100の画像を用意しました。それとは別に同じサイズの「face2.png」という画像も同時に利用したい場合、以下のようなコードになると思います。

画像を並べて読み込む

//フィールド
TextureRegion faceTextureRegion1
TextureRegion faceTextureRegion2
 
  @Override
  protected void onCreateResources() {
  // 画像の用意
  final BitmapTextureAtlas faceTexture = new BitmapTextureAtlas(
    getTextureManager(), 256, 256);
    faceTextureRegion1 = BitmapTextureAtlasTextureRegionFactory
    .createFromAsset(faceTexture, this, "gfx/face.png", 0, 0);
    faceTextureRegion2 = BitmapTextureAtlasTextureRegionFactory
    .createFromAsset(faceTexture, this, "gfx/face2.png", 101, 0);
    faceTexture.load();
  }

簡単ですが、重ならないように座標を計算していくのも面倒です。画像が増えてくるときついかもしれません。

2. BuildableBitmapTextureAtlasを使う

BitmapTextureAtlasに似ています。先ほど例えたようにホワイトボードのイメージで画像を読み込むのですが、その際の座標指定がいりません。
最初のサイズ指定は必要です。全ての画像を含むことができるように十分な大きさのものを作ります。

必要な画像を読み込み終わった後に、buildというメソッドを使って配置座標を計算させます。

AndEngineExamplesの「AnimatedSpritesExample」で使われています。サンプルでは、今回のTextureRegionではなく、
タイル状の画像を利用するTiledTextureRegionを作成していますが、使い方は同じです。

敷き詰めるアルゴリズムは「BLACKPAWN」という人(組織?)のページで紹介されています(英語)。

Packing Lightmaps http://www.blackpawn.com/texts/lightmaps/default.html

3. TexturePackerを使う

外部ツールと、AndEngineのExtensionが必要ですが、個人的にこれが一番楽です。
TexturePackerは、複数の画像ファイルを指定して、それをまとめた画像ファイルと、レイアウトデータのxmlファイルを出力するGUIツールです。
機能制限版はフリーで使うことが出来ます。

使い方は、いずれページを作って、そこで紹介したいと思います。 調べたら出てくると思いますが。。

AndEngineでの使い方はAndEngineExamplesの「TexturePackerExample」にあります。

テクスチャの色々な設定

BitmapTextureAtlasを生成するときは、色々なオプションが設定可能です。 基本的に省略しても問題ないですが、簡単に触れておきます。 完全なコンストラクタは以下のとおりです。

BitmapTextureAtlasの完全なコンストラクタ

public BitmapTextureAtlas(final TextureManager pTextureManager, final int pWidth, final int pHeight, final BitmapTextureFormat pBitmapTextureFormat, final TextureOptions pTextureOptions, final ITextureAtlasStateListener<IBitmapTextureAtlasSource> pTextureAtlasStateListener)

BitmapTextureFormatはそのテクスチャで色情報、透明度情報の表現に使うビット数を指定するようです。

  • RGBA_8888
  • RGB_565
  • RGBA_4444 に対応しているようです。

TextureOptionsはテクスチャのレンダリング方法を指定します。拡大や回転時に顕著な変化が見られるようです。 AndEngineExamplesの「TextureOptionsExample」で例があります。

ITextureAtlasStateListenerでは、テクスチャの読み込みの成否などのイベント時に行うリスナを設定します。
「ImageFormatsExample」では、対応していないgif形式のファイル読み込み失敗時にToastを表示する方法が書かれています。

Comments