タグ別アーカイブ: andengine

(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 でチェックします。
以下は、参考のコードです。実行チェックしてません、
[c]
for(int i; i<getChildCount();i++){
if( getChildIndex(i).getTag() == DEFAULT_TAG){
//do something
}
}
[/c]

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)

[c]
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;
}
[/c]

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

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

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

PhysicsCollisionFilterExample.javaより

[c]
/* 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);
[/c]

(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);

[c]
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);
[/c]
あとは、それぞれplay()です。

(1)cocos2d for iPhoneからandEngine for androidへの移植(たぶん)過程メモ,box2d

(1)cocos2d for iPhoneからandEngine for androidへの移植(たぶん)過程メモ,box2d

過去の移植記事 

cocos2d for iPhone をcocos2d-xに移植する過程の記録メモまとめ、Androidクロスプラットフォーム化へ 、(1)〜(6)分

andEngineを選んだ理由

アイフォンでゲームを開発するなら、cocos2d for iPhone、cocos2d-x、unityが有名です。他にもフレームワークはあると思いますが私は知りません。
cocos2d for iPhoneはobjective-c、cocos2d-xはc++でどちらもXCODEです。unityは3Dオブジェクトモデル主体で、c#, javascriptを使用し、ビジュアル的にオブジェクトを配置します。その配置したオブジェクトに対して命令、処理を与えるわけです。unityはどことなくAdobe Flashに似ています。比較的操作しやすい環境です。

 cocos2d for iPhone、cocos2d-xに関する記事はこちら

 Unityに関する記事はこちら

 Blenderに関する記事はこちら

クロスプラットフォーム対応としてcocos2d-xかUnityで開発し、ひとつのコードでアイフォンとアンドロイド向けスマートフォンに対応することができます。
 cocos2d-xとUnityはほぼクロスプラットフォームに対応しているので、アイフォンとアンドロイド用のアプリを生成できます。
多少の調整は必要となるかもしれませんが。

 アンドロイド向けアプリ開発のフレームワークとしてandEngineがあります。他にもあるようですが、日本語のサイトをあまり見かけませんので、andEngine が主流なのかと思っています。
coronaSDK(Lua言語)というのもありました。無料から会社の規模に応じて料金を支払うようです。言語がちょっと特殊なので今回は除外です。

私の場合今回は、andEngineを使用することにしました。
 理由は、前回のアプリ開発がアンドロイドアプリだったので、このままアンドロイドアプリの開発に慣れておきたいからです。
他の理由として、クロスプラットフォームは、その開発環境がOSや再生環境(スマートフォン)のバージョンアップに即座に対応できないこと、いずれ開発会社か開発者が、クロスプラットフォーム環境の開発をやめてしまうのではないかという個人的な危惧から、純粋な開発環境で開発したほうが後々得をするのではないかと考えたからです。
 例えば、WindowsとMacの両方で動作可能としたクロスプラットフォームがかつてありましたが、結局、それぞれのOSのための設定、調整が必要で個別の開発を進めたほうが後々のデバッグ等で開発がスムーズに進み、逆にクロスプラットフォームとして開発するほうがデメリットが大きかったりしました。
 しかも、そのソフトのバージョンアップがなくなるとまた他の開発ソフトに切り替える必要があったりと、メリットが有るのは最初だけだったように思えます。それでも、最初のうち、ソフトの内容が小規模のうちは非常に有効なソフトでした。

もちろんすべての例に当てはまることはないと思います。andEngineがなくなってしまうこともありますので、他の環境も徐々に覚えていきたいと思います。

とりあえず、AndEngineを利用して、アイフォンで開発したゲームをアンドロイドに移植するとどのような違いがあるのかをメモしていきたいと思います。

アイフォンアプリとして作成したミニゲーム「ひよこレスキュー」を多少改善して、アンドロイドアプリとして開発します。
こちらでダウンロードできます。https://itunes.apple.com/jp/app/hiyokoresukyu/id578574439?mt=8(iTunesに移動します)
他のアプリについてはこちら

参考図書:AndEngineでつくるAndroid 2Dゲーム , 立花 翔 (著)
実際に公開しているアプリについて解説されています。著者についてはあまり気にせず日本を選びましたが、アイフォンアプリの開発本を書いている人でもありました。アイフォンアプリとアンドロイドアプリで100本以上も開発したそうです。
ゲーム自体が、ミニゲームでほんの数分程度しか遊べないようなゲームですが、個人でアプリ開発をするのに参考になる内容です。

AndEngineには物理演算エンジンも利用できます。物理エンジンBox2Dを使いたいときは別途ダウンロードして、インポートする必要があります。
box2dはcocosでも利用できます。私はcocos2d for iPhoneのbox2dはまだ、勉強していないので、今後cocos2d for iPhoneのbox2dを利用したアプリも作ってみたいと思います。

・開発環境
MacOSX10.8.5、Eclipse、ネクサス7(2013)、PowerBookPro(2012)、外部モニター使用

<比較内容>
・画像の表示
・BOX2Dの利用
・その他情報BOX2D、R.U.B.E 、cocos2d for iPhone with box2dチュートリアル
・スマートフォンアプリの市場について

画像の表示

cocos2d for iPhone

andEngine
画像サイズよりも大きめの領域を確保してから画像から読み込みます。(自動で領域を確保してくれません。)
どのフォルダassets/gfxにあるのかも記入する必要があります。

[c]
Scene scene;
protected static final int CAMERA_WIDTH=800;
protected static final int CAMERA_HEIGHT=480;
BitmapTextureAtlas playerTexture;
ITextureRegion playerTextureRegion;
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
playerTexture=new BitmapTextureAtlas(getTextureManager(), 64, 64);//画像サイズ
playerTextureRegion=BitmapTextureAtlasTextureRegionFactory.createFromAsset(playerTexture,
this , "player.png",0,0);
playerTexture.load();
Sprite sPlayer =new Sprite(CAMERA_WIDTH/2, CAMERA_HEIGHT/2, playerTextureRegion, this.mEngine.getVertexBufferObjectManager());
sPlayer.setRotation(45.0f);//必要に応じて
this.scene.attachChild(sPlayer);//box2dのときは、ここはコメントにし、他のところでattachchildします。
[/c]

[c]
@Override
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
throws Exception {
// TODO Auto-generated method stub
this.scene=new Scene();
this.scene.setBackground(new Background(0, 125, 58));

//box2dの場合で通常のSpriteでは必要ありません。
physicsWorld=new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false);
this.scene.registerUpdateHandler(physicsWorld);

//common
pOnCreateSceneCallback.onCreateSceneFinished(sceneManager.createSplashScene());

}

[/c]
box2dでは更に物理ワールドを追加します。
[c]
PhysicsWorld physicsWorld;
FixtureDef PLAYER_FIX=PhysicsFactory.createFixtureDef(10.0f, 1.0f, 0.0f);
Body body=PhysicsFactory.createCircleBody(physicsWorld, sPlayer, BodyType.DynamicBody, PLAYER_FIX);

this.scene.attachChild(sPlayer);//
physicsWorld.registerPhysicsConnector(new PhysicsConnector(sPlayer, body, true, false));

[/c]

BOX2Dの利用

Rectangle 四角形のポリゴン表示

Rectangle 四角形のポリゴンを表示する場合、比重、弾力、摩擦抵抗の順で環境設定します。

アンドエンジンは、左上から下に向かって正座標になります。
そして、四角形の基準点も上から基準です。ポリゴンの中心点ではありません。3Dモデリングをしたりすると、だいたいオブジェクトの中心が基準になるので、BOX2Dもそうかと思ったら、違うみたいで、上の位置が基準のようです。

(注)「AndEngine GLES2 Anchor Centerというライブラリがあり、これを使用することで、cocos2dと同様に、左下原点、座標中心座標となります。なお、AndEngineをremobeして入れ替えることになります。」

そのため、
new Rectangle()の引数は
左上X、左上Y、厚さ幅(左からの幅)、高さ(上からの高さ)、VertexBufferObjectManager()
となり、
画面上の右側にポリゴンをカメラ上下に配置したいときは、
左上座標をカメラ幅(厚さを15としたので、その分を引いてます。)位置にして、上から下に向かってカメラ高さにします。
よって、CAMERA_WIDTHの400-15とY座標の0を基準にして、厚さと高さを指定しています。
なお、ポリゴンの中心が基準ではありません(だと思います。つい勘違いして、オブジェクトの中心位置がオブジェクトの基準点だと思いがちです)。

座標の基準はiOSと同じです。
cocos2dの場合は、下が原点になります。左下が原点(0,0)で、上に向かてY座標は正になります。ここは注意が必要です。
SpriteがないのでConnectは必要ありません。
画像box2d_1.png
box2d
[c]
//right wall
int CAMERA_WIDTH=400;
int CAMERA_HEIGHT=800;
FixtureDef WALL_FIX=PhysicsFactory.createFixtureDef(0.0f, 0.0f, 0.0f);//比重、弾力、摩擦抵抗の順
Rectangle rightWallRectangle=new Rectangle(CAMERA_WIDTH-15, 0, 15, CAMERA_HEIGHT, getBaseActivity().getEngine().getVertexBufferObjectManager());//15引くことで、見えない状態から見える位置に戻してます。
rightWallRectangle.setColor(new Color(0, 100, 0));
PhysicsFactory.createBoxBody(physicsWorld, rightWallRectangle, BodyType.StaticBody, WALL_FIX);
attachChild(rightWallRectangle);
[/c]

その他情報BOX2D

Box2dで使用するキャラクターやオブジェクトの設定、当たり判定、リグ、IK(インバースキネマティクス)、コネクション関係を設定するツールソフト。

R.U.B.E stands for Really Useful Box2D Editor. 約3000円のツール

Box2D mountain-bike

http://www.iforce2d.net/b2dtut/
Box2D tutorials – Introduction – iforce2d

・cocos2d for iPhone with box2d アイフォンアプリ用のbox2dのチュートリアルも参考になると思うので記載
Intro to Box2D with Cocos2D 2.X Tutorial: Bouncing Balls | Ray Wenderlich

How To Create A Breakout Game with Box2D and Cocos2D 2.X Tutorial: Part 1 | Ray Wenderlich

How To Create A Breakout Game with Box2D and Cocos2D 2.X Tutorial: Part 2 | Ray Wenderlich

スマートフォンアプリの市場について

アイフォンとアンドロイド携帯、その他の携帯電話、スマートフォンが発売されています。現在、アンドロイド携帯端末が多く、そして2番めにアイフォン端末だと思います。
主流の2つのスマートフォンに向けて、アプリを開発することが望ましいことは言うまでもありません。
 実際にadmobをアイフォンアプリとアンドロイドアプリに設定して、広告表示数をチェックしてみたところ、ほぼおなじ回数の広告が表示されていました。ダウンロード数が少ないので、他のアプリ全般に共通しているといえることではないですが、この結果をみると、できるだけ、多くのプラットフォームに対応したほうが、広告表示回数が多くなるということがわかりました。