今回は、ブロック崩しゲームを作ってみようと思います。プロデルに添付されているゲームのサンプルプログラムには、これまで詳しい解説がありませんでした。そこで、このブログにて新作のゲーム作りを通じてゲームプログラミングの方法をご紹介できればと思います。
ブロック崩しは、球とラケットを使ってラケットで球を跳ね返しながら、画面上部にある敷き詰められたブロックを消していくゲームです。当てたときのポイントや効果音など、ゲームらしい機能も盛り込んでいきます。
まずはピンポンゲームを作る
「ブロック崩し」と書いたのに、なぜ「ピンポン」なの?と疑問に思ったかもしれません。実はブロック崩しのゲームの内容を細かく考えると、ブロックを崩すための球とラケットの動きの部分はピンポンとほぼ同じなのです。
まずピンポンゲームを作れば、ブロック崩しの完成に一歩近づきます。
ピンポン作りの作戦
- 画面上で球(円)を動かす
- 球が画面の上下左右に来たら跳ね返す
- マウスで動くラケットを作る
- 球がラケットに当たったら跳ね返す
- 球を取り逃したらミスの効果音を流す
ピンポンゲームで作らなければいけない機能をまとめてみました。このようにゲームはもちろんのこと、何かプログラムを作りたいと思ったときは、やりたいことを分解して小さい目標をいくつか決めながら作ると、作業が進めやすくなります。
ゲームシステム作り
最初に、ゲームシステムの骨組みとなる部品を作っていきます。ゲームのメイン画面では、「キャンバス」部品と「タイマー」種類を使います。このブログでは、パクパクくんのアニメーションを作る時にご紹介しましたので、そちらもご覧下さい。
ゲームの内容は、すべてキャンバス上の図形で表現します。キャンバス上に図形を作ると、その図形の色や大きさを自由に変化させられます。またキャラや敵を動かすために「タイマー」種類を使います。タイマーは、10ミリ秒に設定して、毎回「ゲームを進行する」手順が実行されるようにしておきます。「ゲームを進行する」手順がこのゲームシステムでのメインループに当たります。
また、「ゲームを初期化する」手順を定義しておきます。この手順にはゲーム画面上に表示する図形などを、あらかじめ作っておくための準備プログラムを書きます。
メイン画面を表示する 待機する メイン画面とは ウィンドウを継承する はじめの手順 初期化する ーー貼り付けた部品に対する操作をここに書きます ゲームを初期化する メインタイマーというタイマーを作る メインタイマーの時間になった時の手順は、ゲームを進行する メインタイマーの間隔を10に変える メインタイマーを開始する 終わり 初期化する手順 ーー自動生成された手順です。ここにプログラムを書き加えても消える場合があります この内部領域大きさを{647,485}に変える この内容を「ピンポン」に変える キャンバス1というキャンバスを作る その位置と大きさを{0,0,647,485}に変える そのドラッグドロップを×に変える そのドッキング方向を「全体」に変える 終わり ゲームを初期化する手順 キャンバス1へ円を描いてボール図形とする その位置と大きさは、{20,50,10,10} その線色を「#ff8c00」に変える その太さを3に変える その背景色を「#ffff00」に変える 終わり ゲームを進行する手順 終わり 終わり
壁で跳ね返る球
では、球が画面上を動くアニメーションを作ってみましょう。球は、決められた方向へ直線に進み、ウィンドウの上下左右の隅に当たると跳ね返るようにします。
ここで、球の位置や大きさ、進む方向を保存しておくための「マイボール」種類を定義します。
また、「ゲームを進行する」手順では、マイボールに保存した画面上の位置(横,縦)を、マイボールの進む方向(横方向,縦方向)だけ増やして、球を移動させていきます。これを繰り返すことで、球が動いているように見せることできます。
進む方向が正の数であれば、左/下方向へ進みます。負の数にすると、右/上方向に進みます。ウィンドウの四隅に当たった時は、進む方向の正と負を逆転させて跳ね返るようにします。
次のような球を移動させるプログラムを「ゲームを進行する手順」の中に書いていきます。
ゲームを進行する手順 //球の移動先を計算する Yは、マイボールの縦+マイボールの縦方向 Xは、マイボールの横+マイボールの横方向 //隅に当たると跳ね返る もしYがキャンバス1の高さ-マイボールの高さ以上なら『 マイボールの縦方向は、-マイボールのスピード Y=キャンバス1の高さ-マイボールの高さ』 他でもしYが0以下ならマイボールの縦方向は、マイボールのスピード もしXがキャンバス1の幅-マイボールの幅以上なら『 マイボールの横方向は、-マイボールのスピード X=キャンバス1の幅-マイボールの幅』 他でもしXが0以下ならマイボールの横方向は、マイボールのスピード //球を動かす マイボールの縦は、Y マイボールの横は、X ボール図形の位置と大きさは、{マイボールの横,マイボールの縦,マイボールの幅,マイボールの高さ} キャンバス1を更新する 終わり
「X」「Y」変数には、球が次へ進む位置を計算して入れておきます。球の位置は、現在位置から進む方向の分だけ値を足して計算します。このときに、もしウィンドウの四隅からはみ出る場合には、進む方向を逆転させます。
続いて、プログラムの一番最後に「マイボール」種類を定義するプログラムを書きます。種類には、球の位置や速さ、方角を保存するための種類変数を定義していきます。種類変数名は、「=」を使って初期値を指定できます。
マイボールとは +縦=10 +横=10 +スピード=5 +縦方向=5 +横方向=5 +幅=10 +高さ=10 終わり
実行すると、画面上に球が表示されて、画面上を動きます。
ラケットを動かす
次にピンポンのラケットを表示させてみましょう。ラケットは、マウスで左右に動くようにします。
「マイボール」と同様に、ラケットも「マイラケット」種類を定義して、値を保存しておきます。ここでラケットの大きさを50×30ピクセルに設定します。
マイラケットとは +縦 +横 +幅=50 +高さ=30 終わり
また、ラケットを表示するために、キャンバス上に四角形図形を作ります。「ゲームを初期化する」手順のボール図形に続いて、「ラケット図形」を作ります。
ゲームを初期化する手順 キャンバス1へ円を描いてボール図形とする その線色を「#ff8c00」に変える その太さを3に変える その背景色を「#ffff00」に変える マイボールの縦は、400 マイボールの横は、200 ボール図形の大きさは、{マイボールの幅,マイボールの高さ} キャンバス1へ四角形を描いてラケット図形とする その線色を「#00008b」に変える その太さを3に変える その背景色を「#00bfff」に変える マイラケットの縦は、400 マイラケットの横は、10 ラケット図形の大きさは、{マイラケットの幅,マイラケットの高さ} 終わり
マウスが動いた時のプログラムを書くために、キャンバス1の「~のマウスカーソルが移動した時」の手順を定義します。この手順は、部品上でマウスカーソルが移動した時に実行されるイベント手順です。「メイン画面」種類の末尾に次のようにイベント手順のプログラムを書いておきます。
キャンバス1のマウスカーソルが移動した時の手順 マイラケットの横は、この時の座標(1)-マイラケットの幅/2 ラケット図形の位置は、{マイラケットの横,マイラケットの縦} 終わり
このイベント手順では、マウスカーソルの動きに連動して、ラケットを左右に動かすように指示します。なおマウスカーソルがある座標は、「この時」変数の座標に保存されています。
当たり判定
ゲームに一番重要なのが当たり判定です。ブロック崩しやシューティングゲームでは、自分と敵またはアイテムに接触したかどうかを判断する処理がたくさん必要となります。この判断する処理のことを当たり判定と言います。
//ラケット跳ね返り もしYがマイラケットの縦以上かつYがマイラケットの縦+マイラケットの高さ以下 かつXがマイラケットの横以上かつXがマイラケットの横+マイラケットの幅以下なら もしマイボールの縦方向が0以上なら、Yは、マイラケットの縦 そうでなければ、Yは、マイラケットの縦+マイラケットの高さ マイボールの縦方向は、-マイボールの縦方向 もし終わり
当たり判定では、球とラケットの位置を、横位置(X)と縦位置(Y)でそれぞれに分けて、ラケットと球が重なり合っているかどうか条件判断します。当たり判定のプログラムは、「ゲームを進行する」手順に書いておきます。「ゲームを進行する」手順では、「X」「Y」変数を使っています。これは、球を実際に移動する前に、球が壁やラケットに当たっていないかどうかを判断するために使います。
次の図は、球とラケットの位置関係を、横方向と縦方向それぞれで描いたものです。横方向と縦方向で、緑線が2本の赤線の間に入れば、「もし」の条件が満たされた(つまり当たった)ことになります。「もし」文では、まず一つの目の条件として横方向について球の位置(X)がラケットの左側から右側までの範囲にあるかどうか判断し、次に、縦方向について球の位置(Y)がラケットの上側から下側までの範囲にあるかどうかを判断します。「もし」文で2つの条件が満たされるとき(真)に、ラケットが球に当たったと判定します。
効果音を付けよう
ゲームっぽくするために、当たったり落下した際に点数を付けたり、効果音が鳴るように改良してみましょう。
効果音は、あり合わせのWindowsにある標準の効果音を使います。もちろん探したり作ったりしたWAVEファイル素材を使うこともできます。
プロデルでWAVEファイルを再生させるには「効果音ファイル」種類を使います。次のプログラムでは、球が当たった時の効果音と、ミスをした際の効果音をそれぞれ用意しておきます。
跳ね返り音は、効果音ファイル(「C:\Windows\media\Speech On.wav」)を作ったもの 失敗音は、効果音ファイル(「C:\Windows\media\chord.wav」)を作ったもの
「効果音ファイル」を作ると、CDプレイヤーのように指定したWAVEファイルを何度も再生できるようになります。
跳ね返り音を再生する
「効果音ファイル」種類の「再生する」手順を呼び出すと、指定した効果音が再生されます。
球がラケットに当たった時に「跳ね返り音」の効果音が再生させるようにします。具体的には、先ほどの当たり判定で、当たった時に「再生する」手順を呼び出すようにします。
//ラケット跳ね返り もしYがマイラケットの縦以上かつYがマイラケットの縦+マイラケットの高さ以下 かつXがマイラケットの横以上かつXがマイラケットの横+マイラケットの幅以下なら ・・・・ 跳ね返り音を再生する もし終わり
落下したとき
続けて、球をラケットで取り損ねて画面下に落下した時は、ミスと見なして、「失敗音」の効果音を鳴らすようにしてみます。ピンポンでの壁での跳ね返りの判定部分のプログラムを書き換えて、球が画面の下端に来た際に、失敗音を再生させるようにします。
ゲームを進行する手順 //球の移動先を計算する Yは、マイボールの縦+マイボールの縦方向 Xは、マイボールの横+マイボールの横方向 //壁の跳ね返り もしYがキャンバス1の高さ-マイボールの高さ以上なら マイボールの縦方向は、-マイボールのスピード Y=キャンバス1の高さ-マイボールの高さ 失敗音を再生する 他でもしYが0以下なら マイボールの縦方向は、マイボールのスピード もし終わり ・・・・ 終わり
ブロックを敷き詰める
これでようやくピンポンゲームが完成しました。
このピンポンゲームでも十分遊べるかとは思いますが、さらにこのゲームを改良して、今回の目標であるブロック崩しを作っていきます。
今回は、100×20ピクセルの緑色のブロックを、6列×5行(30個)分だけ敷き詰めます。次のように、列方向と行方向で「繰り返す」文を二重に書く(ネストする)ことで順番にブロックを敷き詰めていきます。敷き詰める際に、ブロックが重ならないように均等に配置するために、行や列に応じてブロック位置を計算するのがポイントです。次のプログラムでは、ブロックとブロックの間に10ピクセルの余白を入れるように配置します。
「ゲームを初期化する手順」の末尾に次のようなプログラムを書きます。
行を1から5まで増やしながら『 列を1から6まで増やしながら『 キャンバス1へ四角形を描いてブロック配列(列,行)とする その位置と大きさは、{(列-1)*110+30,行*30+60,100,20} その背景色を緑色に変える 』ことを繰り返す 』ことを繰り返す
なお、敷き詰めたそれぞれのブロックは、当たり判定やブロックを消すときに必要ですので「ブロック配列」二次元配列に入れておきます。
次の図には、ブロックの位置関係を描きました。数字はピクセル単位で表しています。先ほどのプログラムの「位置と大きさ」設定項目で指定している値は、ウィンドウ上に書いたような配置と対応しています。プログラム中のウィンドウの大きさ、ブロックの数や大きさの設定を調整することで、ゲームの難易度を変えることもできます。
ブロックに球が当たったことを判定する
ブロックは表示できましたが、このままではブロックと球との当たり判定が無いために、球が当たってもブロックを通過してしまいます。ブロックに当たったかどうかの判定は、ラケットの時と同じように縦位置と横位置で条件判定します。注意なのは、すべてのブロックについて一つ一つ当たったかどうかを判定する必要があることです。
・・・・ //ブロック当たり判定 消えた数は、0 行を1から5まで増やしながら『 列を1から6まで増やしながら『 判定ブロックは、ブロック配列(列,行) もし判定ブロックの表示かつYが判定ブロックの縦以上かつYが判定ブロックの縦+判定ブロックの高さ以下 かつXが判定ブロックの横以上かつXが判定ブロックの横+判定ブロックの幅以下なら マイボールの縦方向は、-マイボールの縦方向 跳ね返り音を再生する 判定ブロックの表示は、× もし終わり もし判定ブロックの表示でないなら、消えた数を増やす 』ことを繰り返す 』ことを繰り返す もし消えた数が5*6なら 「クリア!」を表示する メインタイマーを停止する もし終わり ・・・・
ブロックの当たり判定結果、当たった場合は、ブロックの「表示」設定項目を×(偽)にして、ゲーム画面上から消しておきます。また、消したブロックの数を「消えた数」変数にカウントしておき、消えた数が30個となった時点で「クリア!」と表示させて、ゲームを終了するようにします。
スコアを表示する
ここまで来れば、ブロック崩しゲームの完成までもう少しです。
画面上にスコアを表示させて、球でブロックを消した時にスコアをカウントするようにします。 すでに書いたプログラムを書き加えて、スコア表示に対応させていきます。
「スコア」変数
スコアを保存するために「スコア」変数を定義しておきます。スコア変数は、「メイン画面」種類の先頭に書いておくとわかりやすいです。
メイン画面とは
ウィンドウを継承する
+スコア
+ブロック配列
はじめの手順
・・・
スコアラベルを作る
画面上にスコアを表示されるための文字図形部品を貼り付けます。
キャンバス上に文字を表示させるには、キャンバス種類の「文字を描く」手順を使います。「文字を描く」手順を呼び出すと、「キャンパス文字」部品が作られますので、これを「スコアラベル」とします。スコアラベルの設定項目を変えることで、画面に表示するテキストや文字の色や大きさを変えられます。
まずは「ゲームを初期化する」手順の末尾に、スコアラベルを貼り付けるプログラムを書きます。
ゲームを初期化する手順 ・・・ キャンバス1へ「」という文字を描いてスコアラベルとする その位置は、{50,20} そのフォントを「メイリオ」に変える その文字色を赤色に変える その文字サイズを20に変える 終わり
次に、スコアが変わったときに、スコアラベルにスコアを反映させるために「スコアを更新する手順」を定義しておきます。
スコアを更新する手順 スコアラベルの内容は、「[スコア]ポイント」 終わり
次に、「ゲームを進行する手順」手順の当たり判定の部分に、スコアを増減するプログラムとスコアを更新するプログラムを書きます。
具体的には、球がブロックに当たった時に10ポイント, 球がラケット当たった時に1ポイント, 球を取りこぼして画面下に落下したときは-1ポイントとします。
これらのそれぞれの部分に、スコアを増やしたり減らしたりするプログラムと、スコアラベルを更新するプログラムを書いていきます。当たり判定の部分のプログラムを探して、スコアを更新するプログラムを書いていきましょう。
Yは、マイボールの縦+マイボールの縦方向 Xは、マイボールの横+マイボールの横方向 //壁の跳ね返り もしYがキャンバス1の高さ-マイボールの高さ以上なら ・・・ スコアを3だけ減らす スコアを更新する 失敗音を再生する ・・・ もし終わり
//ブロック当たり判定 ・・・ 行を1から5まで増やしながら『 列を1から6まで増やしながら『 もし判定ブロックの表示かつYが判定ブロックの縦以上かつYが判定ブロックの縦+判定ブロックの高さ以下 かつXが判定ブロックの横以上かつXが判定ブロックの横+判定ブロックの幅以下なら ・・・ スコアを10だけ増やす スコアを更新する もし終わり ・・・ 』ことを繰り返す 』ことを繰り返す ・・・
//ラケット跳ね返り もしYがマイラケットの縦以上かつYがマイラケットの縦+マイラケットの高さ以下 かつXがマイラケットの横以上かつXがマイラケットの横+マイラケットの幅以下なら ・・・ スコアを増やす スコアを更新する もし終わり
改良してみよう
これでブロック崩しゲームの基本機能が完成しました。(ぱちぱち
ぜひ完成したゲームを遊んでみましょう。遊んでいるうちに、こうしたいああしたいと思った所もあるかもしれません。ぜひより面白くなるように改良してみましょう。
球の速さをランダムに
球の速さは、5ピクセル/10msになっています。例えば、乱数を使って「マイボールのスピード」をランダムに設定するには、「乱数」手順を使って次のように書きます。
マイボールのスピードは、1~8の乱数
このプログラムを「ゲームを初期化する」手順の末尾に入れることで、ゲームを始めるごとにスピードを毎回変化させることができます。そのほかにも「乱数」手順を使ってブロックの個数や配置を変化させることもできるかもしれません。
図形の変わりに画像を使う
今回は、円図形や四角形図形を使って、球やラケットを描きました。もし絵を描くのが得意な方や、無料の画像素材を持っている場合には、画像を使うこともできます。キャンバスの「画像を描く」手順を使うことで、画像図形をキャンバスに貼り付けることができます。この画像図形には、PNGやJPEG画像を貼り付けられます。
例えば、作成したプログラムと同じフォルダにある「block.png」をブロックの画像に使いたいときには、「ゲームを初期化する」手順のブロックを敷き詰めるプログラムを、次のようなプログラムに書き直します。
行を1から5まで増やしながら繰り返す 列を1から6まで増やしながら繰り返す キャンバス1へ画像を描いてブロック配列(列,行)とする その位置と大きさは、{(列-1)*110+30,行*30+60,100,20} その画像を「block.png」に変える 繰り返し終わり 繰り返し終わり
まとめ
今回は、プロデルで簡単なブロック崩しを作ってみました。
最後に出来上がったプログラムは、140行ほどですが、ゲーム作りに必要な当たり判定など基本的なプログラムの方法をご紹介しました。
このブロック崩しを改良して難易度を変化させたり、画像などを使ってよりオリジナルのゲームに作り上げることもできますので、ぜひチャレンジしてみて下さい。