Silverlight をインストールするには、ここをクリックします*
Japan変更|サイトマップ
MSDN
|MSDN ライブラリ|デベロッパー センター|ダウンロード情報|開発ツール製品|コミュニティ|ご意見・ご要望|サイトマップ
MSDN Home > Student > プログラミング チャレンジ スクエア > 第 8 章 月着陸ゲームを完成させよう

第 8 章 月着陸ゲームを完成させよう


サンプルプログラムのダウンロード (chap8_vb.msi, 815 KB)

※ また、サンプルプログラムは、あらかじめ Visual Basic 2005 Express Edition と同じパソコンにインストールしておいてください。
   設定方法は こちら


この章でやること
・ 月着陸ゲームを完成させます。
・ 今までの章で出てきたコントロールや各種機能を応用してゲームを作ってみます。

第 8 章 月着陸ゲームを完成させよう
ゲーム内で使う変数を用意しよう
[経過時間] のカウント処理を決定しよう
着陸船のタイマーを準備しよう
ゲームを開始する時の処理を設定しよう
着陸船の動きを設定しよう その 1
着陸船の動きを設定しよう その 2
エンジンに点火しよう





健一さんと翔太君、美咲さんの 3 人が、パソコンを前に会話しています。


翔太:いよいよ、最後の章まで来たね。
美咲:第 7 章が結構大変だったから、第 8 章がどんなことになるのかちょっと怖いけど、でも最後だからすごいのが作れそうな気もするわね。
健一:第 8 章は、確かに大変だけど、できあがってみると楽しいと思うよ。
翔太:やだなぁ、脅かさないでよ、健一さん。
健一:大丈夫、ここまでやって来れた君たちなら第 8 章もやりとおせるさ。さあ、第 7 章の疲れも取れたころだろうから、そろそろ第 8 章を始めようか。


健一さんにうながされて、二人は入門マニュアルを開いて、パソコンに向かいました。

それでは、プログラム メニューから Visual Basic 2005 Express Edition を立ち上げて、サンプルファイルフォルダの中の Part8_VB\Part8_Base フォルダにある Part8.sln を開きましょう。そして、[ソリューション エクスプローラ] から、[Form1.vb] を開きます。






翔太:うわー、ずいぶん本格的なデザインだね。
美咲:ロケットと月面の絵がすごくきれい。
健一:最初に、このゲームの簡単なルールを説明しておこう。そうすれば、どういうプログラムなのかがある程度見えてくるはずだ。


このゲームは [START] ボタンを押して開始します。ゲーム開始直後から、画面の一番上に見えている着陸船が月に着陸するために降下してきます。プレイヤーは、できるだけすばやく月に着陸させなければなりません。しかし、着陸船を放置していると、だんだん加速して落下速度が速まり、ついには墜落し爆発炎上してしまいます。そこで、ロケットエンジンを点火して、加速度を弱めます。ロケットエンジンは、[エンジン点火] ボタンを押している間だけ点火されます。画面右上に表示されているのは、上から順に「現在の経過時間」、「今までの最短時間」、「現在の加速度」となっています。経過時間はプレイ中の記録です。最短記録は過去一番早く着陸に成功した際の記録です。「加速度」は落下中の加速度です。月の表面に着陸船がたどり着いたときに、加速度が 0.6 以上だと、着陸船が月の表面に激突してしまいます。


美咲:安全に月に着陸させるのが目的だけど、かといって時間がかかりすぎても駄目なのね。
翔太:これを今から作るのか。何から手をつければいいのかな。
健一:まずはデバッグ ボタンをクリックして、プログラムを動かしてみよう。





翔太:[START] ボタンを押しても何も動かないね。
健一:よし、それじゃデバッグ 画面を終了して、実際にプログラムを作っていこう。




<ゲーム内で使う変数を用意しよう>

健一:今回は、最初に何をやらなければいけないかを整理してから、実際のコードを見ていくことにしよう。
美咲:コードを見ながら機能を考えるんじゃないのね。
健一:今までの応用だからね。具体的なコードを書くことはできなくても、どういう作業が必要かというイメージはできると思うんだ。
翔太:じゃあ、僕からいこうか。まず、ゲームで使う変数を宣言する必要があると思う。
健一:いいね。その調子だよ。
翔太:さっきの説明で、このゲームにはいろいろな機能があることがわかったと思うんだ。特に、加速度や、エンジンのパワー(着陸船を上昇させる力)や、状況に応じて変化する値を持つ項目がたくさんあるから、それを変数にするといいんじゃないかな。そのためには・・・、第 6 章でやったみたいに、最初に変数を宣言するのが一番手っ取り早そうだね。
健一:第 6 章? ああ、イベントに名前をつけてコード エディタを開くんじゃなくて、自分でメニューから開いて書き込んだんだっけ。
翔太:うん。プログラム全体で使うことになりそうな変数が多いからね。
健一:なかなかいいところに目をつけたね。それでは、最初に基本設定から始めよう。まず、コード エディタを開いて、リスト 8-1-1 を入力するんだ。


[表示] メニューの [コード] をクリックして、コード エディタを開いてください。





そして、次のリスト 8-1-1 を「Public Class Form1」の次の行から入力します。


リスト 8-1-1

    ' 加速度を表す変数
    Private Const SpeedLevel As Double = 0.03
    ' 火力(上昇力)を表す変数
    Private Const EnginePower As Double = 0.08
    ' 強度(着地時に加速度が上回ると破壊)を表す変数
    Private Const Strength As Double = 0.6

    ' 加速値を表す変数
    Private Speed As Double = 0
    ' 高度を表す変数
    Private Koudo As Double = 0
    ' エンジンの点火状態を表すフラグ
    Private EngineOn As Boolean = False
    ' 経過時間(ミリ秒)を表す変数
    Private TimerCount As Integer


健一:あとでどの変数が何だったか思い出せるように、コメントも忘れずに入れておくんだよ。
美咲:最初の 3 つは初めて見る書き方だわ。
健一:ああ、そうだったね。Const を使って宣言した場合、値が変化する変数ではなく、いつも決まった数を使う定数として作られるんだ。変数の宣言も重要だけど、加速度や火力などが一定割合で変化するようにしないといけないから、こういった定数の宣言も重要なんだよ。定数として宣言しておけば、いろいろと使い勝手が良くなるからね。
翔太:Boolean は?
健一:これは特別な型の名前で、中身は True か False しかないんだ。このプログラムではエンジンが点火しているかどうかを判断するのに使われる予定なんだよ。
それじゃ、次は時間に関する設定を見ていこうか。




< [経過時間] のカウント処理を決定しよう>

健一:このプログラムでは、時間に関する機能が複数あるけど、まずは画面 デザインにある [経過時間] についての設定から見ていくことにしよう。
美咲:ここには、ゲームを開始してからの時間が表示されている、っていう話だったわね。
翔太:ということは、第 4 章のラーメンタイマーで使った Timer コンポーネントの出番だな。
美咲:コンポーネントを貼り付けて、Tick イベントに名前をつけてコードを入力できる状態にしないと。
健一:うん、それはそうなんだけど、ただイベントの設定を行うだけじゃなくて、コンポーネントやイベントにちゃんと名前をつけておこう。
翔太:名前? そういえば最近作ったサンプルは、みんなあらかじめコントロールなどに名前がついてたけど、本当はああいう名前も自分で決めていいんだっけ。
健一:そう、でもわかりやすい名前にすることを忘れちゃいけないよ。
美咲:ここで決める名前は、Timer コンポーネントの Name プロパティと、Tick イベントのコンボ ボックスに入力するイベント名ね。
翔太:[経過時間] をローマ字にしてもいいけど、それじゃ長すぎるから、普通にゲームの時間で jikan とかでいいんじゃない?
健一:それじゃ時間の特徴がわからないよ。[経過時間] のデジタル時計表示のところをクリックしてごらん。
翔太:あ、名前が ScoreTime になってる。そうか、このゲームでは時間が得点みたいなものなんだ。
健一:そう、ついでにで [ソリューション エクスプローラ] を見てみると、DigitalTimer コントロールを使っていることがわかるはずだ。名前も見た目もラーメンタイマーのときに使ったものと似てるけど、中身はこのサンプル用に作られている。
翔太:なるほど。
健一:ということで、ここは ScoreTime で使う Timer コンポーネントってことで、「ScoreTimer」でどうかな。
美咲:いいと思うわ。コンポーネントの名前が決まったら、Tick イベントの名前も決まったようなものね。
翔太:どうして?
美咲:今まで作ってきたサンプルは、みんな元になったコントロールやコンポーネントの名前からイベントの名前が作られてたはずよ。だから、今回も、「ScoreTimer_Tick」がふさわしいんじゃないかしら。
健一:そうだね。確かにある程度自由に名前をつけられるといっても、それなりに法則性はあるんだ。2 つともわかりやすい名前になったと思うよ。それじゃそれを使ってコードを書いていこう。


デザイナ 画面でツールボックスを開いて、[コンポーネント] にある [Timer] を選択し、画面 デザインの好きな場所にクリックして貼り付けます。すると、デザイナ 画面の下の方に Timer1 という名前で Timer コンポーネントが追加されるので、Timer1 のプロパティ ウィンドウを表示します。





[Name] プロパティをクリックして、既に入力されている「Timer1」という名前を「ScoreTimer」に変更します。

次に、 [イベント] アイコンをクリックしてイベントの一覧を表示し、一覧にある [Tick] の右にあるコンボ ボックスに「ScoreTimer_Tick」と入力して [Enter] キーを押します。すると、リスト 8-2-1 のコードが追加されました。なお、リスト 8-2-1 は、あとで読み返すときにわかりやすいようにコメント文を追加した形で紹介しています。実際に上記の手順でコードを追加した場合、コメントは追加されていませんので、必要に応じて自分で書き加えてください。以後のリストについても同様です。


リスト 8-2-1

    ' ScoreTimer に指定したミリ秒毎に実行される処理
    Private Sub ScoreTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ScoreTimer.Tick

    End Sub


健一:次は、リスト 8-2-1 の「Private Sub ScoreTimer_Tick〜」と「End Sub」の間の行に、リスト 8-2-2 のコードを追加するんだ。


リスト 8-2-2

        ' 経過時間を 10 分の 1 秒進める
        TimerCount = TimerCount + 100
        ' 画面に表示する経過時間を TimerCount にする
        ScoreTime.MilliSecond = TimerCount


翔太:ここでは、TimerCount 変数の値が 100 増えて、ScoreTime コントロールの MiliSecond プロパティに代入されてるね。
健一:このプロパティは文字通り、ミリ秒単位で設定された時間を表示するためのものだ。今回の場合、Tick イベントが 1 度起きるたびに、時間は 100 ずつ進んでいく。1000 分の 100 秒だから、10 分の 1 秒ずつ時間が増えていくことになるんだ。
これで [経過時間] で時間をカウントするための処理が終わった。次は、着陸船のタイマーを準備しよう。




<着陸船のタイマーを準備しよう>

健一:着陸船は、ある一定の間隔で落下速度を加速させる必要がある。そうでないと、スリルが味わえないのと同時に、攻略もできないからね。
美咲:時間の間隔を設定するの?
健一:そう、これも Timer コンポーネントを使うんだ。
翔太:それじゃ、また貼り付けるんだね。


デザイナ 画面でツールボックスを開いて、[コンポーネント] にある [Timer] を選択し、画面 デザインの好きな場所にクリックして貼り付けます。すると、デザイナ 画面の下の方に Timer1 という名前で Timer コンポーネントが追加されます。


翔太:健一さん、また Timer1 というコンポートができちゃったよ。
健一:うん、それで問題ないよ。さっきの Timer1 は名前がもう ScoreTimer に変わってるからね。それより、このコンポーネントもまた Name プロパティを変更しておく必要があるんだ。
翔太:今度は何がいいかな。今回は関連するコントロールはないよね。
健一:強いて言えば、着陸船かな。着陸船は Lander という名前がついてるから。ここも LanderTimer にしておこうか。


Timer1 のプロパティ ウィンドウを開いて、[Name] に「LanderTimer」と入力します。


健一:続けて、時間の感覚を 1/10 秒に設定しておこう。プロパティ ウィンドウの [Interval] で「10」と入力するんだ。


続いて、 [イベント] アイコンをクリックしてイベントの一覧を表示し、一覧にある [Tick] の右にあるコンボ ボックスに「LanderTimer_Tick」と入力して [Enter] キーを押します。





健一:ここまでで、リスト 8-3-1 のコードが追加されたはずだから、確認してみよう。


リスト 8-3-1

    ' LanderTimer に指定したミリ秒毎に実行される処理
    Private Sub LanderTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LanderTimer.Tick

    End Sub




<ゲームを開始する時の処理を設定しよう>

健一:ゲームを開始するには、[START] ボタンをクリックする必要がある。そして、[START] ボタンをクリックしたら、ゲームの状態を初期化しなくてはならない。
美咲:これは、数当てゲームでやった内容ね。
翔太:ボタンをクリックしたら、ってことだから、[START] ボタンのプロパティで Click イベントに設定する必要があるな。
健一:それじゃ、まず Click イベントに名前をつけて、コードを入力できる状態にしよう。


[START] ボタンのプロパティ ウィンドウでイベント一覧を表示し、Click イベントに「btnStart_Click」と入力して、[Enter] キーを押します。


健一:次のリスト 8-4-1 のコードが表示されているはずだ。


リスト 8-4-1

    ' [START] ボタンを押したときの処理
    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click

    End Sub


健一:この「Private Sub btnStart_Click〜」と「End Sub」の間の行にリスト 8-4-2 のコードを続けて書き加えてほしい。


リスト 8-4-2

        ' 着陸船を画面上部に配置する
        picLander.Top = 0
        ' 高度に着陸船の下底に当たる Y 座標を設定する
        Koudo = picLander.Height
        ' 加速値を 0 にする
        Speed = 0
        ' 経過時間を 0 秒にする
        TimerCount = 0
        ' 経過時間の表示を 0 秒にする
        ScoreTime.MilliSecond = 0
        ' [エンジン点火] ボタンを有効化
        btnEngineOn.Enabled = True
        ' [START] ボタンを無効化
        btnStart.Enabled = False
        ' メッセージを消す
        lblMessage.Text = ""


美咲:これが初期化の作業ね。
健一:よし、それじゃ上から順番にみんなで一つずつ説明してみようか。
翔太:じゃ、まずは僕からいくよ。最初の行にある picLander というのは、画面 デザイン上にある着陸船の画像のことだね。これは第 2 章にも出てきた PictureBox コントロールだ。それで、この picLander を表示するための場所を、ここで設定してるんだと思う。Top って、画像の一番上の位置を表わすプロパティだったはずだから、そこを 0 にしているということは、ゲームが始まった時点で、このゲーム画面の一番上の場所に配置するように設定しているみたいだね。
美咲:今度は私の番ね。次に出てくる Koudo は着陸船の高度を表わす変数で、その値には着陸船画像の高さを表わす数値が代入されているようよ。
健一:そうだね。少し補足をしておくと、このゲームの中では、Koudo は画面の中における着陸船の下底部分の高さを表わす変数でもあるんだ。
美咲:下底が一番下に着けばそれが着陸ということだから、この変数の値がゲームの結果を左右するってことね。
健一:次は僕だな。0 を代入している変数の Speed は、加速値を表わしている。この加速値っていうのは、設定された数の分だけ着陸船を移動させるんだ。ちなみに単位はピクセルになっている。
翔太:また僕の番だね。経過時間を表わす TimerCount に 0 を代入して、初期化してる。TimerCount は、ScoreTime コントロールの MilliSecond プロパティに代入する値だから、単位はミリ秒つまり 1/1000 秒単位。ついでに次の行も説明しておくと、ここで、MilliSecond プロパティ に 0 を代入して表示する時間も 0 秒にすることで、ゲームの始まりに備えているようだよ。
美咲:今度は [エンジン点火] ボタンの btnEngineOn コントロールの Enabled プロパティに True を代入してるわ。これでこのボタンを押せるようにしてるのね。
健一:その次の行では、逆に [START] ボタンである btnStart コントロールの Enabled プロパティに False を代入することで、ボタンを押せない状態にしている。つまり、ゲーム中にタイマーが二重に開始しないようにしているというわけだ。
翔太:最後は僕だ。この行では、着陸船が月の表面に到達したときに、着陸できたか衝突してしまったか、その結果に応じてメッセージを表示する lblMessage コントロールの Text プロパティに、空白の文字列を代入している。こうすることで、最初はメッセージが何も表示されていない状態にしてるんだね。
健一:よーし、二人とも何とかついてきてるね。やっぱり今までの章をこなしてきただけのことはあるなぁ。それじゃ、続けて次のリスト 8-4-3 のコードを入力してごらん。


リスト 8-4-3

        ' タイマーを開始
        ScoreTimer.Start()
        LanderTimer.Start()


美咲:これは簡単ね。ScoreTimer と LanderTimer の Start メソッドを実行して、時間の計測を開始しているところだわ。
健一:そのとおり。それじゃ、ここまでできたらデバッグ ボタンを押して、実際の動きを確かめてみよう。





正常に動作すれば、[START] ボタンをクリックすることで、[経過時間] の時間表示が開始します。時間の計測が確認できたら、デバッグ 画面を終了しましょう。なお、今の状態では、時間が 1 分に達すると表示上は 0 からのカウントを繰り返します。これは、DigitalTimer コントロールが秒数以下しか表示しない設定になっているためで、プログラム上は 59 分 59 秒 9 まで計測が行われます。

もしうまく動かない場合には、コード エディタを開いて、コードを確認してください。正しく動作していれば、リスト 8-4-4 のようなコードが表示されるはずです。


リスト 8-4-4

Public Class Form1

    ' 加速度を表す変数
    Private Const SpeedLevel As Double = 0.03
    ' 火力(上昇力)を表す変数
    Private Const EnginePower As Double = 0.08
    ' 強度(着地時に加速度が上回ると破壊)を表す変数
    Private Const Strength As Double = 0.6

    ' 加速値を表す変数
    Private Speed As Double = 0
    ' 高度を表す変数
    Private Koudo As Double = 0
    ' エンジンの点火状態を表すフラグ
    Private EngineOn As Boolean = False
    ' 経過時間(ミリ秒)を表す変数
    Private TimerCount As Integer

    ' ScoreTimer に指定したミリ秒毎に実行される処理
    Private Sub ScoreTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ScoreTimer.Tick

        ' 経過時間を 10 分の 1 秒進める
        TimerCount = TimerCount + 100
        ' 画面に表示する経過時間を TimerCount にする
        ScoreTime.MilliSecond = TimerCount

    End Sub

    ' LanderTimer に指定したミリ秒毎に実行される処理
    Private Sub LanderTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LanderTimer.Tick

    End Sub

    ' [START] ボタンを押したときの処理
    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click

        ' 着陸船を画面上部に配置する
        picLander.Top = 0
        ' 高度に着陸船の下底に当たる Y 座標を設定する
        Koudo = picLander.Height
        ' 加速値を 0 にする
        Speed = 0
        ' 経過時間を 0 秒にする
        TimerCount = 0
        ' 経過時間の表示を 0 秒にする
        ScoreTime.MilliSecond = 0
        ' [エンジン点火] ボタンを有効化
        btnEngineOn.Enabled = True
        ' [START] ボタンを無効化
        btnStart.Enabled = False
        ' メッセージを消す
        lblMessage.Text = ""

        ' タイマーを開始
        ScoreTimer.Start()
        LanderTimer.Start()

    End Sub
End Class




<着陸船の動きを設定しよう その 1 >

健一:タイマーの動きは確認できたね。今度は、着陸船が着陸するまでの動きを設定しよう。まずは、落下に関する動きについてだ。
美咲:さっき用意したけど使ってなかった「Private Sub LanderTimer_Tick〜」と「End Sub」の間の行を使うのね。
健一:まずはリスト 8-5-1 のコードを、この場所に追加しよう。


リスト 8-5-1

        ' 着陸船の画像をエンジン消火状態に設定する
        picLander.Image = My.Resources.Resources.着陸船1
        ' 加速値に加速度を加える
        Speed = Speed + SpeedLevel
        ' 高度に加速値を加える
        Koudo = Koudo + Speed

        ' 着陸船を現在の高度の位置に配置する
        picLander.Top = Int(Koudo) - picLander.Height
        ' 現在の加速値をラベルに表示する
        txtSpeedLevel.Text = (Int(Speed * 100) / 100).ToString()


翔太:最初に着陸船の画像を設定してるみたいだね。
健一:ここで設定しているのは、着陸船のエンジンに点火する前のイメージ画像だよ。このあと、エンジン点火後の画像も当然出てくるんだ。
翔太:その次の 2 つの行は、加速値に定数で設定した加速度の値が加えられて代入している行と、着陸船の高度を表わす変数に、加速値の値が加えられて代入されてる行だ。
健一:この 2 つの行は、LanderTimer の Tick イベントが発生するたびに繰り返し処理される。だから、時間の経過とともに、Speed と Koudo の値は増加していくことになるんだ。ちなみに加速値は加えられる加速度の定数が 0.03 だから、0.03 ずつ増加していることがわかる。
美咲:あら? 高度が増加すると上昇しちゃうんじゃない?
健一:ああ、ごめん、ごめん、説明するのを忘れてた。この Koudo の値は、座標という考え方に基づいて設定されているんだ。プログラミングの世界で座標というのは、X 座標と Y 座標の二つの数値で表されるもので、これは Windows の画面上の位置を決定するために利用される。そして、X 座標と Y 座標の始まりの位置は左上と決まっていて、そこから右に向かって X 座標は値が増えていき、Y 座標は下に向かって値が増えていく。
美咲:下に向かって・・・。じゃあ、今回の Koudo 変数は・・・
健一:そう、Y 座標を使ってるんだ。だから変数の値が増えれば増えるほど、着陸船の高度は下に向かう、というわけなんだよ。ただし、実際の処理では、直接 Koudo 変数の値を使って設定しているんじゃないんだ。座標の値はピクセル単位で指定するから、整数値になる。だから、Koudo 変数の値を Int メソッドによって整数に変換し、そこから着陸船の画像の高さを引いている。すると、上底の Y 座標がわかるから、picLander の Top プロパティに設定できる。このあたり、Y 座標が上から下に向かって増えていることをイメージできないと、少し混乱しそうだから、よく考えてみよう。
翔太:つまりひっくり返して考えればいいんじゃない? つまり、下底の方が Y 軸上では上に来るんだから、そこから着陸船の高さの分の数値を引けばいい、っていうことだよね。
健一:そうだね。そうして、得られた Y 座標を、着陸船の画像を上からどれくらいの位置に表示するかという指定に使っているんだ。そして、最後の行で、txtSpeedLevel の Text プロパティに、加速値を表わす Speed 変数の値を代入することで、加速値を画面に表示している。ちなみに、ここでは小数点第二位以下を切り捨てている。だから、画面でも小数点以下第一位までが表示されているんだ。


ここまでできたら、デバッグ ボタンを押して、実際の動きを確かめてみましょう。[START] ボタンをクリックすると、着陸船の画像が落下し始めますが、月の表面にたどり着くと、そのまま月の画像の裏側に隠れてしまうことを確認します。





このあと、さらに着陸船は完全に隠れてしまい、経過時間の計測や加速度の表示も止まらずに、デバッグ 画面を終了するまでずっと加算され続けます(経過時間は 60 秒で 0 に戻るのは先ほどと同様)。





もしうまく動かない場合には、コード エディタを開いて、コードを確認してください。正しく動作していれば、リスト 8-5-2 のようなコードが表示されるはずです。


リスト 8-5-2

Public Class Form1

    ' 加速度を表す変数
    Private Const SpeedLevel As Double = 0.03
    ' 火力(上昇力)を表す変数
    Private Const EnginePower As Double = 0.08
    ' 強度(着地時に加速度が上回ると破壊)を表す変数
    Private Const Strength As Double = 0.6

    ' 加速値を表す変数
    Private Speed As Double = 0
    ' 高度を表す変数
    Private Koudo As Double = 0
    ' エンジンの点火状態を表すフラグ
    Private EngineOn As Boolean = False
    ' 経過時間(ミリ秒)を表す変数
    Private TimerCount As Integer

    ' ScoreTimer に指定したミリ秒毎に実行される処理
    Private Sub ScoreTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ScoreTimer.Tick

        ' 経過時間を 10 分の 1 秒進める
        TimerCount = TimerCount + 100
        ' 画面に表示する経過時間を TimerCount にする
        ScoreTime.MilliSecond = TimerCount

    End Sub

    ' LanderTimer に指定したミリ秒毎に実行される処理
    Private Sub LanderTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LanderTimer.Tick

        ' 着陸船の画像をエンジン消火状態に設定する
        picLander.Image = My.Resources.Resources.着陸船1
        ' 加速値に加速度を加える
        Speed = Speed + SpeedLevel
        ' 高度に加速値を加える
        Koudo = Koudo + Speed

        ' 着陸船を現在の高度の位置に配置する
        picLander.Top = Int(Koudo) - picLander.Height
        ' 現在の加速値をラベルに表示する
        txtSpeedLevel.Text = (Int(Speed * 100) / 100).ToString()

    End Sub

    ' [START] ボタンを押したときの処理
    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click

        ' 着陸船を画面上部に配置する
        picLander.Top = 0
        ' 高度に着陸船の下底に当たる Y 座標を設定する
        Koudo = picLander.Height
        ' 加速値を 0 にする
        Speed = 0
        ' 経過時間を 0 秒にする
        TimerCount = 0
        ' 経過時間の表示を 0 秒にする
        ScoreTime.MilliSecond = 0
        ' [エンジン点火] ボタンを有効化
        btnEngineOn.Enabled = True
        ' [START] ボタンを無効化
        btnStart.Enabled = False
        ' メッセージを消す
        lblMessage.Text = ""

        ' タイマーを開始
        ScoreTimer.Start()
        LanderTimer.Start()

    End Sub
End Class




<着陸船の動きを設定しよう その 2 >

健一:着陸船が落下する動きまでは作ることができたようだね。でも、月の表面までたどり着いてもそのまま止まらなかったから、今度は着陸したかどうかを判定して、ゲームを終了するようにしよう。
美咲:また新しいイベントを用意するのかしら。
翔太:それは必要ないよ。だって、着陸船の落下状態を設定するコードがあるんだから。その中でやればいいんじゃない?
健一:そうだね。せっかく、「LanderTimer_Tick」があるんだから、これを使わない手はない。それでは、この中の「Koudo = Koudo + Speed」の行の次の行に、リスト 8-6-1 を追加してみよう。


リスト 8-6-1

        ' 地面に達したら、着陸判定
        If Koudo >= pnlSpace.Height + 9 Then

        End If


さらに、この条件分岐の中、つまりリスト 8-6-1 の「If Koudo >= pnlSpace.Height + 9 Then」と「End If」の間の行に、次のリスト 8-6-2 のコードを入力して下さい。


リスト 8-6-2

            ' タイマーを停止
            ScoreTimer.Stop()
            LanderTimer.Stop()


美咲:Koudo 変数の値が条件式に出てくる、ということは、Koudo 変数は重要な意味を持っているようね。この条件式に出てくる pnlSpace.Height は何の値かしら。
健一:pnlSpace は宇宙空間の画像が表示されているエリアの名前だよ。その Height プロパティというのは宇宙空間の画像が表示されているエリアの高さを表わす値、ということになる。
美咲:ということは、宇宙空間の画像の高さの値と Koudo 変数の値を比較しているのね。>= という書き方も初めて見るわ。○○より大きくて、等しい・・・?
健一:これは○○以上、という意味がある。プログラミングの世界では > と = を 一緒にした記号「≧」をそのまま使えないので、こういう書き方をしているんだ。もちろん逆に以下に相当する書き方もある。
翔太:そうすると、この場合は Koudo 変数の値が pnlSpace.Height の値以上の場合ってこと?
健一:そう、宇宙空間の画像の高さは、月面の画像が表示されている位置の Y 座標と同じだよね。だから、Koudo が、宇宙空間の画像の高さ以上だったら、着陸船が月面の画像に到達しているということになる。
翔太:でも、pnlSpace.Height に数値の 9 が加えられているね。
健一:この場合、宇宙空間の画像の高さに 9 を加えたあとの数値と Koudo を比較するのが正しいんだ。なぜなら、この 9 という数値は、着陸船のエンジンが点火された状態の画像において、噴射している炎の長さと同じ数値になる。つまり、着陸船の炎が月の表面に到達しても、着陸したことにはならない、ということがここを見るとわかる。
美咲:この条件式が満たされた場合、この次の行にある「ScoreTimer.Stop()」と「LanderTimer.Stop()」が実行されるわ。これらは Stop メソッドで、ここでようやくゲームが終了することになる。ちなみに、これは、[START] ボタンをクリックしたときのイベント処理の中で記述されていた「ScoreTimer.Start()」と「LanderTimer.Start()」と対になる作業になるわね。
健一:続けて、着陸に成功したか失敗したかも設定しよう。さっきのリスト 8-6-2 に続けて、リスト 8-6-3 を書き込んでほしい。


リスト 8-6-3

           ' 加速値と強度を比較
            If (Speed < Strength) Then

            Else

            End If


翔太:条件分岐の中にまた条件分岐だ。第 5 章の単語帳で苦労したのが懐かしいなぁ。
健一:翔太君、懐かしいなんて言ってないで、「If (Speed < Strength) Then」と「Else」の間の行に、リスト 8-6-4 を書き込んでくれないかな。


リスト 8-6-4

                ' 加速値が強度より小さかったときの処理

                ' 着陸船の画像をエンジン消火状態に設定する
                picLander.Image = My.Resources.Resources.着陸船1
                ' 高度を着陸した状態に設定する
                Koudo = pnlSpace.Height + 9
                ' [エンジン点火] ボタンを無効化
                btnEngineOn.Enabled = False
                ' [START] ボタンを有効化
                btnStart.Enabled = True
                ' 着陸成功時のメッセージを設定
                lblMessage.Text = "着陸成功!!"
                ' 最短時間と経過時間を比較
                If HiScoreTime.MilliSecond > TimerCount Then
                    ' 最短時間より経過時間が早かったら最短時間を更新
                    HiScoreTime.MilliSecond = TimerCount
                End If


健一:とりあえずここまでにしておこうか。あまり一度に入力しても混乱してしまうかもしれないから。
美咲:とりあえず、ってことはまだ続くってこと?
健一:もちろん。だって、「Else」の次の行が空いてるじゃないか。これはこの条件分岐の前半部分に過ぎないんだよ。


この条件分岐はかなり複雑なので、おさらいしながら少しずつ進めていくことにします。まず、リスト 8-6-3 とリスト 8-6-4 によって、条件分岐全体は次のリスト 8-6-5 のようになります。


リスト 8-6-5

        ' 地面に達したら、着陸判定
        If Koudo >= pnlSpace.Height + 9 Then
            ' タイマーを停止
            ScoreTimer.Stop()
            LanderTimer.Stop()
            ' 加速値と強度を比較
            If (Speed < Strength) Then
                ' 加速値が強度より小さかったときの処理

                ' 着陸船の画像をエンジン消火状態に設定する
                picLander.Image = My.Resources.Resources.着陸船1
                ' 高度を着陸した状態に設定する
                Koudo = pnlSpace.Height + 9
                ' [エンジン点火] ボタンを無効化
                btnEngineOn.Enabled = False
                ' [START] ボタンを有効化
                btnStart.Enabled = True
                ' 着陸成功時のメッセージを設定
                lblMessage.Text = "着陸成功!!"
                ' 最短時間と経過時間を比較
                If HiScoreTime.MilliSecond > TimerCount Then
                    ' 最短時間より経過時間が早かったら最短時間を更新
                    HiScoreTime.MilliSecond = TimerCount
                End If
           Else

           End If
        End If


翔太:・・・。ここまで長いと、どうなってるのか想像もつかないよ。
健一:と、思うかもしれないが、実際はそれほどたいしたことをやってるわけじゃないんだ。まず、最初の If で始まる文の条件式を見てごらん。
美咲:加速値を表わす Speed 変数が Strength 変数と比較されているわ。Strength 変数はなんだったかしら・・・
翔太:たしか、着陸船の強度を表わしてる定数だよ。値は 0.6 だったよね。
健一:変数や定数がたくさんあったり、コードが長かったりする場合には、変数のリストをどこか別に用意しておくと便利だよ。それと、もちろん役割がわかりやすい名前にすることも忘れずにね。
翔太:それで、ここでやっているのは・・・、加速値の値が強度の値よりも下回っていれば条件を満たす、という作業みたいだね。
健一:正解! そしてその場合、リスト 8-6-4 のコードが頭から順番に処理されるんだ。
リスト 8-6-4 の内容を見ていくと、まず、着陸船の画像を、エンジンを点火して炎を吹き出している画像から、エンジンを点火していない最初の画像に変更している。
美咲:点火中の画像は終わりってことね。次の行では、さっきの条件分岐で条件式だった「Koudo = pnlSpace.Height + 9」が式として成立しているわ。
健一:つまり、着陸したってことだね。
翔太:そうか! そもそもこれはゲームが終了したあとの処理だから、この時点で加速値が強度より下、っていうことは着陸船は爆発せずに強度を維持したままなんだよね。それに、Koudo、つまり着陸船の高度が宇宙空間の画像の高さに 9 を足した値と一致することで、着陸船の炎を除いた底面が、月の表面に接してる状態になっている。ということはつまり、着陸したってことなんだ。
健一:そう、そして着陸船の画像を、エンジンを点火して炎が吹き出している画像から、エンジンを点火していない最初の画像に変更している。
美咲:[エンジン点火] ボタンの Enabled プロパティに「False」が代入されているのは、ボタンを使えない状態にしてるってこと? [START] ボタンの Enabled プロパティにはその逆に「True」が代入されて使える状態になってるわ。
翔太:画面に表示されるメッセージとして、「着陸成功!!」という文字列が代入されてるね。なんだか、だんだん終わりが近づいてきた感じがするよ。
健一:そうして、最後にもう一度条件分岐だ。「HiScoreTime」というのは、[最短記録] に表示される時間のこと。ゲームによくあるハイスコア、最高得点ってことだね。その MilliSecond プロパティが、経過時間を表わす TimerCount 変数の値よりも大きい場合には、経過時間の値を最短記録に代入する。もしそうでなければ、つまり、経過時間がハイスコアよりも長い時間だったら、「End If」に進んで、着陸判定の前半終了だ。
翔太:ハイスコアの更新ってこういうところでやってるんだ。
健一:さあ、それじゃ一気に後半の着陸判定を片付けるぞ。


リスト 8-6-3 の「Else」の次の行に、リスト 8-6-6 のコードを追加します。


リスト 8-6-6

                ' 加速値が強度より大きかったときの処理

                ' 着陸船の画像を爆発状態に設定する
                picLander.Image = My.Resources.Resources.着陸船3
                ' 高度を着陸した状態に設定する
                Koudo = pnlSpace.Height
                ' [エンジン点火] ボタンを無効化
                btnEngineOn.Enabled = False
                ' [START] ボタンを有効化
                btnStart.Enabled = True
                ' 着陸失敗時のメッセージを設定
                lblMessage.Text = "着陸失敗!!"


翔太:最初に画像を変更してるけど、さっきとは違う画像みたいだね。
健一:これは爆発している画像だね。
翔太:それじゃ失敗したときの処理になるんだ。えーっと、その次の行で、Koudo の設定をまたやっていて・・・、今度は炎の分の 9 が追加されてないんだね。
健一:失敗して月の表面で爆発してるんだからね。
美咲:ボタンの処理はさっきと同じだわ。[エンジン点火] ボタンが使えなくなって、[START] ボタンが使えるようになってる。
翔太:画面のメッセージは「着陸失敗!!」になるんだね。


この後半部分を加えることで、条件分岐全体は、リスト 8-6-7 のようになります。


リスト 8-6-7

        ' 地面に達したら、着陸判定
        If Koudo >= pnlSpace.Height + 9 Then
            ' タイマーを停止
            ScoreTimer.Stop()
            LanderTimer.Stop()
            ' 加速値と強度を比較
            If (Speed < Strength) Then
                ' 加速値が強度より小さかったときの処理

                ' 着陸船の画像をエンジン消火状態に設定する
                picLander.Image = My.Resources.Resources.着陸船1
                ' 高度を着陸した状態に設定する
                Koudo = pnlSpace.Height + 9
                ' [エンジン点火] ボタンを無効化
                btnEngineOn.Enabled = False
                ' [START] ボタンを有効化
                btnStart.Enabled = True
                ' 着陸成功時のメッセージを設定
                lblMessage.Text = "着陸成功!!"
                ' 最短時間と経過時間を比較
                If HiScoreTime.MilliSecond > TimerCount Then
                    ' 最短時間より経過時間が早かったら最短時間を更新
                    HiScoreTime.MilliSecond = TimerCount
                End If
           Else
                ' 加速値が強度より大きかったときの処理

                ' 着陸船の画像を爆発状態に設定する
                picLander.Image = My.Resources.Resources.着陸船3
                ' 高度を着陸した状態に設定する
                Koudo = pnlSpace.Height
                ' [エンジン点火] ボタンを無効化
                btnEngineOn.Enabled = False
                ' [START] ボタンを有効化
                btnStart.Enabled = True
                ' 着陸失敗時のメッセージを設定
                lblMessage.Text = "着陸失敗!!"

           End If
        End If


健一:ここまでできたら、またデバッグ ボタンで実際の動きを確認してみよう。








健一:着陸に失敗するところまで確認できたかな。
翔太:これで問題ないの?
健一:問題ないよ。だって、[エンジン点火] ボタンを押して、加速を調整する機能がまだついてないからね。それよりも、ここではちゃんと月の表面で爆発することが重要なんだよ。それに、時間や加速度の計測も止まってるだろう?
美咲:さっきまではずっと計測しっぱなしだったものね。


もしうまく動かない場合には、コード エディタを開いて、コードを確認してください。正しく動作していれば、リスト 8-6-8 のようなコードが表示されるはずです。


リスト 8-6-8

Public Class Form1

    ' 加速度を表す変数
    Private Const SpeedLevel As Double = 0.03
    ' 火力(上昇力)を表す変数
    Private Const EnginePower As Double = 0.08
    ' 強度(着地時に加速度が上回ると破壊)を表す変数
    Private Const Strength As Double = 0.6

    ' 加速値を表す変数
    Private Speed As Double = 0
    ' 高度を表す変数
    Private Koudo As Double = 0
    ' エンジンの点火状態を表すフラグ
    Private EngineOn As Boolean = False
    ' 経過時間(ミリ秒)を表す変数
    Private TimerCount As Integer

    ' ScoreTimer に指定したミリ秒毎に実行される処理
    Private Sub ScoreTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ScoreTimer.Tick

        ' 経過時間を 10 分の 1 秒進める
        TimerCount = TimerCount + 100
        ' 画面に表示する経過時間を TimerCount にする
        ScoreTime.MilliSecond = TimerCount

    End Sub

    ' LanderTimer に指定したミリ秒毎に実行される処理
    Private Sub LanderTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LanderTimer.Tick

        ' 着陸船の画像をエンジン消火状態に設定する
        picLander.Image = My.Resources.Resources.着陸船1
        ' 加速値に加速度を加える
        Speed = Speed + SpeedLevel
        ' 高度に加速値を加える
        Koudo = Koudo + Speed
        ' 地面に達したら、着陸判定

        If Koudo >= pnlSpace.Height + 9 Then
            ' タイマーを停止
            ScoreTimer.Stop()
            LanderTimer.Stop()

            ' 加速値と強度を比較
            If (Speed < Strength) Then
                ' 加速値が強度より小さかったときの処理

                ' 着陸船の画像をエンジン消火状態に設定する
                picLander.Image = My.Resources.Resources.着陸船1
                ' 高度を着陸した状態に設定する
                Koudo = pnlSpace.Height + 9
                ' [エンジン点火] ボタンを無効化
                btnEngineOn.Enabled = False
                ' [START] ボタンを有効化
                btnStart.Enabled = True
                ' 着陸成功時のメッセージを設定
                lblMessage.Text = "着陸成功!!"
                ' 最短時間と経過時間を比較
                If HiScoreTime.MilliSecond > TimerCount Then
                    ' 最短時間より経過時間が早かったら最短時間を更新
                    HiScoreTime.MilliSecond = TimerCount
                End If

            Else
                ' 加速値が強度より大きかったときの処理

                ' 着陸船の画像を爆発状態に設定する
                picLander.Image = My.Resources.Resources.着陸船3
                ' 高度を着陸した状態に設定する
                Koudo = pnlSpace.Height
                ' [エンジン点火] ボタンを無効化
                btnEngineOn.Enabled = False
                ' [START] ボタンを有効化
                btnStart.Enabled = True
                ' 着陸失敗時のメッセージを設定
                lblMessage.Text = "着陸失敗!!"

            End If

        End If

        ' 着陸船を現在の高度の位置に配置する
        picLander.Top = Int(Koudo) - picLander.Height
        ' 現在の加速値をラベルに表示する
        txtSpeedLevel.Text = (Int(Speed * 100) / 100).ToString()

    End Sub

    ' [START] ボタンを押したときの処理
    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click

        ' 着陸船を画面上部に配置する
        picLander.Top = 0
        ' 高度に着陸船の下底に当たる Y 座標を設定する
        Koudo = picLander.Height
        ' 加速値を 0 にする
        Speed = 0
        ' 経過時間を 0 秒にする
        TimerCount = 0
        ' 経過時間の表示を 0 秒にする
        ScoreTime.MilliSecond = 0
        ' [エンジン点火] ボタンを有効化
        btnEngineOn.Enabled = True
        ' [START] ボタンを無効化
        btnStart.Enabled = False
        ' メッセージを消す
        lblMessage.Text = ""

        ' タイマーを開始
        ScoreTimer.Start()
        LanderTimer.Start()

    End Sub
End Class




<エンジンに点火しよう>

健一:さあ、いよいよ最後だ。今までずっと着陸船が落下するのを止められなかったけど、エンジンに点火できるようにすれば着陸船を無事に着陸させることもできるようになる。さあ、ここで二人に質問だ。ここでまずやるべきことはなんだろう?
翔太:えーっと・・・ [エンジン点火] ボタンの設定、ではなくて。
美咲:そうね。せっかくエンジンの点火状態を表わす変数 EnginOn を宣言してるんだから、あれを使って初期化しないと。
健一:よくできました! でも、せっかく変数を宣言してあるから、っていうのはちょっと違うけどね。この変数は元々そのために用意してあるんだから。
翔太:初期化するための変数?
健一:そう。エンジンに点火する、という機能は、[エンジン点火] ボタンをクリックしている間だけ有効になっていなければならないんだ。その間は、着陸船の画像も変更されるから、エンジンが有効かどうかを判断することはとても重要な処理の一つなんだよ。
美咲:なるほど。
健一:さあ、それじゃ早速初期化のコードを入力しよう。書き込む場所はどこだかわかるかな?
翔太:ゲーム全体の初期化を行ってるところでいいんじゃないの?
健一:そうだね。あそこに書いておけばいい。リスト 8-4-2 で最後に書いた「lblMessage.Text = ""」のすぐ次の行に書くようにしよう。そうすれば、すべて初期化が済んだあとで、時間の計測が始まることになる。


リスト 8-7-1 のコードを、リスト 8-4-2 の最後の行に追加します。


リスト 8-7-1

        ' エンジンを消火状態にする
        EngineOn = False


翔太:最初はゲーム開始前だから、エンジンの点火は無効状態のままなんだね。
健一:次のコードも、今までのコードの中に追加するんだ。


リスト 8-6-1 にある「If Koudo >= pnlSpace.Height + 9 Then」の 1 つ前の行に、リスト 8-7-2 のコードを追加します。


リスト 8-7-2

        ' エンジン点火中なら加速度を引く
        If (EngineOn = True) Then
            ' 着陸船の画像をエンジン点火状態に設定する
            picLander.Image = My.Resources.Resources.着陸船2
            ' 加速値から火力を引く
            Speed = Speed - EnginePower
        End If


健一:これは、エンジンに点火している状態のときに、着陸船の画像を炎を出している画像に変更し、さらに加速値の値を減らしてるんだが、減らす値というのが、EnginePower の値になっている。
美咲:EnginePower は・・・、エンジンの火力を表わす定数ね。つまり、加速値から 0.08 が引かれているんだわ。
健一:ちなみに、加速値が増えるときの定数は?
翔太:えーっと、0.03 だったかな。
健一:そう。つまり落下速度を緩めるエンジンの力は、加速する力よりも大きいということになる。微調整が難しいゲームになりそうだね。


健一:さて、いよいよ [エンジン点火] ボタンを押したときの処理だ。今回は、通常の Click イベントとは違うイベントを使う必要がある。
美咲:どうして?
健一:それは、[エンジン点火] ボタンを押している間は、エンジンの点火が有効になっていなければならないからなんだ。Click イベントは、クリックした瞬間に発生するイベントであって、クリックしたままという場合には使うことができない。そこで、[MouseDown] と [MouseUp] というイベントを使う必要がある。


[エンジン点火] ボタンのプロパティ ウィンドウを開いて、イベントの一覧で [MouseDown] という項目をクリックします。





翔太:説明が書いてあるよ。「マウス ポインタがコンポーネント上にあり、マウス ボタンが押されたときに発生します。」だって。
健一:つまり、マウスの矢印カーソルがボタンの上にあって、クリックされている状態のときに発生するイベント、ということになるんだ。それじゃ、実際に、[MouseDown] の右にあるコンボ ボックスに「btnEngineOn_MouseDown」と入力して [Enter] キーを押してみよう。





リスト 8-7-3 のコードが追加されました。


リスト 8-7-3

    ' [エンジン点火] ボタンを押したときの処理
    Private Sub btnEngineOn_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnEngineOn.MouseDown

    End Sub


健一:続けて、「Private Sub btnEngineOn_MouseDown〜」と「End Sub」の間の行にリスト 8-7-4 のコードを追加しよう。


リスト 8-7-4

        ' エンジンを点火状態にする
        EngineOn = True


翔太:これは、エンジンを点火状態にしているんだね。つまり、マウスで [エンジン点火] ボタンがクリックされている間はエンジンが点火されているってことになるわけだ。
健一:また [エンジン点火] ボタンのプロパティ ウィンドウに戻って、今度は [MouseUp] イベントを見てみよう。





美咲:今度は、マウス ボタンが離されたとき、って書いてあるわね。つまり、[エンジン点火] ボタンがクリックされた状態になったら発生するイベントってことかしら。
健一:今度は [MouseUp] の右にあるコンボ ボックスに「btnEngineOn_MouseUp」と入力して [Enter] キーを押してみよう。





リスト 8-7-5 のコードが追加されました。


リスト 8-7-5

    ' [エンジン点火] ボタンを放したときの処理
    Private Sub btnEngineOn_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnEngineOn.MouseUp

    End Sub


健一:続けて、「Private Sub btnEngineOn_MouseUp〜」と「End Sub」の間の行にリスト 8-7-6 のコードを追加しよう。


リスト 8-7-6

        ' エンジンを消火状態にする
        EngineOn = False


翔太:今度は、エンジンを点火していない状態に設定しているんだね。
健一:さあ、これでコードの書き込みはすべて終了だ。デバッグ ボタンをクリックして、動きを確認してみよう。








翔太:やった! 無事に着陸できたよ。
美咲:私にはちょっと難しいなぁ。
健一:そういう時は、加速値に加える加速度の定数の値や、強度の定数の値を変えてみるといい。エンジンの火力を変えると微調整が利くようになって、ゲームがやりやすくなるかもしれないね。


実際にゲームを何度か繰り返し試してみて、最短時間が更新されたり、着陸の成功、失敗したりといった一連の動作をすべて確認しましょう。

なお、このゲームの最短時間の記録は、プログラムを動かしている間だけ最新のものが表示されています。プログラムを一旦終了してしまうと、その記録は保存されずに無くなってしまいます。デバッグ ボタンを押して、プログラムをまた始めようとすると、最初の最短時間設定(59 秒 9)が表示されるので、好記録が出た場合には自分で他のファイルなどに手作業で記録を残しておく必要があります。

また、[エンジン点火] ボタンを押し続けることで、現在の加速度が減少していきますが、加速度が 0 を過ぎるとマイナス表示になって、着陸船が上昇します。画面の一番上を越えて画面の外まで着陸船が飛んでいってしまうこともありますので、[エンジン点火] ボタンの押しすぎには気をつけてください。画面の外まで飛んでいった着陸船は、加速度がプラスに転じると再び落下してきます。

もしうまく動かない場合には、コード エディタを開いて、コードを確認してください。正しく動作していれば、リスト 8-7-7 のようなコードが表示されるはずです。


リスト 8-7-7

Public Class Form1

    ' 加速度を表す変数
    Private Const SpeedLevel As Double = 0.03
    ' 火力(上昇力)を表す変数
    Private Const EnginePower As Double = 0.08
    ' 強度(着地時に加速度が上回ると破壊)を表す変数
    Private Const Strength As Double = 0.6

    ' 加速値を表す変数
    Private Speed As Double = 0
    ' 高度を表す変数
    Private Koudo As Double = 0
    ' エンジンの点火状態を表すフラグ
    Private EngineOn As Boolean = False
    ' 経過時間(ミリ秒)を表す変数
    Private TimerCount As Integer

    ' ScoreTimer に指定したミリ秒毎に実行される処理
    Private Sub ScoreTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ScoreTimer.Tick

        ' 経過時間を 10 分の 1 秒進める
        TimerCount = TimerCount + 100
        ' 画面に表示する経過時間を TimerCount にする
        ScoreTime.MilliSecond = TimerCount

    End Sub

    ' LanderTimer に指定したミリ秒毎に実行される処理
    Private Sub LanderTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LanderTimer.Tick

        ' 着陸船の画像をエンジン消火状態に設定する
        picLander.Image = My.Resources.Resources.着陸船1
        ' 加速値に加速度を加える
        Speed = Speed + SpeedLevel
        ' 高度に加速値を加える
        Koudo = Koudo + Speed
        ' エンジン点火中なら加速度を引く
        If (EngineOn = True) Then
            ' 着陸船の画像をエンジン点火状態に設定する
            picLander.Image = My.Resources.Resources.着陸船2
            ' 加速値から火力を引く
            Speed = Speed - EnginePower
        End If

        ' 地面に達したら、着陸判定
        If Koudo >= pnlSpace.Height + 9 Then
            ' タイマーを停止
            ScoreTimer.Stop()
            LanderTimer.Stop()
            ' 加速値と強度を比較
            If (Speed < Strength) Then
                ' 加速値が強度より小さかったときの処理

                ' 着陸船の画像をエンジン消火状態に設定する
                picLander.Image = My.Resources.Resources.着陸船1
                ' 高度を着陸した状態に設定する
                Koudo = pnlSpace.Height + 9
                ' [エンジン点火] ボタンを無効化
                btnEngineOn.Enabled = False
                ' [START] ボタンを有効化
                btnStart.Enabled = True
                ' 着陸成功時のメッセージを設定
                lblMessage.Text = "着陸成功!!"
                ' 最短時間と経過時間を比較
                If HiScoreTime.MilliSecond > TimerCount Then
                    ' 最短時間より経過時間が早かったら最短時間を更新
                    HiScoreTime.MilliSecond = TimerCount
                End If
            Else
                ' 加速値が強度より大きかったときの処理

                ' 着陸船の画像を爆発状態に設定する
                picLander.Image = My.Resources.Resources.着陸船3
                ' 高度を着陸した状態に設定する
                Koudo = pnlSpace.Height
                ' [エンジン点火] ボタンを無効化
                btnEngineOn.Enabled = False
                ' [START] ボタンを有効化
                btnStart.Enabled = True
                ' 着陸失敗時のメッセージを設定
                lblMessage.Text = "着陸失敗!!"
            End If
        End If
        ' 着陸船を現在の高度の位置に配置する
        picLander.Top = Int(Koudo) - picLander.Height
        ' 現在の加速値をラベルに表示する
        txtSpeedLevel.Text = (Int(Speed * 100) / 100).ToString()

    End Sub

    ' [START] ボタンを押したときの処理
    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click

        ' 着陸船を画面上部に配置する
        picLander.Top = 0
        ' 高度に着陸船の下底に当たる Y 座標を設定する
        Koudo = picLander.Height
        ' 加速値を 0 にする
        Speed = 0
        ' 経過時間を 0 秒にする
        TimerCount = 0
        ' 経過時間の表示を 0 秒にする
        ScoreTime.MilliSecond = 0
        ' [エンジン点火] ボタンを有効化
        btnEngineOn.Enabled = True
        ' [START] ボタンを無効化
        btnStart.Enabled = False
        ' メッセージを消す
        lblMessage.Text = ""
        ' エンジンを消火状態にする
        EngineOn = False

        ' タイマーを開始
        ScoreTimer.Start()
        LanderTimer.Start()

    End Sub

    ' [エンジン点火] ボタンを押したときの処理
    Private Sub btnEngineOn_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnEngineOn.MouseDown

        ' エンジンを点火状態にする
        EngineOn = True

    End Sub

    ' [エンジン点火] ボタンを放したときの処理
    Private Sub btnEngineOn_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles btnEngineOn.MouseUp

        ' エンジンを消火状態にする
        EngineOn = False

    End Sub

End Class


翔太:・・・とうとう、最後までたどり着いちゃったね。
美咲:うん、でも始める前はこんなに楽しいなんて思ってもみなかった。
翔太:それに、こんなにプログラミングのことがわかるようになるなんて。
健一:わかるって言っても、まだまだプログラミングの世界は奥が深いんだ。この入門マニュアルに書いてないようなことがたくさんあるんだよ。僕だって、まだ勉強してる最中だからね。
翔太:でもこれだけ詳しいんだし、すごいプログラマだと思うな。僕も勉強して、健一さんみたいになりたいな。
健一:いやいや、まだまだだよ。今日だって、君たちと一緒にサンプルを作るために、がんばって予習してきたんだから。
美咲:よーし、私もがんばって勉強してみようかしら。実は、第 2 章の画像を加工するプログラムでは、もっといろいろなことができそうな気がしてるの。
翔太:僕は、この月着陸ゲームで、着陸船を左右に動かしてみたいな。そうしたら、もっと面白くなりそうじゃない?
健一:それじゃ、今度はもう少し上級者向けの本を持ってきてあげるよ。それを使ってみんなで一緒に勉強しよう。


どうやら、翔太君と美咲さんは、プログラミングをもっと勉強したくなったようですね。皆さんは、第 8 章まで進んできていかがでしたか? いくらサンプルが用意されているからといっても、どうしても抵抗を感じてしまう人もいると思いますが、今回この資料で紹介した Visual Basic 2005 Express Edition は、誰でも簡単にプログラミングの世界を体験できる開発環境として、とても優れた機能を持っています。ぜひこの機会に、翔太君たちのようにプログラミングの世界に興味を持ってくれることを願いつつ、この教材もここで終了とさせていただきます。

それでは、また機会があればどこかでお会いしましょう。


Top of Page Top of Page Top Page プログラミング チャレンジ スクエアへ戻る

Microsoft