2014年9月6日土曜日

擬似乱数が話題になっていたので、MT布教のためのJava Classサンプル公開

Mersenne Twister(MT) は非常に簡単な処理で恐ろしく周期が長い、というか周期が無いとしても差し支えない優秀な擬似乱数生成アルゴリズムです。
詳しくはこちらの本家を御覧ください。
Mersenne Twister: A random number generator (since 1997/10)

僕は初期のMTを知り感動して以来、C++、Java、C#のクラスに実装しずっと使わせて頂いています。
コンピュータの乱数の話でこのMTを語らない方が多くいつもモヤモヤしてましたので、自前の移植クラスを公開してみます。

ゲームにおいてですが、32ビットCPU使えるならこれ以外の擬似乱数は必要ありません。というかこれ以前の生成方法は特別な状況以外価値がなくなりましたので、わざわざ使わない方が良いですね。

実はJavaのクラスライブラリには随分前にMTが採用されているのですが、ゲームプログラムにおいては自前クラスで実装しておいた方が何かと便利です。ゲームプログラミグ独特かもしれませんが、C++のSTLと同様用意されたものを使わず自前実装した方が有利なカテゴリと言えますね。


public class MT {
public final static long Max = 0xffffffff;
final static int MT_N = 624; // length of state vector
final static int MT_M = 397; // a period parameter
final static long MT_MATRIX_A = 0x9908B0DFL; // constant vector a

long [] sv = new long[MT_N]; // state vector
int N, M; // random value is computed from here

public MT(long _s) {
N = 0;
M = MT_M;
for (int i = 0; i < MT_N; i++)
sv[i] = _s = ((1812433253L * (_s ^ (_s >> 30)) + (long)(i))) & 0xffffffffL;
}

public long Next() {
int P = N;
if (++N == MT_N) N = 0;
// move hi bit of u to hi bit of v
sv[P] = sv[M] ^ (((sv[P] & 0x80000000L) | (sv[N] & ~(0x80000000L))) >> 1) ^(((sv[N] & 1L) != 0)? MT_MATRIX_A: 0);
if (++M == MT_N) M = 0;
// Tempering
long y = sv[P];
y ^= (y >> 11);
y ^= (y << 7) & 0x9D2C5680L;
y ^= (y << 15) & 0xEFC60000L;
y ^= (y >> 18);
return ((long)(y));
}

public long NextL(long _max) { return (Next() % (_max +1)); }
public long NextL(long _min, long _max) { long range = _max - _min +1; return (Next() % range + _min); }
public int Next(int _max) { return ((int)(Next() % (_max +1))); }
public int Next(int _min, int _max) { int range = _max - _min +1; return ((int)(Next() % range + _min)); }

public float Next(float _max) { return ((float)(Next())*_max/0x100000000L); }
public float Next(float _min, float _max) { float range = _max - _min; return ((float)(Next())*range/0x100000000L +_min); }
}



これだけ、コンストラクタと基本のメソッド1つです。
コンストラクタに適当なシードを渡すと、古い擬似乱数でMTの初期ベクタを作ります。Next()を呼ぶ度に撹拌されたlong値の擬似乱数が返ります。
Next()メソッドがMTの本体ですが、この様な単純な演算の組み合わせだけで2の19937乗-1というとんでもない周期の乱数が手に入ります。
出力もlong以上が欲しければ、複数回取ってきて組み合わせるだけです。4個一組にしても、とんでもない周期が1/4になるだけですから。

Next()メソッドの変種が色々付いてますが、この処理はゲーム用に簡略化しています。皆さん用途に合わせて適当に作られれば宜しいかと。

初期ベクタの設定の仕方で様々な応用ができますので、コンストラクタも用途に合わせてアレンジするのが良いかと思います。
アナログ的な乱数として使用するなら、シードを現在時刻から生成すれば良いでしょう。
但し出力段(Next)の撹拌性能に由来する偏りも知られていますので、気になる方は対策を調べられるよと良いかと思います。

ちなみに元のC言語版ではCPUのキャッシュ内での実行による高速化等が考慮されていたのですが、今時のゲーム用途ではさほど必要無いのでシンプルな処理に直しました。

このMTがゲームにおいてとんでもない武器だという事を、一人でも多くの方に知っていただきたいものです。僕なりの使い道の例はその内に。

最後ですが、MTのサイトにある以下のページは、是非とも御覧ください。数学研究に対する考えが少し変わるかと思います。


お願いと謝辞


2014年8月10日日曜日

Androidのスマホやタブレットが調子悪くなったら試してみよう

Androidの端末がものすごく重かったり、他の人のは電波つかんでるのに自分のだけアンテナ立たない・・・
そんな症状でお困りでしたら、以下を試されると幸せになれるかもしれませんよ?



(1) 携帯のアンテナが立たなかったり、立ったてもすぐに消えたり
原因:SIMカードの端子が汚れている

対処:
スマホの電源を落としてSIMカードを外します。
SIMカードの金属端子部分を綿棒等でゴシゴシ掃除します。
はぁ~っと息を吹きかけて、その湿り気を乾拭き。でも十分ですが、
表面が薄く酸化してたり、ヤニとかで覆われている場合には、アルカリ電解水を綿棒に少しだけ付けて擦ると効果があります。
ティッシュ等で良く水分を拭きとってからスマホに装着し、電源を入れて確認してみてください。

それでもダメな場合、SIMカードが壊れているか、スマホが壊れているかのどちらかです。
使ってない予備スマホがあって、同じ大きさのSIMカードが刺されば、自宅でも確認できます。
面倒ならショプに行きましょう。



(2) Android端末で動作が異様に重い
原因:スマホのメモリ(RAM)の空きが少なすぎる

足りないのはアプリを入れておくフラッシュメモリではなく、アプリを動かす時に使う一時メモリ(RAM)です。これは作業机の様なもので、机の上にモノがあふれかえっていて、まともに仕事できない状態と同じになってます。

対処:
Advanced Mobile Care(AMC)等のアプリで、余計なアプリを一時的に止めてみます。
解決したなら、不要なアプリをアンインストールしてみます。
この時、一度再起動してからでないと効果が出ない場合が多いようです。
AMCはアンチウィルスも付いていて便利です。同種のアプリを色々試しましたが、使いやすく安定しているのでオススメです。



(3) 操作できないレベルで動きが重い
原因:SDカードのデータが壊れている

スマホの各アプリが自分の保存データを読み書きしようとするのですが、出来ないのが分かるまでにずーと待ちぼうけしてしまいます。この為、スマホの中で大渋滞が発生し、ほとんど動かせなくなってしまいます。
スマホのアプリは、SDカードが刺さってるとアプリのセーブデータをSDに書き込むものが多く、実はそのSDカードの「フォーマットの一部が壊れてしまう」事が頻繁に起こります。

保存したファイルが壊れるのではなく「フォーマット」から壊れてしまうと、データの読み書きができなくなるだけでは無く、壊れているのかどうかが分かるまで、かなりの時間がかかってしまいます。

対処:
SDカードから必要なファイル、例えば撮影した写真などをバックアップし、SDカードをPCで初期化します。この時「クイックフォーマット」のチェックを外す必要があります。
フォーマットの形式は「FAT32」で問題ないはずです。
もしスマホでそのまま使えなかった場合、改めてスマホの設定からSDカードを初期化して下さい。



対策は以上です。

そもそも使っているアプリの組み合わせでメモリが足りてない場合には、買い替えを検討される時期でしょう。
次はRAMの搭載量も気にして選ぶと良いでしょう。最近のモデルでしたらRAM2G以上を探すと、かなり長持ちすると思いますよ。



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()で出力しないで利用しても問題無いです。