2014年7月16日水曜日

Javaの小ネタ

Javaの言語仕様として、文字はUnicode使うって事になってますよね。
そんでJavaは実行環境もコンパイル環境も仕様は変わりないんです。
で、何が小ネタかといいますと、実はJavaの変数名・メソッド名なんかには漢字が使えます。
というかUnicodeの文字なら何でもありです。

    String 勇者の名 = "ハラペコ";
    int 体力 = 256;
    ステータスの表示(勇者の名, 体力);

とか書いてもコンパイル通ります。
恐らくオッサンの皆さん(with俺)の脳裏には「ぴゅう太の日本語ベーシック」とか浮かんでいるのではないでしょうかw

ただしClass名だけはファイル名と同じにする関係上、ダメな場合がほとんどです。
特にEclipseとかの統合環境は日本語ファイル名が使えない様なのでどうにもムリっぽいです。
(内部クラスなら行けるかも)

しょうもないネタで御免なさいm(_ _)m

2014年6月9日月曜日

今更ですが、OpenGL ESは1.1と2.0、どちらを選ぶべき?

スマホ・タブレット向けゲームアプリを本気で制作しようとすると、OpenGL ESでの描画は避けて通れませんね。
で、実際にサンプルでも動かそうとする場合に、1.1と2.0では処理の仕方/書き方が少々違っている。という所までは簡単にに調べが付きます。
では、どちらで開発すれば良いのでしょか?

結論から言えば、現状では未だOpenGL ES 1.1 を使うしかないと考えます。

ではどう違うのでしょうか?


●OpenGL ES 1.1
・GPUの負荷が軽いので、ごく一部の画面の更新速度が元から30fpsの端末を除けば、60fps以上を出せる。
Android2.2~2.3の頃の端末でも、比較的動作が安定している。
・シェーダーが使えないのは致し方ないが、レンダリング先をスクリーン以外に行うなどの便利機能が無くて痛い。
・仕様が枯れているので、ネットで情報を集めやすい。

●OpenGL ES 2.0
・シェーダを駆使すれば、PCゲー並みの描画が実現可能。でもGPUの負荷が重い。
・たとえアプリを軽く作っても、OpenGL側で30fpsが頭打ちになってしまっている。
・Android2.2~2.3の頃の端末では不安定な挙動が散見されているらしい。
(↑これは聞いた話なので未確認です)
・シェーダプログラミング自体が開発の負荷になるし、そもそも書籍でもネットでも良い情報が得られにくい。


GLES2.0はシェーダに触れなくても30fps以下しか出ません。これは動きのあるゲームでは致命的です。
ゲームの歴史的に30fps以下のハードでは、ソフトウェアが良い評価を得る事が非常に難しくなります。
まぁゲームの操作性は気にしない。フォトリアルまっしぐらな方はGLES2.0以降でも良いですし、今後ハード(GPU)の性能自体が数倍に跳ね上がれば、GLES1.1はレガシーになり消えていくのでしょう。

2014年の現在、ファミコン程度の操作性を実現する為にはOpenGL ES1.1しか選択の余地がない。という事でした。



2014/07/16 更新 OpenGL ES 2.0以降だと30fpsが頭打ちと書きましたが、最新のGPUではそうでもない様です。 僕の情報が半年~一年遅れだったかもしれません。 ただし多くのユーザーの機種には、未だ重たいのが現状のようです。 GPUのパワーが上がっているのは確かですが、画面解像度もFullHDが当たり前になりつつあるので、その分相殺されています。 もう1~2年待たないと60fpsは辛そうだな、と僕は予想しています。

黄色くなったファミコンを真っ白に漂白する方法。の新技を発見しましたよ

新発見!(゚∀゚)アヒャ
…とか言う程の事でも無いんですが、巷の情報より良い方法を見つけました。
元々の方法は各自ググって調べてみてください。

■新しい方法
何の事はありません。プラ漂白でよく使われている「酸素系」漂白剤ではなく「塩素系」漂白剤を使います。
スーパーや薬局で安く売っているのでOKです。洗濯用でも台所用でも大差ないので、洗濯用の大入りボトルを買うと良いでしょう。僕は業務スーパーで買いました。

後は今までのやり方と一緒で、黄ばんだプラスチックを漂白剤につけながら日光(紫外線)に1~2週間ほどさらすだけです。100均で買える大きいタッパがなんとか使えますが、完全に密封できていないので液漏れに注意が必要です。
気になる方はガッチリ密封する保存容器を使って下さい。



左が塩素系で2週間ほったらかし、右が酸素系(濃縮タイプ)に10日間ほど漬け込みました。


裏はこんな感じです。

塩素系の方はよく分からずにそのまま放り込んだので、貼り付けてある「ファミリーコンピューター」のエンブレムとかの表面が溶けて消えてしまいました。
という訳で、ファミコン本体の場合は予めラベル関連を剥がす必要がありますね。

酸素系の漬け込み期間が少し短いのは、確認した時には既に漂白成分が飛んでしまっていたためです。これ以上は無意味だったので取り出しました。
塩素系は酸素系に比べて漂白のスタートダッシュが遅い様なのですが、しばらく天日に晒してもあまり効果が落ちませんので、長期間または他のプラ漂白に続けて利用できる点も有利ですね。
そうそう、塩素系は裏側も結構漂白されてる所も優れていました。

まぁお洗濯の時の使い分けと同じで、色柄がある場合は酸素系。真っ白にしちゃっていいのなら塩素系でOKかと思われます。


2014年5月16日金曜日

Androidのデバッグ用に、クラス名・メソッド名・行番号を表示する

ゲーム開発ですと、統合環境のデバッガでのんびり見てられない事が多いので、自前でデバグ出力を何とかする必要があります。

LogCatに出力するLogクラスが有りますが、以下な感じの便利メソッドを何処かのクラスに置いておくと便利です。

public static void Debug(String _msg) {
Throwable throwable = new Throwable();
StackTraceElement stack = throwable.getStackTrace()[1];
int line = stack.getLineNumber();
String func = stack.getMethodName();
String cls = stack.getClassName();
Log.i("ProjectName",cls+":"+func+"/"+line+" "+_msg);
}

これを任意の場所で呼び出せば、呼び出し元のクラス名・メソッド名・行番号を表示できます。
VMの実行環境を拾ってくるだけですね。
もちろんLog.i()で出力しないで利用しても問題無いです。




2013年10月28日月曜日

Fatal signal 11 (SIGSEGV) ・・・ なんだよこれ!

何の音沙汰もなくアプリが落ちる。
あまつさえ端末が再起動し始める。

こんな場合、OpenGLのBuffer問題を考慮してみるのが有効かもしれません。
WebViewを使っている時も原因は同じようですが、こちらはクラスライブラリ内部の話なので解決策はよく分かりませんが。

先ず発生条件ですが、OSでは

・GB以前は無かった。ICS以降。ICSでも初めは問題なかった。

で、端末では

・シングルコアでは見た事が無い。どうもデュアルコア以降らしい。
・ainol Novo7Fire(CM10.1)だと起動後暫くすると発生。
・SAMSUNG GalaxyTab7.7Plusだと起動直後にフリーズ。

アプリでは

・別のスレッドでOpenGLを叩いている。
・例外では何も拾えない。

となります。何が推測できるかといいますと、

どうもGPUが参照中にアクセス保護しているメモリ領域に対して、アプリ側がコンフリクトを起こしている。

という事です。

OpenGLにデータを渡すためにnioのBufferクラスを使いますが、内部で持っているネイティブのメモリアクセスに対して何もしてなさそうです。
OpenGLに渡したBuuferへのアクセスを、OpenGLを叩いているスレッドだけに絞ると、このエラーはピタッと収まりました。

こんな事がありましたので、ご参考になれば。



2014/07/16 追記

少し具体的な説明です。
OpenGLは初期化したスレッドからのみ呼び出しが可能という仕様は知られていますが、
Javaで呼ぶ場合にデータを渡すために使ったBufferクラスのインスタンスへの書き込みも該当します。
OpenGLがBufferのメモリを覗いてせっせと描画している時に、別スレッドからBufferのメモリにアクセスするとコケるという具合です。

解決策としては、メインのスレッドではBufferに直接書き込まず、更新用の情報を別に用意します。
OpenGLを叩くスレッドで、描画する前に更新内容をBufferに適用すれば問題解決です。
面倒くさいんですが、マルチコアCPUの恩恵を受けるためには致し方ありません。








SAMSUNGてめ~w (初代ギャラタブとかのテクスチャが表示されない場合)

今更で需要は少ないかもしれませんが、古い機種も対応される方向けに・・・

SAMSUNGのAndroid2.2系端末、初代ギャラタブとかですね。この頃の機種はOpenGLのドライバに悲しいバグが色々あるのですが、検索で見つからず難儀した事を思い出したので軽く。

テクスチャ絡みで、テクスチャに割り当てるIDを払いだしてもらえるメソッドがあります。

結論:
そのメソッドを使ってはいけません。
(なんてメソッドだったか調べるの面倒くさいので、各自でよろしくです)

何故か:
負の値が払い出される事がある。その値をそのままテクスチャのバインドに使うと、そのIDに割り当てたテクスチャは呼び出せない。

gl.glBindTexture(GL11.GL_TEXTURE_2D, id);
GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bmp, 0);

これで id<0 だと、描画時にもう一回バインドしても何も描画されません。
ま、gl.glBindTexture()が負の値を受け付けないというか、0以下はバインド解除なんで当然なんですけれど。
ちなみに払い出しID値の法則性は不明。他のメーカーの端末とは異なり意味不明なバラバラな値。なんか擬似乱数っぽい感じでした。

解決策:
自分で適当なカウンタを用意して、それを勝手にIDとして使います。
IDはかぶらなければ、特に問題なかったです。OpenGLって、結構てきとうな作りですね。


assetに置いたファイルがMediaPlayerで再生できない → 解決


タッチのコントロールクラスが良い感じに片付いたので、そろそろほっぽっといたサウンド関連に着手しました。
で、MediaPlayerでassetに置いた.oggファイルを再生しようと思ったら、思いっきり躓きました。

普通にMediaPlayerを継承したクラス内で

AssetFileDescriptor afd = asset.openFd(filename);
try {
    setDataSource(afd.getFileDescriptor());
    prepare();
    start();
} catch (Exception e) {
    //
}

こんな感じで書けば音が鳴るんですが・・・というか鳴ってたんですが、しばらくするとprepare()で

java.io.IOException: Prepare failed.: status=0x1

となり、失敗するようになりました。
その前に数回は再生されていて、テスト端末を疑って再起動なども行いましたが変わらず。意味が分かりません。
このエラーの文言で検索しても不明でしたが、何とかなりました。
結論としてはsetDataSource()の所を

setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());

こうしないとダメでした。なんでだ?
オフセットと長さを指定しないと例外って、AssetManager絡みの実装不具合っぽいですね。

とりあえず音関係クラスの実装が続きます・・・


--------その後


・・・一応、使える所まで完成しました。

ゲームに使う時のMediaPlayerとSoundPoolの切り分けが、使い勝手に直結するので難しかったです。
その内落ち着いたら、実装したものの解説でもしようかと思ってます。