情報授業実践記録
理科目次へ

ブロック崩しゲームを創る

宮崎県立宮崎西高等学校
溝上俊彦

 
1.なぜブロック崩しなのか

 私はこれまで,プログラムを書くということを意識的に避けながら授業をしてきていた。それは,教科「情報」の指針が,当初,フローチャートを使ってアルゴリズムを教え,プログラムには触れていなかったことにある。しかし,それは例えれば,ロボットの設計図だけ書いて,実際に動くロボットをつくらない授業をしていたことと同じだった。
 「コードを書く」ということの教育的意味を,偶然,私は生徒たちから教えられた。ある時,EXCELのグラフを動かす簡単な「コードを書く」という授業を試しにやることにした。「難しい」という反応なら,それっきりにするつもりだった。ところが,彼らはそのボタン一つでグラフが動き出す授業を拍手と興奮で迎えてくれたのだ。
 そうだった…。その時私は,学生の頃初めてFORTRANのコードを書いて,Hello!とコンピュータにあいさつされたときのなんとも言えない気持ちを思い出していた。コンピュータが知的な生命体のように感じたあの気持だ。

  

 生徒たちは,コンピュータが開発され,1枚のチップにその心臓部分(CPU)が収められるようになったばかりの頃を知らない。計算機センターに収まっていた巨大なコンピュータが自分のものになるという驚き,それは,多くの理系人間にとって衝撃的な出来事だった。当時,そのチップで作られたマシンはマイコンと呼ばれ,特に1977年アップル社の出したApple II は,みんなの憧れの的だった。ソフトは,BASICというプログラミング言語だけで,付録に簡単なゲームがついていた。コンピュータは計算機であると思っていた理系人間にとって,「ゲームができる」ことにその時気づいた人は多い。そこに新しい地平が見えていたのだ。その付録のゲームこそ「Little Brick Out」つまりブロック崩しゲームである。
 この授業実践は,Excelを使って,ブロック崩しゲームをつくる実践である。
 授業は,まずボールを動かす,そしてボールを壁で反射させる,という一つ一つの動きを理解しながらプログラミングしていく。そして,この授業の最終的な目標を,このブロック崩しゲームを参考に「自分のオリジナルゲームを開発する」ということにおいている。
 生徒たちは,当然,プログラミングに必要な考え方を学ぶことになるが,それ以上に,コードを書いて簡単なゲームをつくったという経験が,彼らにコンピュータという道具を改めて考え直すきっかけになると思っている。
 以下,プログラムの要点を述べ,最後にプログラムを添付した。解説はExcel2007を使っているが,他のバージョンと大きく変わるところはない。

 
2.ブロック崩しの準備

(1) 表の座標を数字にする。

 ここでは,まずプログラムコードが書きやすいようにExcelのほうの準備をしておく。
 OfficeボタンからExcelのオプション→数式を選び, R1C1参照形式を使用する をチェックしておく。Excel2003以前のバージョンだとワークシートのツールメニューから オプション→全般→R1C1参照形式にする をチェックする。
 R1C1形式に対して通常の形式をA1形式という。R1C1形式にするとExcelの横の欄がアルファベットから数字になり,セルの場所を(x,y)座標として表すことができ,より生徒が受ける数学の感覚に近くなる。

(2) セキュリティチェックを外す設定

 開発というメニューから「マクロのセキュリティ」を開き,すべてのマクロが有効になるようにチェックを入れておく。また,開発者向けのマクロ設定にもチェックを入れておく。

(3) 作業画面を出す

 開発というメニューからVisual Basic Editorを開き,画面にエディターのウインドウが出てくるようにしておく。このエディターにプログラムコードを書いていく。出てこない時は,挿入→標準モジュール を選ぶ。プロジェクトの該当するシートをダブルクリックしてもよい。実際の作業では,このVisual Basic のウインドウとExcelのウインドウを同時に表示するように,生徒たちには指導している。

 
3.ブロック崩しの現場づくり

 ブロック崩しのExcel側をまずは作ってみる。最初は下図のように,まるごと同じように作ってみる。特に,数値の座標が違うと,プログラムコードがこの例とずれてしまい厄介なことになる。右の「スタート」や「ブロック」のボタンはまだ作る必要はない。
 グラフは,散布図にして,ボールの位置(x,y)に丸いボール,ラケットの位置に横長の長方形,ブロック位置に18個のブロックが正方形の点として示されるようになっている。

 また,縦と横の座標軸は,最小値0,最大値10で固定しておく。これは大事な部分で,実際にボールが動き出した時,座標を固定していないと困ったことになる。
 あとは,ラケットは右矢印→キーを押すと右に,左矢印←キーを押すと左に行くようにすればよい。また,ボールがラケットや,ブロック,壁にあたったとき反射するようにすればいいわけだ。さらには,ブロックにボールが当たったらブロックがなくなってしまうようにする必要がある。
 これらをプログラミングしていくわけである。
 実際の授業では,まずボールだけを描かして,ボールがまっすぐ進むプログラムを自分で作ってみる。次のステップでは,グラフの壁で反射するようにプログラムを書くというように,1時間1時間ゆっくり進んでいく。

 
4.プログラムの全体構成

 添付したプログラムは,Ballというメインプログラム(Subプロシージャ)が変数宣言文の次に書かれている。(Sub Ball() からEnd Subまでに相当する部分)。
 このBallというプログラムは,ボールをまっすぐ進ませようとする。
 そして,途中,次に進むべきほんのちょっと先の( 秒後の)位置には次の3つの問題がないか判断させる。

 (1)壁はないか,もしあったら反射して向きを変える。
 (2)ブロックはないか。もしあったら反射して向きを変え,かつブロックを崩す(消す)
 (3)ラケットはないか。もしあったら反射する。

 つまり, 秒間の1ステップの移動ごとにすべてを判断させるという,まあ,ボールにとっては厄介なことをさせていることになる。ブロックにいたっては18個もあり,その1個ずつの反射と消去を判断する必要がある。
 また,メインプログラムには,DoEventsというコードが途中書かれてあって,何か他の指示が来た場合,それに従わなければならない。
 それらのプログラムはプライベートサブプログラムとして,このBallプログラムの下に書かれてある。各々は,線で区分けしてあるので,わかりやすいだろう。
 授業では,これらのコードをいっぺんに書かせることはせず,進度に合わせて,プログラムを加えていくようにしている。
 このように構造化しておくと,同じプログラムの中にいっぺんに書くより,ディバッグも容易で,生徒がどこまでは動くというチェックをするのにも便利である。さらには,自分のオリジナルのゲームを作り始める時,アルゴリズムがばらばらになって収拾がつかなくなることもこれによってかなり防げるだろう。

 
5.ボールを動かす

 それでは,グラフの中のボールを動かすことにしよう。いよいよプログラムコードを書く。
 グラフをつくったところがSheet1なら,右図のSheet1のところをダブルクリックしてみる。右にプログラムを書くための白い紙が出てくる。
 そこに図のようなプログラムを半角文字で書いてみる。

 ファンクションキーF8でプログラムをチェックすることができる。間違いなく書けていたら,DO 〜 LOOP の中を何回もループする様子が分かるはずだ。DoEvents はほかの命令が来たらそっちのほうをやれということで,これによってLOOPからの脱出が行われる。
 うまくいけそうだったら,Visual Basic のウインドウにある をクリックしてボールが動くかどうか確かめてみる。止める時は■だ。(一時停止は だ)
 ここではBASICの特徴をしっかり説明する。例えば,「x=x+vx*dt というコードはそれまでの x の値に vx×dt をくわえたものを,新しいxの値としなさい。」という意味で,数学的なイコールではないことを解説する。すると x=Cells(3, 7) は,セル(3,7)の値を,xという名前の箱に入れるという意味であることを理解できるようになる。
 ここでは,ボールの等速運動がどのように表わされているかを読み取らせる。

 
6.ボールを壁で反射させる

 ボールを壁で反射させるにはどうしたらいいのだろうか。まず,あたらしいプログラムを書くために,変数の宣言文をSub Ball()プログラムの上に出しておく(コピー&ペースト)。なおSubプログラムのことをSubプロシージャと呼んでいる。
 このボールの反射の仕方をパソコンに教えてやるために,メインのBallプログラムの次に「ボールの壁反射」のプログラムを書く。そして,メインのBallプログラムのDo-Loopの中に,次のコードを書いておく。

Call ボールの壁反射()

壁での反射プログラム
9.65≦ x だったら vx の向きを180度変えて-vx にする。
 ボールが次の位置に移動するときに,常にこの「ボールの壁反射」のプログラムに途中立ち寄り,反射の有無を判断するようにしてやる。
 「ボールの壁反射」の中では,次のようにして壁の反射を判断させ,向きを変えさせる。図と一緒に見るとわかりやすいだろう。
 ボールは 秒後のことしか知らない。そのときの座標の(x, y)が,壁に入っているかどうかをIF文で判断させる。もし,壁があったら左右の壁だったら,速さの x 成分を逆向き(つまり-1をかけてやればよい)にする。上下の壁に迫っていたら,速さのy成分vyを逆向きにする。
 コードで書くと vx=-vx と vy=-vy となる。もちろんこれも等式ではなくvx の符号(向き)を変えたものを,新しくvxとしなさい。という意味である。
 
7.ブロックを崩す

 さあ,それではいよいよブロックを崩してみよう。このブロックにボールが当たると,ボールは反射し,しかもブロックはその場所から無くならないといけない。どうすればこんなプログラムが書けるのだろう。
 ブロックとボールの衝突には一次元配列の手法を使う。ブロック0からブロック17までの位置座標を,その一般形であるブロックn の位置座標b_px(n)とb_py(n)としてやるのだ。ブロックnについてプログラムを書いてやれば,あとはその中で,nを0から17までひとつずつ増やして回してやればいい。こうすれば,すべてのブロックについていちいちプログラムを書く手間が省けるというわけだ。
 b_px(n)とはn番目のブロックのポジションのx座標という意味で,もっと簡単に書いても何らかまわない。
 ただ,この一次元配列はブロック100個までOKで単精度の数ですよと,初めの変数宣言をしておく。
 あとは反射の仕方である。これは,壁反射と基本的には同じだが,条件は複雑になる。
 ブロックの4つの辺の周辺に近づいているかどうかの判断になり,また,反射の向きもどちらにするかを決める必要がある。プログラムを見て研究していただきたい。
 
8.ブロックがなくなる

 それでは,ボールが当たったらブロックがなくなるようにするにはどうしたらいいのか。これは,授業では生徒たちに1時間考えさせ,いろんなアイデアを出してもらう。その中でおそらく出てくるだろうアイデアが,ボールがブロックに当たったと判断したら,ブロックの位置を,グラフの外にしてしまう方法である。このプログラムでは,縦軸の座標12のところにブロックを上げてしまうようにしている。もちろん,生徒たちには,この部分は授業で考えさせるため見せない。
 プログラムが,人のアイデアの塊であること,そしてそれこそが,「著作権」という権利につながることを学ぶ大事な場所にもなっている。
 
9.ラケットを動かす

 いよいよこのブロック崩しの中に,ラケットを持って入るにはどうしたらいいのか。突然,パソコンの中に入るのも失礼だ。ここでは,その挨拶の言葉がある。

Private Declare Function GetAsyncKeyState Lib "User32.dll" (ByVal vkey As Long) As Long

何の意味かは不明だが,「ごめんなさい。ちょっとキーボードを使わせてくださいねっ」というような意味だ。たぶん・・・。こいつを変数の宣言文のあるプログラムの最初に追加しておく。

If GetAsyncKeyState(37) < 0 Then
Rk = Rk - 0.3
End If

 キーボードの→矢印の番号は37(←矢印は38)となっていて,このコードを訳すと,←矢印キーを押した(<0)なら,ラケットのx座標の値を0.3だけ減らしなさい。ということになる。これで,ラケットを動かすことができる。

 
10.スタートボタンの挿入

 最後に,実際にゲームをするには,スタートボタンやリセットボタンがあったほうがずっと便利だ。まずスタートボタンをどうやって作るのか。
 「開発」のタブをクリックしてコントロールの中の「挿入」からActiveXコントロールを選び,その中のボタンをクリックして,そのままエクセルのグラフの横に広げてはりつける。 Excelの2003までのバージョンの場合,「表示」の「ツールバー」の中に「コントロールツールボックス」というところがある。これをクリックすると同様のものが出てくる。
 そのボタンを右クリックすると「コードの表示」が出てくるので,それを選んで,そのボタンが意味するコードを書く。
 ボタンの名前は,ボタンを右クリックで「プロパティ」を選びその中の「Capton」にわかりやすい名前を書いておく。
 ためしにゲームのスタートとストップのボタン,もう一つは,ブロックのボタン(これを押すとブロックが元の位置に再現される)の2つのコマンドボタンをつくってみた。また,ボールの速さを3段階に変えるスクロールバーをつくった。まずはその通りコードを打ち込んでほしい。参考になるだろう。
 
11.最後に

 プログラムを説明することは難しい。これを読んでいる先生にもいろんな方がいて,多少コードを書いたことがある方なら,寝転がって読んでもらえるだろう。マニアックなところはほとんどない。しかし,さっと見ただけで閉じてしまう方もいるだろう。「情報もこんなマニアックな方向にいきたがる人もいるんだよねえ。」と呟きながら・・・。

 だいたい,僕自身,物理の研究で,大学でちょっとコードを書いたことがあるぐらいである。

 この程度のプログラムで,生徒たちは色んな工夫をして,オリジナルの作品を作ってくれる。昨年の生徒の作品の中には,重力場の中で,バスケットボールをするゲームをつくったものもいる。生徒のほうがずっと頭がいい。それを知るのも,この授業の面白さのひとつかもしれない。

教育用ブロック崩しゲーム  mizogami


Private Declare Function GetAsyncKeyState Lib "User32.dll" (ByVal vkey As Long) As Long

Dim bContinue As Boolean
Dim vx As Single
Dim vy As Single
Dim dt As Single
Dim x As Single
Dim y As Single
Dim Rk As Single
Dim n As Integer
Dim b_px(100) As Single
Dim b_py(100) As Single
Dim b_vx(100) As Single
Dim b_vy(100) As Single


Sub Ball()
 dt = Cells(9, 3)
 vx = Cells(6, 3)
 vy = Cells(6, 4)
 x = Cells(3, 7)
 y = Cells(3, 8)
 Rk = Cells(3, 11)
  bContinue = True
  CommandButton1.Caption = "STOP"
 Do
  Calculate
  x = x + vx * dt
  y = y + vy * dt
  Cells(3, 3) = x
  Cells(3, 4) = y
  Call ボールの壁反射
  Call ブロック崩し
  Call ラケット
  DoEvents
  Loop While bContinue = True
End Sub


Private Sub ボールの壁反射()
  Select Case Cells(3, 3).Value
Case Is >= 9.65
vx = -1 * vx
Case Is <= 0.35
vx = -1 * vx
End Select

Select Case Cells(3, 4).Value
Case Is >= 9.65
vy = -1 * vy
Case Is <= 0.35
vy = 0
End Select
End Sub


Private Sub ブロック崩し()
For n = 0 To 17
b_px(n) = Cells(6 + n, 7)
b_py(n) = Cells(6 + n, 8)
If y > b_py(n) - 0.75 And y < b_py(n) + 0.75 Then
If x < b_px(n) + 0.45 And x > b_px(n) - 0.45 Then
vy = -1 * vy
Cells(6 + n, 8) = 12
Else
End If
Else
End If
If x > b_px(n) - 0.75 And x < b_px(n) + 0.75 Then
If y < b_py(n) + 0.45 And y > b_py(n) - 0.45 Then
vx = -1 * vx
Cells(6 + n, 8) = 12
Else
End If
Else
End If
Next n
End Sub


Private Sub ラケット()
If GetAsyncKeyState(37) < 0 Then
Rk = Rk - 0.3
End If
If GetAsyncKeyState(39) < 0 Then
Rk = Rk + 0.3
End If
Cells(3, 11) = Rk
If Cells(3, 4) > 1.5 Then
ElseIf Cells(3, 3) > Rk + 1 Then
ElseIf Cells(3, 3) < Rk - 1 Then
Else
vy = -1 * vy
End If
End Sub


Private Sub CommandButton1_Click()
If bContinue = True Then
bContinue = False
CommandButton1.Caption = "START"
Else
Call Ball
End If
End Sub


Private Sub CommandButton3_Click()
For n = 0 To 8
Cells(6 + n, 8) = 9
Next n
For n = 0 To 8
Cells(15 + n, 8) = 8
Next n
End Sub


Private Sub ScrollBar1_Change()
Cells(6, 3) = ScrollBar1.Value
Cells(6, 4) = ScrollBar1.Value
End Sub