‘ゲーム’ タグのついている投稿

3D物理エンジンbulletをAndroidで使ってみた

Game Physics Simulation

以下のエントリーが詳しいです。今回はこちらで公開されているサンプルを実行してみました。

OpenGLによる3D描画とBulletによる物理演算の縫合メモ – 麗ちゃんとママの実験ノート

自分でビルドしてみようと思ってハマったポイントをいくつか書いておきます。ちなみに元のサンプルは何も問題ないです。余計なことをして個人的にハマっただけです。

bulletのバージョン

bulletのライブラリのバージョンが新しくなっているのでAndroid.mkは更新する必要があります。

bullet – Bullet is a professional free 3D Game Multiphysics Library – Google Project Hosting

僕はbullet-2.81-rev2613.zipをダウンロードしました。
jniフォルダにsrcの中身を展開します。Makefile.amを開いてリストを確認します。今回はBulletMultiThreadedを除いた、拡張子cppのファイルのリストを全部コピーして、Android.mkに貼り付けました。

ヘッダファイルは作りなおした方が良さそうです

作りなおすとヘッダファイルの内容が少し増えます。

もしくはサンプル通りの名前空間でクラスファイルを作りましょう。

後述するUnsatisfiedLinkErrorの関係で、正確なメソッド名がわからなくて困っていました。
javahコマンドで作成できます。

C:\Users\test\Documents\workspace\BulletTest>javah -classpath bin/classes -o jni/info_play_smart_android_bullettest_Cube.h info.play_smart.android.bullettest.Cube

クラスパスが間違っていると以下のようなエラーになります。

C:\Users\test\Documents\workspace\BulletTest>javah -classpath bin -o jni/info_play_smart_android_bullettest_Cube.h info.play_smart.android.bullettest.Cube
エラー:info.play_smart.android.bullettest.Cube にアクセスできません。
info.play_smart.android.bullettest.Cube のクラスファイルが見つかりません
javadoc: エラー - クラス info.play_smart.android.bullettest.Cube が見つかりません。
Error: コマンド行でクラスが指定されませんでした。-help で確認してください。

ただ、引数の名前と数が変わってしまうので、Cube.cppファイルから引数の部分だけコピーしてヘッダファイルを更新しました。

名前空間とアンダースコア

名前空間にアンダースコアが含まれるクラスを作っていたので、以下のようなエラーが発生しました。

01-05 12:56:43.351: W/dalvikvm(20100): threadid=11: thread exiting with uncaught exception (group=0x40c5d300)
01-05 12:56:43.390: E/AndroidRuntime(20100): FATAL EXCEPTION: AsyncTask #1
01-05 12:56:43.390: E/AndroidRuntime(20100): java.lang.RuntimeException: An error occured while executing doInBackground()
01-05 12:56:43.390: E/AndroidRuntime(20100):     at android.os.AsyncTask$3.done(AsyncTask.java:299)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at java.lang.Thread.run(Thread.java:856)
01-05 12:56:43.390: E/AndroidRuntime(20100): Caused by: java.lang.UnsatisfiedLinkError: Native method not found: info.play_smart.android.bullettest.Cube.simulate:(Linfo/play_smart/android/bullettest/Cube;)V
01-05 12:56:43.390: E/AndroidRuntime(20100):     at info.play_smart.android.bullettest.Cube.simulate(Native Method)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at info.play_smart.android.bullettest.Cube.simulate(Cube.java:75)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at info.play_smart.android.bullettest.Cube$AsyncTestTask.doInBackground(Cube.java:69)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at info.play_smart.android.bullettest.Cube$AsyncTestTask.doInBackground(Cube.java:1)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at android.os.AsyncTask$2.call(AsyncTask.java:287)
01-05 12:56:43.390: E/AndroidRuntime(20100):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
01-05 12:56:43.390: E/AndroidRuntime(20100):     ... 5 more

JNIの呼び出しは

JNIEXPORT void JNICALL Java_名前空間_クラス名_関数名

で定義された関数を呼び出します。

.(ドット)は_(アンダースコア)に変換します。

今回、名前空間にinfo.play_smartを使ったのでinfo_play_smartとしていたのですが、それが間違いでした。

すでにあるアンダースコアは「_1」に変換しておく必要があります。

この辺は上記ヘッダファイルを作ったときに初めて知りました。(ヘッダファイル中に記述されるので)

名前空間を元のサンプルに合わせておけばもっと楽にできたので残念です。

一応これで動くようになりました。

LuaかSquirrelとバインドして動くようにできたら便利だろうなぁ。誰か作らないかなぁ。