(2)cocos2d for iPhoneからandEngine for androidへの移植(たぶん)過程メモ,タグ、タッチイベント

(2)cocos2d for iPhoneからandEngine for androidへの移植(たぶん)過程メモ,タグ、タッチイベント

前回の(1)cocos2d for iPhoneからandEngine for android移植過程メモはこちら

アンドエンジンよりは主に、box2dのコードを調べていますが、アンドロイドのBOX2Dに限定したサイトは少なく、FLASHだったり、C#, cocos2dだったりしました。box2dが活用された時期は数年前になるようで、その間にサイトが無くなった可能性もあります。

プログラム言語が異なるので、検索したサイトの記事が、AndroidとBox2dの参考にならないかと残念に思っていたら、Flashのコードをよくよく見ると、box2dがC++で記載されているせいか、若干の記載が異なるだけで、ほぼ似たようなコードの記載になっているようでした。他のプログラム言語で書かれているBOX2Dの記載でも、JAVAのアンドロイドにおいても参考になりました。

では、以下より、移植のための比較メモを始めます。途中cocos2dに関する比較のためのコードの記載がない箇所があります。

cocos2dでもAndEngineでもタグを設定できます。これで、スプライトの種別を判別できます。
これによって、判定処理により、あるタグは無視して、あるタグだけタップした時に何か処理を与えることができます。

Andengineチュートリアル、
AndEngine Simple Android Game Tutorial

cocos2dの時と同じ内容のチュートリアルでとても参考になります。

タグの設定

iPhone

Android
スプライトにタグを設定できます。intです。implementクラスに記載します。
Sprite sprite;
sprite.setTag(1);

final DEFAULT_TAG=1;
sprite.getTag()==DEFAULT_TAG;

getChildIndex(i).getTag()として取得できます。
getChildCount()で総数を取得し、For でチェックします。
以下は、参考のコードです。実行チェックしてません、

for(int i; i<getChildCount();i++){
	if( getChildIndex(i).getTag() == DEFAULT_TAG){
   //do something
	}
}

Zオーダーでスプライトの重なりについては、

cocos2dは
[self addChild:sprite z:1];

AndEngineは
Zindexにおいて
sprite.setZIndex(1);
のようにします。

タッチイベントの取得

AndEngineのタッチイベントの記載は複数の方法あるようです。
画面全体に対するイベントと、特定エリアに限定したタッチイベントがあります。
メソッドを記述するだけ、宣言をするだけでは機能しない(設定不足となる)ものもあります。
インプリメントの記述漏れについては、エクリプスがエラーを表示するので、その時に宣言を追加すれば良いと思います。

AndEngine
onAreaTouched(),IOnAreaTouchListener

設定
setOnAreaTouchListener(MainScene.this);//dont forget

定義
boolean onAreaTouched

登録
registerTouchArea(sprite);

onAreaTouchedを使って、タップされたスプライトなどにアクションを与えたいとき、
設定し定義してもどのスライトに対して、そのイベントを対応させるのかは、登録しないとコンパイルエラーや実行時のエラーがなくても正常に動作しません。
タッチ後のアクションを与えるのかがわからないからです。

これはonSceneTouchEvent(Scene, TouchEvent)と異なります。
onSceneTouchEventは、
設定
setOnSceneTouchListener(MainScene.this);
して、定義を書けば動きます。
この点が異なります。

box2d衝突判定ContactListenerを使用

ContactListenerはobjective-c、cocos2dにもありません。box2d固有のものです。

cocos2dのbox2dについてはまだ、cocos2d with box2dのプログラムを進めていないので明確に記載できません。
とりえず、AndEngineの衝突判定は、ContactListenerを使用します。
忘れるといけないので記載します。
宣言についての説明は省略し、実際は他のところに記載しています。
なお、contactListenerにsetTransformを記述しても、BODYは移動しません。(実はここが重要だったりします。)

そのために、registerUpdateHandlerタイマーを利用して、contactListenerにBODYが接触したかのフラグ等を入れてチェックをして、接触したら、移動させるように別途用意する必要があります。(プログラムがエラーにならないので、なぜか悩みましたが、海外の掲示板に書かれていました。)
なお、色を変更するくらいは、実行出来ました。

参考
body.setTransform does not work inside contact listener (andEngine and box2d)

private ContactListener createContactListener()
	{
	    ContactListener contactListener = new ContactListener()
	    {
	        @Override
	        public void beginContact(Contact contact)
	        {
	            final Fixture x1 = contact.getFixtureA();
	            final Fixture x2 = contact.getFixtureB();
	            if (x1.getBody().getUserData()!=null && x2.getBody().getUserData()!=null ){
	            	if ( x1.getBody().getUserData().equals("hiyoko") && x2.getBody().getUserData().equals("another") ||
	            			x1.getBody().getUserData().equals("another") && x2.getBody().getUserData().equals("hiyoko") 
	            			){
		        		Log.d("contact", "contact_hiyoko");
		        		woodRectangle.setColor(1.0f, 0.0f, 0.0f);
		        	}
	            	
	        	}
	        }

	        @Override
	        public void endContact(Contact contact)
	        {
	        	final Fixture x1 = contact.getFixtureA();
	            final Fixture x2 = contact.getFixtureB();
	        	if (x1.getBody().getUserData()!=null && x2.getBody().getUserData()!=null ){
            	if ( x1.getBody().getUserData().equals("hiyoko") && x2.getBody().getUserData().equals("another")||
            		x1.getBody().getUserData().equals("another") && x2.getBody().getUserData().equals("hiyoko") 
            			){
	        		Log.d("contact_end", "end_hiyoko");
	        		
	        		woodRectangle.setColor(0.0f, 1.0f, 0.0f);
	        	}
            	
        	}
	        	
	        }

			@Override
			public void preSolve(Contact contact, Manifold oldManifold) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void postSolve(Contact contact, ContactImpulse impulse) {
				// TODO Auto-generated method stub
				
			}
	    };
	    return contactListener;
	}

(6)A物体とB物体が衝突しないように設定するのは、FixtureDefでmaskBitの設定をする

以下の例は、
BOXはBOXとWALLで衝突し、CIRCLEはCIRCLEとWALLに衝突します。
BOXとCIRCLEは衝突しません。
(short)0はグループのようです。グループに分けて、衝突の分類分けができるみたいです。

なので、登録した物同士が衝突し、登録してないものは衝突しない。透けていくということです。

PhysicsCollisionFilterExample.javaより

/* The categories. */
	public static final short CATEGORYBIT_WALL = 1;
	public static final short CATEGORYBIT_BOX = 2;
	public static final short CATEGORYBIT_CIRCLE = 4;

	/* And what should collide with what. */
	public static final short MASKBITS_WALL = CATEGORYBIT_WALL + CATEGORYBIT_BOX + CATEGORYBIT_CIRCLE;
	public static final short MASKBITS_BOX = CATEGORYBIT_WALL + CATEGORYBIT_BOX; // Missing: CATEGORYBIT_CIRCLE
	public static final short MASKBITS_CIRCLE = CATEGORYBIT_WALL + CATEGORYBIT_CIRCLE; // Missing: CATEGORYBIT_BOX

	public static final FixtureDef WALL_FIXTURE_DEF = PhysicsFactory.createFixtureDef(0, 0.5f, 0.5f, false, CATEGORYBIT_WALL, MASKBITS_WALL, (short)0);
	public static final FixtureDef BOX_FIXTURE_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f, false, CATEGORYBIT_BOX, MASKBITS_BOX, (short)0);
	public static final FixtureDef CIRCLE_FIXTURE_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f, false, CATEGORYBIT_CIRCLE, MASKBITS_CIRCLE, (short)0);

(7)乱数

1.Random r = new Random();
//乱数の取得
int i = r.nextInt(180); //0~180の乱数を取得する

2.int ran = (int)(Math.random()*100)+90;//0-0.9に100倍(90)して+90とする
Math.random()は0以上1未満なので、それに該当する数をかけて、10とか100にします。
この例では、0から99にして90を加算しています。

3.ミリ秒を使用
Calendar cal = Calendar.getInstance(TimeZone.getDefault());
cal.setTime(new Date());
int ms = cal.get(Calendar.MILLISECOND); // 0..999
int ran = (int)(Math.random()*100)+ms/10;//msについては個別に対応することとしてとりあえず10分の1として、深い意味はありません。

効果音、BGM

音の形式については、oggが推奨されているようですが、wav、mp3も再生可能です。
問題なく、再生できました。なお、ファイル名が違っていたり、ファイルが無いと強制的に終了します。エラーが発生してもちょっとみにはどこに問題があるかわからず、ログを追っかけてわかるので、ファイルIO関連は、ログを出力するようにするか、強制終了しないように回避策を入れたほうが良いと思います。(私は余裕が無いので、ログくらいしか出しません)

getBaseActivity()は、個別に作成したactivityです。
MainActivity.javaのonCreateEngineOptions()記載します。
EngineOptions eo=new EngineOptions(true, ScreenOrientation.PORTRAIT_FIXED,
new RatioResolutionPolicy(DEFAULT_CAMERA_WIDTH, DEFAULT_CAMERA_HEIGHT), camera);
eo.getAudioOptions().setNeedsMusic(true);
eo.getAudioOptions().setNeedsSound(true);

SoundFactory.setAssetBasePath("mfx/");
MusicFactory.setAssetBasePath("mfx/");
		
private Sound badSound;
private Music bgmMusic;
 badSound=SoundFactory.createSoundFromAsset(getBaseActivity().getSoundManager(), getBaseActivity(), "se_bad.m4a");
			bgmMusic=MusicFactory.createMusicFromAsset(getBaseActivity().getMusicManager(), getBaseActivity(), "bgm_play_short.mp3");
			bgmMusic.setLooping(true);
  

あとは、それぞれplay()です。

関連記事

「スポンサーリンク」


ツイートツイート
カテゴリー: Androidアンドロイド携帯アプリ タグ: , , , , , , , , , パーマリンク