SurfaceView をグリグリ動かす

やりたいこと(一応書いていおくとQuixや100万トンのばらばら的なゲームです)

1)自分はいつも画面の中心に表示
2)画面サイズよりも十分大きなマップを読み込む
3)上下左右にフリックさせると、下上右左に動く
4)マップの画像は透明色部分には移動できないようになっている
5)ボタンがあって、モードを切り替える
6)モードが切り取りモードの場合は、動きまわるとその軌跡が繰り抜かれる
7)切り取りモードでマップを横切ると、マップの小さい部分が繰り抜かれる
8)適当な要点を設定できる(スタート地点、ゴール地点、パワーアップなど)

1),3),4),5),8)は問題ない。
2)は自前のクラスで対応。
具体的に言うと読み込んだイメージを byte 配列に格納している。
配列には7)に対応できるように全体の面積を算出できるように、8)に対応できるように数種(byteなので全部で250種はOK)の設定が可能となっている。
もっと速くするならNDK?

当初は Viewクラスを継承した独自クラスを、使っていたのだけど、SurfaceView の方が良いみたい。
Viewでも可能だけど、SurfaceView の方がこのゲームには合っている。
http://www.atmarkit.co.jp/fsmart/articles/android12/android12_1.html

SurfaceView にしたことで onDraw で描いていたものが描けなくなったので、doDraw というメソッドを作って(onDrawでもいいけど、自動的に呼ばれると勘違いされる可能性があるので)
そこに処理を持っていく。
また Canvas も Lockable なタイプになっているので、そこも変更。

で、引っかかっていたのが、SurfaceView のサイズ変更に関するところだ。
http://www21.atwiki.jp/memodroid/pages/26.html
などにも書かれているが、SurfaceView のサイズは自由に変更できない Fixed となる。
マップイメージは各面毎にちがうので、単純に getWidth(), getHeight() メソッドでは取ってこれないし、そもそも ImageView のXMLのように android:src で設定されていないのだ。
画像が設定されていないので、大きさが0のままである。
で、surfaceCreated、surfaceChanged、surfaceDestroyed などが全く呼び出されることもなく「なんでだろう??」となっていた。
でどうやるかというと、Activity の継承クラスでサイズの決定を行う。


/**
* onCreate では view サイズが決定できないのでここでサイズ設定を行う
*/
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!isSizeSetted) {
// Viewのサイズを取得
Display display = getWindowManager().getDefaultDisplay();
mMapImageView.setLayoutParams(new LinearLayout.LayoutParams(
display.getWidth(), display.getHeight()));
mMapImageView.setViewSize(0, 0, display.getWidth(), display.getHeight());
isSizeSetted = true;
}
}
これでやっと各種問題が解決。
surfaceView のメソッドも呼ばれるようになった。

あと問題なのは7)だが。大きなマップであるほど面積の計算には時間がかかる。
Android 2.x は画面サイズ的に大丈夫だと思うが(というか、そもそもBitmapイメージを読み込めないと思うので対象外)、3.x, 4.x は最低でも1920x1080ほどにも対応しなければならないので、結構たいへん。
そこで最初のマップの読み込み時に面積を出しておいて、後は切り抜きモードで端っこに来たら(別スレッドをたちあげて?・・・でもこれをやると面積の整合性が取れなくなるなぁ・・・切り抜きモードを強制停止するか?)そこでその面積を計算させる。
その面積が、最初に読んでいた面積の半分より小さければそれが切り抜かれる部分になる。
半分より大きければ、そこじゃない部分が切り抜かれる部分になる。
移動方向を考えて、横方向に大きく移動している場合は上下で、縦方向に大きく移動している場合は左右で判定する。

こんな感じかな・・・1ヶ月かかってやっとここまで辿りつけた・・・orz