Andengineを使ってみる その1

GeNERACE laboを御覧の皆様、はじめまして。

ピンキリエンジニアのひろゆきです。

先日からAndengineを使っていますが、日本語の紹介があんまりないので書いてみます。

少しでもお役に立てば幸いです。

本家はここ→ http://www.andengine.org/

用意したものはAndroid開発環境があるMac、Eclipse、DLしたAndengine。

プロジェクト作成などはこちらを参考にしてください。

では、簡単ではありますが、サンプルを記載します。

※SampleScene.javaを作成して動かしています

文字を出力する。

// フォントを指定
Texture texture = new BitmapTextureAtlas(activity.getTextureManager(), 480, 800, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
Font font = new Font(activity.getFontManager(), texture, Typeface.DEFAULT_BOLD, 30, true, Color.WHITE);
activity.getTextureManager().loadTexture(texture);
activity.getFontManager().loadFont(font);

// 出力する文字を設定
String str = "hello andengine!!";
Text text = new Text(0, 0, font, str, str.length(), new TextOptions(HorizontalAlign.LEFT), activity.getVertexBufferObjectManager());
attachChild(text);

まずはTextureの生成から使用したいFontを指定します。
それをActivityに設定して、Textにて文字を生成します。

画像を表示する

// 使用する画像名
String fileName = "button.png";

// 使用する画像の設定
BitmapTextureAtlas bta = new BitmapTextureAtlas(activity.getTextureManager(), 100, 100, TextureOptions.BILINEAR_PREMULTIPLYALPHA);
activity.getEngine().getTextureManager().loadTexture(bta);
ITextureRegion btr = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, activity, fileName, 0, 0);
Sprite sprite = new Sprite(0, 0, btr, activity.getVertexBufferObjectManager());
sprite.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
attachChild(sprite);

ボタン画像を表示する

// 使用する画像名
String btnName = "button.png";
String btnPressName = "button_press.png";

// 使用する画像の設定
BuildableBitmapTextureAtlas bta = new BuildableBitmapTextureAtlas(activity.getTextureManager(), 100, 200);
ITextureRegion trBtn = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, activity, btnName);
ITextureRegion trPresseBtn = BitmapTextureAtlasTextureRegionFactory.createFromAsset(bta, activity, btnPressName);
try {
    bta.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(0, 0, 0));
    bta.load();
} catch (TextureAtlasBuilderException e) {</em>
    Debug.e(e);
}

// 通常時と押された時の画像を指定する
ButtonSprite buttonSprite = new ButtonSprite(0, 0, trBtn, trPresseBtn, activity.getVertexBufferObjectManager());
buttonSprite.setBlendFunction(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
attachChild(buttonSprite);

ボタン画像を押した時に処理を行う

public class SampleScene extends Scene implements ButtonSprite.OnClickListener {

ButtonSprite.OnClickListenerを定義します。

// 識別タグ
buttonSprite.setTag(1);
// リスナー
buttonSprite.setOnClickListener(this);
// 認識するエリア登録
registerTouchArea(buttonSprite);

上記で表示したボタン画像に対して、この処理を加えます。

@Override
public void onClick(ButtonSprite pButtonSprite, float pTouchAreaLocalX, float pTouchAreaLocalY) {
    if (pButtonSprite.getTag() == 1) {
        // ボタン画像を大きくする
        buttonSprite.setScale(1.2f);
    }
}

どのボタン画像が押されたかはTagで識別します。

画像を動かす

// Handloerを定義する
public TimerHandler timeHandler = new TimerHandler(1f / 60f, true, new ITimerCallback() {
    @Override
    public void onTimePassed(TimerHandler pTimerHandler) {
        // Y軸に移動させる
        sprite.setPosition(sprite.getX() ,sprite.getY() + 1);
        // 拡大させる
        sprite.setScale(sprite.getScaleX() * 1.01f, sprite.getScaleY() * 1.01f);
        // 透明にする
        sprite.setAlpha(sprite.getAlpha() * 0.99f);
    }
});

これだけでは画像は動きません。
Handlerは登録する必要があります。

registerUpdateHandler(timeHandler);

動きを止めたいときは

unregisterUpdateHandler(timeHandler);

とします。
慣れてないときは、これを忘れて動かない!ということが多々ありました。

Sceneを遷移させる

NextScene scene = new NextScene(activity);
activity.getEngine().setScene(scene);

SceneからActivityを遷移させる

activity.startActivity(new Intent(activity, NextActivity.class));
activity.finish();

現在のActivityを終了して、次のActivityを呼び出します。

他にAndengineの機能は多々ありますが、調べきれていない部分などもありますので、次回に続きたいと思います。

ご覧頂きありがとうございました。

AndEngineでAndroidネイティブのView操作をSceneから行う

こんにちは
Zynga Japanを12月に退職し、GeNERACEという作りたての会社でCTOやってます、村松です。
GeNERACEではAndroidのネイティブゲーム開発にAndEngine(gituhub)を使ってます。

AndEngineはとっても便利ですが、ネイティブのViewと連携させるとより便利です。
今開発中のゲームもネイティブのViewをいくつかのSceneで使っています。
その際にScene1ではいらないけど、Scene2では使いたいとかいう場合ありますよね。
これ、単純にActivityのインスタンスを取得し、対象のViewにsetVisibilityで制御出来るようで実は出来ない。

何故か。

Viewはシングルスレッドモデルです。
AndEngineのSceneはActivityとは別スレッド。
SceneでネイティブのView操作を行うとアプリが強制終了します。

その為、こんな感じに実装してみました。

  • StageScene.java(ゲーム画面のクラス)
  • public class StageScene extends GeneraceAndEngineBaseScene implements ButtonSprite.OnClickListener, IOnSceneTouchListener, IOnAreaTouchListener{
    	private void showResult() {
    		// ネイティブのViewを表示状態にしたいYO!
    		getBaseActivity().visibleNativeViewFromId(R.id.edit_text_result);
    	}
    }
    
  • GeneraceAndEngineBaseScene.java(ゲーム画面の親クラス)
  • public abstract class GeneraceAndEngineBaseScene extends Scene implements ButtonSprite.OnClickListener{
    	private GeneraceAndEngineBaseActivity baseActivity;
    	public GeneraceAndEngineBaseActivity getBaseActivity() {
    		return this.baseActivity;
    	}
    }
    
  • GeneraceAndEngineBaseActivity.java(アクティビティ制御クラス)
  • public abstract class GeneraceAndEngineBaseActivity extends SimpleLayoutGameActivity {
    	Handler goneNativeViewHandler = new Handler();
    	Handler visibleNativeViewHandler = new Handler();
    	Handler invisibleNativeViewHandler = new Handler();
    	public void goneNativeViewFromId(final int id) {
    		new Thread(new Runnable() {
    			public void run() {
    				goneNativeViewHandler.post(new Runnable() {
    					public void run() {
    						findViewById(id).setVisibility(View.GONE);
    					}
    				});
    			}
    		}).start();
    		
    	}
    	
    	public void invisibleNativeViewFromId(final int id) {
    		new Thread(new Runnable() {
    			public void run() {
    				invisibleNativeViewHandler.post(new Runnable() {
    					public void run() {
    						findViewById(id).setVisibility(View.INVISIBLE);
    					}
    				});
    			}
    		}).start();
    		
    	}
    	
    	public void visibleNativeViewFromId(final int id) {
    		new Thread(new Runnable() {
    			public void run() {
    				visibleNativeViewHandler.post(new Runnable() {
    					public void run() {
    						findViewById(id).setVisibility(View.VISIBLE);
    					}
    				});
    			}
    		}).start();
    	}
    }
    
  • activity_main.xml
  • <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    	xmlns:tools="http://schemas.android.com/tools"
    	android:layout_width="match_parent"
    	android:layout_height="match_parent" >
    
    	<org.andengine.opengl.view.RenderSurfaceView
    		android:id="@+id/renderview"
    		android:layout_width="fill_parent"
    		android:layout_height="fill_parent" />
    	<EditText
    		android:id="@+id/edit_text_result"
    		android:gravity="left|top"
    		android:inputType="textMultiLine"
    		android:layout_marginLeft="10dip"
    		android:layout_marginRight="10dip"
    		android:layout_marginTop="300dip"
    		android:visibility="gone"
    		android:layout_width="match_parent"
    		android:layout_height="100dip"/>
    </RelativeLayout>
    

    非同期処理とかで使う実装に似た感じ。
    なんかイマイチ綺麗じゃないなー、俺Handlerあんま好きじゃないんだよなーとか思うけど、もう今日は眠いのでこれで限界。(3:30 AMなう)
    より良い実装が浮かんだら書き換えよう。そうしよう。

    そういえば、AndEngineってZyngaのNicolas Gramlich(facebook)さんが作ってるですよね。
    Zynga Japan辞めてもなんやかんやでZyngaにお世話になることはまだまだありそうです。