プログラミングでブロック崩しを作るイメトレ
こんにちは。継続の錬金術士なおキーヌです。
ブログ毎日更新は88日目になります。
平日はがっつりとソースコードを乗せた記事が書けないのが辛いですね。
なのでゲームの作り方を考えてみるイメージトレーニングをしてみようと思います。
行き当たりばったりでプログラミングをしていると非効率なソースコードになることが多いので
しっかりとフローを考えて作ると無駄を少なくできます。
ブロック崩しとは
前回、「プログラミングが難しいと感じる初心者はゲームを作ってみよう」でPONG GAMEの作り方を書きました。
ブロック崩しはPONG GAMEの一人用バージョンみたいなものです。
では、始める前に少しPONG GAMEについてみてみましょう。
PONG GAMEの欠点
PONG GAMEはお互いがパドルを操作して球を打ち合い、相手のゴールに入れたら勝ちです。
基本的に1:1で対戦するゲームなので相手が居ないと楽しめません。
ゲームらしくCPUの機能を実装して一人で対戦するということも可能ですが
CPUはボールの軌道を先読みできてしまうのでメチャクチャ強かったり
逆に調整を怠るとメチャクチャ弱くなったりで全然楽しくないですね。
私も過去に一人用のPONG GAMEを作ったときに3段階の強さを設定してみたのですが
一番強いレベルはこちらがはじき返した瞬間にボールが来る位置を知っているので先読みで動かれるので勝ち目がありません。
流石に強すぎると微調整を施しましたが、結果的にCPUの穴を突いて勝てるようにしました。
しかし開発者である私しかクリアできないんじゃないか?っていうシビアなものになって開発を辞めました。
一人で遊ぶならPONG GAMEよりもブロック崩しの方が向いているでしょう。
### ブロック崩しの内容とルール
ブロック崩しとはその名の通りブロックを崩していくゲームです。
ボールを打ち返すのはPONG GAMEと同じなのですがブロック崩しは相手は一切動きません。
画面上に配置されているブロックに球が当てると、ブロックが消えて球を跳ね返します。
そして跳ねかえってきた球を再度打ち返し、別のブロックにあてて消していくというのが基本的な内容になっています。
全てのブロックを崩すことが出来ればクリアですが、
PONG GAME同様、球を打ち返せなかったらコチラの1ミスとなります。
ブロック崩しの作り方
それでは早速ブロック崩しの作り方を見ていきましょう。
PONG GAMEの時にやったように1つ1つ要素を洗い出します。
- プレイヤーとなるパドルを用意する
- パドルをキー操作できるようにする(横か縦1方向のみ移動にする)
- 球を用意して常に動き続けるようにする
- パドルで球を打ち返せるようにする
- 崩す対象のブロックを画面上に配置する
- 球がブロックに当たるとブロックを消して球を打ち返す
- 機能拡張のためにプレイヤーのステータス配列を作っておく(ライフ保持にも使う)
- デッドラインに弾が当たるとライフを1つ減らす
- 球を初期位置に戻す
- 全てのブロックを崩すとゲームクリアフラグを建てる
シンプルなゲームなのでこうやてすべて羅列できますが
RPGとかの複雑なゲームになってくると羅列するだけで凄い行数になりそうですね。
複雑な処理のゲームを作る前にこういった簡単なゲームを作っておくと
処理の作り方を理解できるので、今後面白いゲームを作るためには避けて通れない道です。
例えばロックマンとかのようなアクションゲームを作ろうとした場合
ロックバスターを打ち込んで相手にヒットした時に相手を消すという処理は、
このブロック崩しと同じ処理で実装できます。
こうやっていざ難しいゲームを作ろうとした時、過去に作った簡単なゲームからヒントや答えを得られるので
作った処理は1つの関数にまとめて説明をつけて保存しておきましょう。
何事もそうなのですが、作ったものは自分の資産になります。
作りっぱなしではなく、作ったものは後から見てもわかるようにしっかりとコメントをつけて別で保存しておくと
今後プログラミングする時に流用しやすくなります。
業務アプリを作ってる時に意外とゲームで作った処理とかを応用すれば効率よくできたりするので面白いですよ。
それではブロック崩しの作り方を1つずつ簡単に見ていきましょう。
プレイヤーとなるパドルを用意する
PONG GAMEと同様に画面に白い矩形を表示させましょう。
パドルをキー操作できるようにする(横か縦1方向のみ移動にする)
普通のブロック崩しは一人用なのでプレイヤーを下側において左右に動かせます。
最近の画面は横長なので横向きにしても構いません。
キー操作は使うライブラリにもよるのですが、簡単に実装できます。
キーの監視処理とかも全部作ろうとすると結構難しいので、キー操作などはゲームライブラリを使って楽しましょう。
球を用意して常に動き続けるようにする
矩形でも構いませんが、球という名前なので丸型にしてもいいでしょう。
ゲームループの中で常に座標が変化するように作れば球は動き続けます。
パドルで球を打ち返せるようにする
最初にパドルを表示していますが、そのままでは当たり判定がなくすり抜けてしまうので
パドルに当たり判定をつけましょう。
当たり判定の作り方はライブラリを使うか、自分で実装する場合を少し説明すると
球とパドルのいる座標と矩形の大きさを取得しておき、
球がパドルの座標+大きさの位置に少しでも触れたら球の動く方向を変化させるという感じに作ります。
こうすることでパドルに球が当たって跳ね返っているかのように見えます。
ここで注意してほしいのが、パドルの座標と大きさをそのまま判定にしてしまうと
めり込んでから球が跳ね返って不自然に見えてしまいます。
解決法は大きく二つあって、パドルそのものより少し大きい判定にしておくか
ぶつかる前に次のループでたまにぶつかるかどうかを計算するという感じです。
ここら辺の感覚は実際に作って見ないとよくわからないと思いますが
ゲームにおいて当たり判定はかなり重要なファクターとなります。
なのでこういった簡単なゲームで慣れておくと、のちに複雑なゲームを作る時に役に立ちます。
最近の有名な3Dゲームなんかも原理的にはほとんど一緒です。
崩す対象のブロックを画面上に配置する
今度はブロック崩しの崩す部分を作りましょう。
ブロックは基本的に動かないので、画面に表示することと
先ほどの当たり判定と当たった時の消える処理を実装するだけなので簡単ですね。
球がブロックに当たるとブロックを消して球を打ち返す
すでに前項で言っちゃいましたが、ブロックに当たり判定を設けて
球が触れた時に消えるという処理を組み込んで、球の方向を逆転させると球が跳ね返ったかのようになります。
機能拡張のためにプレイヤーのステータス配列を作っておく(ライフ保持にも使う)
PONG GAMEと違って一人用のゲームなので拡張しなければ多分つまらないゲームになってしまうため
今後の拡張も兼ねてプレイヤー用の配列を用意しておきましょう。
今回は機能拡張についてはあまり言及しませんがゲームオーバーの判定を作るために
用意した配列にライフの変数をつっこんでおきましょう。 a
デッドラインに弾が当たるとライフを1つ減らす
PONG GAMEは相手のゴール(相手のパドルの後ろ)に球がいくと点数が入っていましたよね。
ブロック崩しでは球を打ち返せなかった時にライフを減るようにします。
全てのライフがなくなったらゲームオーバーにすればOKです。
球を初期位置に戻す
1つライフが減ったら球を初期位置に戻す処理を入れてゲームを再開させましょう。
全てのブロックを崩すとゲームクリアフラグを建てる
ステージ内のブロックを全て崩すことができればゲームクリアという仕組みにしましょう。
これも複数やり方があって、ブロックの数を監視してそれが0になればクリアするか
崩したブロックをカウントして、一定の数になったらクリアという方法もあります。
後者の方が色々応用は効きますね。
例えばブロックの中に壊せないブロックがあったとして
それを監視していたらいつまでたっても壊せないブロックのせいでゲームクリアができません。
後者であればステージごとにクリアするのに必要な数を設定しておけば壊せないブロックの実装とかも用意になります。
一通り機能ができればブロック崩しは完成です。
あとは実際に遊んで見て見た目的におかしな処理がないかのチェックに入ります。
いわゆるデバッグプレイですね。
友達にやってもらったら意外と気づかなかったところも見えてくるので
一人で作って一人で完結するのはオススメできません。
誰かにプレイしてもらってこそのゲーム制作です。
──ブロック崩しの次に作るゲームは何がベストか。
ブロック崩しの作り方を書いておいてなんですが、実は私はまだブロック崩しを作ったことがないんですよね。
なぜブロック崩しの作り方をかけるかというと、ゲーム作りの仕組みをある程度知っているからです。
いきなり難しいゲームを作ろうとしたので、がむしゃらになって調べていたら
何とか作れたりしましたが挫折しまくっています。
ですがその挫折も経験値となってこうやってブロック崩しを作らなくても、
ブロック崩しの作り方がわかるようになります。
逆にブロック崩しの作り方を知っておけば、難しいゲームを作る時にも応用がきくので
私みたいにいきなり難しいゲームを作るのではなくて簡単なゲームから作った方が効率は良いですね。
でもたまにはハードルの高いゲームを作ろうとしたほうがいいこともあります。
簡単なゲームでは出会えない難問が待ち構えていますからね。
もし壁にぶつかったら1つずつ処理を切り分けて実装してみれば案外解決したりもします。
それでは。