AndEngine講座‎ > ‎

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

作成日:2015/01/16


動画版

Youtube版

ニコニコ版

AndEngineでAndroid2Dゲーム開発 part5 ゲーム作成開始! - ニコニコ動画

前回のあらすじ

前回:第4回:Spriteで画像の表示

概要

今回からゲームを作っていきます。ゲームを作りながら、色んなAndEngineの要素を紹介していこうと思います。

作るゲームは 「数字が書かれたパネルを、数字の順番にタッチするゲーム」です。 周辺視野などを鍛える脳トレですね。

今回はまずゲーム画面の構成を作っていこうと思います。

今後の方針

今後はこの講座ではいよいよゲーム作成に入っていきます。 それに伴い、このページは、動画内で作成した時点までのソースコードと、
要点の説明を中心に掲載します。 動画の内容をそのまま文字起こしするようなページを作ると、各作業の時点でのソースコードを掲載しなければならなくなり、
見るほうも大変なことになるだろう、と思ったからです。

なので、一つ一つの作業手順を見たい場合は動画をご覧いただければ幸いです。

やること

  • プロジェクトの作成
  • リソースマネージャーの作成
  • シーンの作成
  • シーンに文字と画像の配置

プロジェクトの作成

ハローワールドと同じ感じでプロジェクトを作ります。

  • アプリケーション名:ゆっくりタッチナンバー
  • プロジェクト名:YukkuriTouchNumber
  • パッケージ名:com.example.yukkuritouchnumber

ResourceManagerクラスの作成

リソースや、AndEngineのアクティビティが持っている様々なオブジェクトに簡単にアクセスするためのクラスを作ります。
例えば、BaseGameActivityが持っているVertexBufferObjectManagerや、Engineなどです。

webで調べると、シングルトンで実装されていたりしますが、説明できないので簡単な仕組みのものを作ります。
ResourceManagerが、必要なオブジェクトをpublicなフィールドとして持っている、という簡単なものです。

オブジェクト指向の考え方では、publicなフィールドは良くない実装なのですが、大規模な開発を整然と行うためのオブジェクト指向なので、
個人の小規模な開発ではおそらく問題ないだろうと思います。

今回の内容では、用意するリソースは、Fontとパネル用のTextureRegionです。
FontはHello worldのときに、TextureRegionはSpriteの説明のときに用意する手順を紹介したので、 特に説明はしません。

GameSceneの作成

Hello worldではアクティビティの中でシーンを作っていましたが、今回からは個々のシーンを別々のクラスで作っていきます。 シーンの中で、シーンを組み立てる処理を書いていきます。

今回は、タッチするパネルと、次にタッチする番号のナビゲーションのテキスト、経過時間を表示するテキストを表示します。
テキストはダミーで、今回の時点ではまだ、その機能は実装しません。

GameSceneのレイアウト

残念ながらAndEngineではシーンのレイアウトをGUIで組み立てるツールはありません。
(Cocos Builderというツールを使う拡張があるらしいですが、Macでしか使えないらしいので試していません)

ですので、各Entityの座標は計算して求める必要があります。 今回は簡単な(そして雑な)設計図を用意しました。


各座標を求める手順は以下のような感じでした。

  1. 画面の幅は480、高さは720
  2. 縦横80の正方形のパネルを25枚隙間無く埋める
  3. パネル部分の左右の余白は40になる
  4. 上下の余白も左右にあわせて40にする
  5. 一番左上のパネルの(左上の)座標はx=40, y=280になる

GameSceneの組み立て

テキスト

画面上の、次の番号と時間を表示するテキストは、特に難しいことはありません。計算した座標にTextを作成してシーンにattachChildを行っているだけです。

パネル

パネルに関してはfor文を使った繰り返し処理でパネルのSpriteを作成して配置しています。
xPosIndexとyPosIndexは、パネルが左から、上から何番目かを0から4の値であらわしています。 繰り返し変数のiを5で割った商と余りを利用しています。

xPosIndexとyPosIndexに、80を掛けて左上の座標(40, 280)に加えて各パネルの座標を計算しています。

パネルのテキスト(大事)

パネルに表示するテキストは、シーンに対するattachChildではなくパネルのSpriteに対してattachChildを行って追加しています。
attachChildはシーンだけでなくEntityに対しても使えます。これを使ってEntity間に親子関係を作ってグループ化することが出来ます。

つまり今までは

シーン
├画像
├画像
├画像
└画像

何も考えずに文字をおくと

シーン
├画像
├画像
├画像
├画像
├テキスト
├テキスト
├テキスト
└テキスト

親子関係を持たせると

シーン
├画像
│└テキスト
├画像
│└テキスト
├画像
│└テキスト
└画像
└テキスト

ということになるわけです。

このとき、子のEntityの座標は親のEntityの座標が基準になります。 つまり、パネルにテキストをattachChildするとき、
テキストの座標をx=0, y=0にすると、親Entityであるパネルの左上を基準とした座標として解釈され、テキストはパネルの左上に配置されます。

この親子関係をうまく使うと、レイアウト構成の効率や、アニメーション作成の表現がかなり変わってきます。ぜひ使いこなしてください。

(今までのパネルや、他のテキストの座標の基準となる親は、Sceneだったわけですね)

また、パネルの文字が、パネルの中心に来るように座標の調整も行っています。

実行結果

今回の内容を実行すると以下のようになります。


今回の内容終了時点でのプロジェクト内容


作成したクラス

  • MainActivity
    • アプリのメインのアクティビティ
  • ResourceManager
    • リソースやアクティビティが持っているオブジェクトに簡単にアクセスする為のクラス
  • GameScene
    • ゲーム画面のシーン

その他の追加したファイル

  • panel.png
    • asset/gfxフォルダに追加。タッチするパネル用の画像

ソースはこんな感じです。

MainActivity.java

package com.example.yukkuritouchnumber;

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.ui.activity.SimpleBaseGameActivity;

public class MainActivity extends SimpleBaseGameActivity {

	ResourceManager resourceManager;
	GameScene gameScene;

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

	@Override
	protected void onCreateResources() {
		resourceManager = new ResourceManager(this);
		resourceManager.loadResources();

	}

	@Override
	protected Scene onCreateScene() {
		gameScene = new GameScene(resourceManager);
		return gameScene;
	}

}

ResourceManager.java

package com.example.yukkuritouchnumber;

import org.andengine.engine.Engine;
import org.andengine.engine.camera.Camera;
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.opengl.vbo.VertexBufferObjectManager;
import org.andengine.ui.activity.BaseGameActivity;

import android.graphics.Color;


public class ResourceManager {

	public BaseGameActivity activity;
	public Engine engine;
	public Camera camera;
	public VertexBufferObjectManager vbom;

	// テキスト用
	public Font gameFont;

	// パネル用
	public TextureRegion panelRegion;
	public Font panelFont;

	public ResourceManager(BaseGameActivity activity) {
		this.activity = activity;
		this.engine = activity.getEngine();
		this.camera = engine.getCamera();
		this.vbom = activity.getVertexBufferObjectManager();
	}

	// リソースの読み込みを行う
	public void loadResources() {
		// フォントの読み込み
		//ColorはAndroidのもの!
		gameFont = FontFactory
				.create(activity.getFontManager(),
						activity.getTextureManager(), 256, 256, 32, true,
						Color.rgb(255, 128, 0));
		gameFont.load();

		panelFont = FontFactory
				.create(activity.getFontManager(),
						activity.getTextureManager(), 256, 256, 64, true,
						Color.rgb(255, 128, 0));
		panelFont.load();

		// パネル画像の読み込み
		BitmapTextureAtlas panelTexture = new BitmapTextureAtlas(
				activity.getTextureManager(), 128, 128);
		panelRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(
				panelTexture, activity, "gfx/panel.png", 0, 0);
		panelTexture.load();

	}

}

GameScene.java

package com.example.yukkuritouchnumber;

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.util.color.Color;

public class GameScene extends Scene {

	ResourceManager resourceManager;

	public GameScene(ResourceManager resourceManager) {
		super();
		this.resourceManager = resourceManager;

		createScene();
	}

	private void createScene() {
		setBackground(new Background(Color.WHITE));

		// 次にタッチする番号を表示
		Text nextText = new Text(40, 40, resourceManager.gameFont, "Next XXX",
				"Next XXX".length(), resourceManager.vbom);
		attachChild(nextText);

		// 現在時間を表示
		Text timeText = new Text(0, 40, resourceManager.gameFont,
				"Time XX:XX.XX", "Time XX:XX.XX".length(), resourceManager.vbom);
		// テキストの右端が画面の右端から40px離れているようにする
		timeText.setX(resourceManager.camera.getWidth() - 40
				- timeText.getWidth());
		attachChild(timeText);

		// パネルを25個配置する

		for (int i = 0; i < 25; i++) {
			int xPosIndex = i % 5;
			int yPosIndex = i / 5;

			float x = 40 + 80 * xPosIndex;
			float y = 280 + 80 * yPosIndex;

			//パネルの作成
			Sprite panel = new Sprite(x, y, resourceManager.panelRegion,
					resourceManager.vbom);
			//パネルに番号の追加
			int panelNumber = i+1;
			Text text = new Text(0, 0, resourceManager.panelFont, String.valueOf(panelNumber), resourceManager.vbom);
			//文字の座標をパネルの中心に合わせる
			float textX = (panel.getWidth() - text.getWidth())/2;
			float textY = (panel.getHeight() - text.getHeight())/2;
			text.setPosition(textX, textY);
			//パネルにテキストを追加する
			panel.attachChild(text);
			attachChild(panel);

		}

	}

}

次回予告

次回はパネルをタッチしたときの処理を追加します。

次回:第6回:AndEngineでタッチ入力

Comments