【Android】アクションパズルのソースを公開【ソース】【ACT/PZL】


単純な仮想マップで実現しています。

4つ くっついたら消えるルールなので、ぷよぷよ型ですね。
ルールを変えたい場合、コラムスやテトリスのほうが作りは簡単です。

ユーザが入力できる動作としては、上から落ちてくるのではなく、zoo keeperのように隣接するブロックを一か所だけ入れ替える方式です。

学べること

・仮想マップ
RPGやSLG、アクションゲームなど応用が幅広いです。

・タッチ操作

・アクション、アニメ
Threadの一使い方

・グラフィック

思いと想い出

べーまがの記念号で、コラムス特集で勉強させてもらいました。
同じように、後世の人に作ってもらう面白さを体験してもらえればと思います。

初心者の頃って見ていじって覚え、そのうちにだんだん自分で型を組み合わせるようになります。
サービスの受け手よりは作り手が増えたほうが幸せです。

あの時も、ルールを変えたりいじって遊びました。
あまりにも簡単になりすぎてつまんなくなってしまいましたが、いい思い出です。

当時も高級なPC9801の BASICマニュアルを50周ぐらいして、できることを理解していったりもしました。
(親に感謝)

ソース

GitHubに公開

https://github.com/naturallucky/ActionPuzzleAndroid

はずかしいですが あまりソースを公開しているところがないのでやってみました。
結構整備に時間を取られました。
まだきれいでないところももちろんありますが。

操作性など改善したいところもあります。あまり凝った作りにすると
初学者に難しくなると思うのでこのあたりで止めておきます。

完成版:Google Play

https://play.google.com/store/apps/details?id=biz.myworkstyle.fruitsparadise

発展させた完成版を Androidにあげましたが、ちょっと簡単すぎるので
またルールを変えて更新しようと思っています。(公開停止中)

ライセンス

著作権を放棄しないレベルですので、自由に使ってください。

おまけ:プログラム初心者向け説明

中1ぐらいで、プログラミングで動かしてみたいと思っている人向け。

ブロックのプログラムの組み方

テトリスなど、どうやってんの?ってまったく想像もつかないかもしれません。

最初は、実は変数の扱いの延長線上で、わかってくるのです。
ほぼすべてのゲームのフィールドは同じロジックですし、3Dになっても基本は変わりません。

ここでは、2次元配列の理解とアニメーションまで説明します。

参考:ゲームを作るときの考え方のとっかかりについてはこちら

配列

まず変数というものは何かというと、代数みたいなもので、情報を保持できます。コンピュータが保持できる情報は電子的なトランジスタで動いているので、bit(ON or OFF)なんですがCPU上、整数や小数が中心で、整数を拡張して、色、音、文字、日本語などがあります。これらの組み合わせ方でもっといろいろな情報を保持していますが、基本は数字の組み合わせでしかありません。bitの組み合わせの動作を数学のルールと一致させたり、マウス、キーボード、HDD、ディスプレイ、スピーカー、ネットワークアダプタなどの Input/Output(I/O)をbitでやり取りしています。

ここでは、一旦例えば、整数をひとつ保存できると覚えておいてください。

x = 3;
セミコロンは、一文の完了を表すので、プログラミング言語での文のピリオドみたいな意味です。

この処理の後 xに 3という数字が記憶されています。
x = 10;
とすると x に 10という数字が記憶されることになります。

ぜんぜん  3,10で イコールでないやんけ!と理解の深い人は思うかもしれません。コンピュータでは、長年省略されてきて、当たり前なのでルールとして
一般的です。

今でも
x:= 3; などと各言語もあるようですし、昔はそのように設定するのもありました。

microsf / ASCIIの BASIC 言語も昔は
let x=10; のように書いていましたが、プログラミングではあまりにもコード回数が多く当たり前なので、今のような記載になってきたようです。

任天堂のファミベの説明書でも let みたいな記述があったような気がします。

で設定したら何に使うかというと、後で計算時に参照するときに使います
当初WWI当たりのパソコンは弾道を計算するために開発されていました。
なので、初速や角度を変数に代入して、着弾地点を計算します。
初速 vx = 10.0;みたいに使い、のちに   vy/g * vx*2 ~~~のように
数式に合わせ、CPUのレジスタ領域にセットして使います。

1次元配列

このように一つの数値が覚えられるようになってきても、100個、1000個の数値をまとめて扱うとき、プログラム上での宣言自体も面倒ですし、変数名の管理も大変です。そこで出てきたのが配列という考え方です。

配列は 整数をたくさん、例えば10個覚えられますよというものです。
x[10] という宣言の書き方をします。

3番目にアクセスしたいときは、
値の設定も、参照も x[2] という書き方が一般的です(0,1,2の3番目:0スタート)

2次元配列

ドラクエなどのマップは平面に広がってますよね。そうです。X/Yの2方向に広がっているため、そのマップごとに川があるのか、山があるのか、何があるかという情報を覚えるには2次元配列が便利です。

2次元配列といっても実際は1次元配列が 複数個セットあるようなイメージです。
map[100,100]のような形式です。

例えば、コラムスやパズドラで赤い宝石を1、青い宝石を2として保存します。
ぷよぷよでは、赤ぷよを1、お邪魔ぷよを99などと保存します。実際マイナスの値や、0などを使うのは好みです。似たような意味は連番にするとプログラムしやすくなりますが、区別はしにくく覚えづらいです。

テトリスやDr marioも、色毎にmapを設定してもいいですし、ボードゲームのオセロや将棋、囲碁なども似たような考え方です。

上記のアプリの動画も、色毎に2次元配列で値を覚えておき、描画するときにその対応するパーツ(オブジェクト)を描いているだけです。

ブロックを消すとは?

なんとなく、ぷよぷよのフィールドの配置内容が見えてきたと思います。

じゃあ、どうやって消すか判定しているの?というところでとっかかりが難しいかもしれません。

テトリスで消えるときとは

まず簡単に、テトリスのパターンで考えてみます。
テトリスのルールは、ブロックを置いた直後に判定します。
そして横一列がどんな色やブロックでもそろったら消えます。

なのでそれをプログラム上で判断すると
map[x,y]で判断します。
そこには値が入っており、空は0、ブロックは1~6だとします。
その時、yを下から検索し すべてのx[0<x<10]の値(一列)が、1以上であるとき
その列を消します。

実際は、消した行数を覚えておき、
全部終わったら行を全部空(0)で上書きします。
行数のスコアを足して、レベルアップ等の処理を行いアニメーション用情報(消えるシーンとか、落ちるシーン)を保持して次の処理に進みます。

コラムスの場合は、縦横3つ並んでいたら、消します。
オセロの場合は、各方向で、もう一方が自分の色でその間がすべて相手の色であれば、ひっくり返します。

ぷよぷよの場合は

ぷよぷよの場合は、4つ繋がったら消すというルールです。
なのでけっこう難しいです。

まず1パターンだけ考える

いわゆる迷路のアルゴリズムや経路探索のアルゴリズムに近いことをします。

まずは、全部を考えると難しいので、ある1点だけで考えます。
そこから同じ色で4つ繋がっていたら、消すというパターンのみまず検討します。
スタートのぷよの色を取得し、4つの全方向(後述)チェックします。まず右に進んでみます。同じ色であれば、同色数を1つアップして2にしておきます。保存する場所としては  map_check[x,y]というように同じサイズの仮想マップを用意して、そこに記載します。もし空や壁であったり、同色でなければ、その方向はありえないので、-1:でストップを意味する値を入れて、別の方向に進みます。

そこでも同色であれば、連続している数字を1つアップして、また次に進みます。

1パターン考えたら、少しずつ全体に拡張していく

このように一歩進むごとに、また全方向探索していくように、同じやり方が続いていきます。このような処理の仕方を再帰といいます。局所局所では同じようなことをやるので、アルゴリズムを作るときはサイズが変わっても影響を受けにくいですし、作りやすいです。

全部終わったら消しますよ

どの方向も完了したら、4つ以上つながった方向のみ、消す対象にします。それ向けとして、map_del[x,y]を別途用意しておいてもいいです。

消す対象は、メソッドのコールバック時にチェックしていけばいいかと思います。どのようにチェック結果を反映するか、そこらへんはプログラマーの腕の見せ所です。 さきほど全方向としましたが、下と上は同じ方向なので省略可能です(ぷよぷよの場合は左右も同じと思いがちですが、チェックルートとしては同じでないため省略不可です。左右か、上下どれか1方向のみ省略可能です)。無駄なので実際は省いて実装します。ただいきなりそこまで考えるのは難しいので、実装が出来上がってから、無駄を省いていきます。

これを全ますにおいて行えば、4つ以上つながって消えるマスがわかります。
ちなみに本来のぷよぷよの場合はお邪魔ぷよもあるので、もうひと処理が必要です。

2次元配列 応用例は広い

このように2次元配列を活用して、消込ができます。3Dなども同じで、1マスの大きさを小さく・細かくしていけば、砂レベルまで表現できます。メモリ確保やスピード上の難しさは出てくるので、そこで目的に合わせてバランスをとり頑張ります。プログラマーが腕を見せるところです。

x,yの後にもっと情報を載せると n次元に膨らんでいくかと思いますが、3次元以上大抵のケースで必要なく、増えません。なぜなら 3つ目を種別として利用し、それで大抵事足りるからです。

アニメーション

今度はアニメーションについて、話します。

アニメーションというのは、単に一定期間ごとの処理STEPです。
先ほどはマス単位でしたが、今回はひとくくりの処理単位ごとの切り口でアルゴリズムを作っていきます。

例えば 50msec( 20fps) ごとに 一塊の処理を行うように設計します。
50msecごとに処理させる場合、単純なループではなく、スレッドやタイマーを使います。最近のプログラミング言語は用意されているので、それをそのまま使います。

それで呼び出されるごとに一塊の処理をするところをメインループ処理とします。

ギャラガなどのゲームでは、自機の移動、敵の移動、各弾の移動、背景の移動、当たり判定などがセットになります。スコアやゲームオーバー、効果音等の処理は各処理の中でやります(一例なので実際は好きに設計してかまいません)

  • メインループ(タイマー起動)
    1. 自機の移動
    2. 敵の移動
    3. 各弾の移動
    4. 当たり判定
    5. 背景の移動

このように1コマ1コマずつ処理することになります。
右を押している間、自機の移動は、この1コマで x座標を右に増加させたりします。

ブロック崩しや、弾などは初速の速度文増減させていきます。

最近はイベントドリブン方式なので、キー入力時に自機移動の処理をしているかもしれません。それでもいいですが、1コマの処理単位を意識しないと、1コマで3回自機が動いたり、逆に敵の弾がめちゃくちゃ早く動いたりします。

ぷよぷよの場合は

ぷよぷよの場合は、とくになく、消したぷよがあればそれを点滅させ、消して、残りのぷよを重力をイメージでして落とします。

実際には、それぞれの状態を statusに保存し、0の時は通常の操作可能、
1の時は、消す点滅中、 20コマ進んだら、2のステータスにセットし消滅させ落とすアニメーションを処理します。落としきったらまた statusを0にします。
(点滅中のぷよがある場合は、動かせないようにロック処理が必要です)

ぷよごと(map1マスごと)に statusを設定してもいいですし、全体で一つのstatusとしてもいいです。それはゲームのやりたいことに合わせて調整します。細かくすると面倒ですが、それぞれバラバラに処理ができるようになります。

3Dのゲームでは、fpsが60を超えてきているので、描画のスレッドと処理のスレッドは別になっていると思います。もし同じだと、早いPCのほうが早く弾が飛んだり、ダメージが長く入ったりするかもしれません。それを防ぐにはつねに時間に合わせた移動処理をする必要があります。ネットプログラミングでPvPで対戦するような場合は、注意が必要でしょう。

リスペクトの精神

キャラデザインやストーリー以外は利用できますが、最初に考えた人たちのリスペクトは忘れないようにしましょう。

最後に

駆け足で、仮想マップとアニメーションの考え方のとっかかりを紹介しました。最初はとっかかりもないかもしれませんが、何十回もアルゴリズムやソースを読んだり、仮説を立てながら、興味のある部分を1文字ずつ改造して自分なりになにがどう動いているのか、主体的に能動的に解明していくのが楽しいでしょう。

Delicious にシェア
Digg にシェア
reddit にシェア
LinkedIn にシェア
LINEで送る
email this
Pocket

213 views.



コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です