第7回 逆引き:プログラムを分解解説 「6.得点と最初と最後とまとめだよ」

7−6 得点と最初と最後とまとめだよ

 いよいよ、残りわずかになりましたね。
では、なんとなく忘れていた得点の処理を説明しましょう。
得点は、Scoreという共通変数を用意して処理しています。表示上は、ラベル(Lbl1021)に表示しています。
NS Basicのラベルコントロールでは、予め予想される最大の表示桁数分を確保しておかなければなりませんでしたね。
ま、このゲームでしたら、6桁も要らないと思いますが、格好をつけて6桁分確保しておきました。

    

これは、IDEで画面のデザイン時にセットしておけば良いですね。
一方、プログラム中では、
    Lbl1021.Label="SCORE:" + Format(Score,"000000")
としています。Format()は、数値などの体裁を整えて文字列として返してくれる関数でしたね。これで、表示部分はOKです。
そして、得点は、1回Do〜Loopが処理されるたびに1点としましたので、
    Score=Score+1
です。6桁も用意して1点ずつというのは、いかがなものかと思いますが、万一、1,000,000点を達成した方がいればご連絡下さい(賞品はありませんが・・・)

さて、後は最初と最後ですね。
このアプリケーションでは、幾つかの共通変数を用意していますが、これらの変数を[Startup]で定義するのは、もう反射的に行ってしまうとして、次に考えるのは、それらの変数の値を初期化するのはどこか?という点です。
例えば、自機の座標Yiは、衝突するたびに初期化すべきですが、自機の数MyShipは、ゲーム開始時に初期化すれば良い変数ですね。
これらを考えると、衝突した後に初期化する変数を集めたサブルーチンと、全ての変数を初期化するサブルーチンの2つを用意すれば便利だろうと思われます。
衝突の所で出てきたInit_Screen()というサブルーチンは、この前者に相当するサブルーチンで、これについては既に説明済みですね。
そして、後者の全ての変数を初期化するサブルーチンとして、Init_All()を用意しました。
Init_Allでは、
    MyShip=2
    Score=0
    Call Init_Screen
と、自機の数、得点を初期化した後、Init_Screenを呼び出していますが、これで、全部の変数が一気に初期化されるわけです。
これは、ゲームが始まる前、つまり、[Startup]と再ゲームの処理の時に使用しています。

ゲームの始まりがあれば、終わりもあるわけで、このゲームオーバーを表すフラグはFlg3という変数でしたね。
そして、自機の残数がない時、Flg3=1となり、ゲームが続行しなくなります。
一方、ゲームが終わってしまっても、イベントは常に処理待ちの状態にありますので、これを利用して、画面をタップすると再度ゲームが始まるようにします。
    If GetEventType()=nsbPenDown Then
        If flg3=0 Then 
            Stop
        Else
            Call Init_All
            Redraw
        End If
        
    End If
イベント処理の中に、画面をタップしたときの処理を入れておけばよいのですが、ゲームが終わっている時は、Init_All()を呼び出して、再度ゲームが始まるようにしました。一方、ゲーム中にタップすると、Stopコマンドによってゲーム自体が終了するようにしておきました。

ふぅ〜、これで、一通りの個別の処理を紹介したわけですが、どうでしょうか?
各々の処理については、特に難しいコマンドを使ったわけではなく、今までに紹介したBASICコマンドの組み合わせで出来ていることがお分かりいただけたでしょうか?
最初に示したプログラムが「なんだか長いなぁ」と思った方でも、ここまで読めば「スクロール」や「移動」などの処理単位を分解して理解することができますので、ちょっと、イメージが変わったのではないでしょうか?

さて、今回のプログラム、長いようでしたが、実際は次の6つの部分に分解することが出来ます。

    

そして、個々の部分では、短いものや長いものがありますが、順を追っていけば難しくない処理単位になっているはずです。
例えば、[After]モジュールの中は、

    

という細かな処理の集まりとして見ることができます。
そして、この細かな1つ1つの処理は、それほど難しいコマンドを使っている訳ではありませんでしたね。
このように、簡単なコマンドが集まって1つのプログラムになっているのですが、では、プログラムがどうして難しいのでしょうか?
それは「流れ」があるからです。

  ある処理をしたら、次にこの処理をして、そして、ある条件ではあの処理をして、そして、この場合は、この条件をチェックして・・・・

このような一連の流れを組み立てるのがプログラミングの難しいところであり、また、醍醐味でもあります。
今回は、簡単なコマンドの集まりでも1つのプログラムになることを紹介する目的でしたので、流れについては説明をしませんが、このプログラムを解読する時も、流れを意識するととても理解しやすいでしょう。(今回のサンプルは、教材用に作りましたので、あまり参考にならないかもしれませんが。)

さて、プログラムの上達法の1つに「改造」があります。例えば、このゲームの自機を5機にするとか、隕石の出る確率を点数が上がる度に大きくするとか、様々な改造の余地があります。最初から作るのはもちろん大変ですが、改造をするには、その部分がどんな処理をしているのか理解しなければ出来ませんので、こちらも結構大変です。
ぜひ、このようなサンプルを使って改造してみてください。




Sub main()

    Global Scrn(10)as Integer   'スクロール表示用(Bmpの番号:1008〜1016)
    Global Yi as Integer        '自機のY座標(段)
    Global Flg as Integer       '連続キー入力防止フラグ
    Global Flg2 as Integer      'カウントフラグ
    Global Flg3 as Integer      'ゲームオーバーフラグ(=1の時、ゲームオーバー)

    Global ReStart as Integer   '再開フラグ
    Global MyShip as Integer    '自機の数
    Global Score as Integer     '得点
    Global FUEL as Integer      '燃料
    
    Call Init_All
    
End Sub

Sub Form1004_after()

    Dim i as Integer
    
    Do Until (SysEventAvailable()=1 And Flg=1) Or Flg3=1
    
        For i=1 to 10
            DrawBitmap Scrn(i),i*15-10,25
        Next
        DrawBitmap 1007,5,Yi*15+25

        Lbl1021.Label="SCORE:" + Format(Score,"000000")
                
        If ReStart=1 Then
            DrawChars "Ready!",65,75
            For i=1 to MyShip 
                DrawBitmap 1020,90+i*11,148
            Next
            DrawLine 5,147,155,147
            Delay 1.5
            ReStart=0
        End If
        
        FUEL=FUEL-1
        DrawLine 5+FUEL,147,155,147,nsbInverted
        
        Score=Score+1
        
        If Yi<1 Or Yi>6 Or FUEL=0 Then
            Call Crush
            Redraw
        End If
        
        If Scrn(1)<1014 Then
            If Scrn(1)-1007=Yi Then
                Call Crush
                Redraw
            End If
        End If
        
        If Scrn(1)=1016 And Yi=6 Then
            FUEL=FUEL+20
            If FUEL>150 Then
                FUEL=150
            End If
            DrawLine 5,147,5+FUEL,147
        End If
        
        For i=1 to 9
            Scrn(i)=Scrn(i+1)
        Next
        
        If Flg=1 Then
            Delay 0.15
        End If
        
        Flg2=Flg2-1
        If Flg2=0 Then
            Scrn(10)=1008+Int(rand()*9)
            Flg2=5
        Else
            Scrn(10)=1014+Int(rand()*2)
        End If
        Yi=Yi+1
        Flg=1
    Loop
    
End Sub

Sub Crush()

    Dim i as Integer
    
    For i=0 to 10
        DrawBitmap 1018,5,Yi*15+25
        Delay 0.1
        DrawBitmap 1019,5,Yi*15+25
        Delay 0.1
    Next
    
    FillRectangle 90+MyShip*11,148,10,10,0,nsbInverted
    MyShip=MyShip-1
    If MyShip<0 Then
        DrawChars "GAME OVER",55,75
        Flg3=1
    Else
        Delay 1.5
        Call Init_Screen
    End If
    
End Sub

Sub Form1004_events()

    Dim theKey as String
    
    Flg=0
    
    If GetEventType()=nsbKeyOrButton Then
        
        theKey=GetKey()
        If theKey=&h1 Or theKey=&h2 Or theKey=&h3 Or theKey=&h4 Then
            SetEventHandled
            Yi=Yi-2
            Redraw
        End If
    End If
    
    If GetEventType()=nsbPenDown Then
        If flg3=0 Then 
            Stop
        Else
            Call Init_All
            Redraw
        End If
        
    End If
    
End Sub

Sub Init_Screen()

    Dim i as Integer
    
    For i=1 to 10
        Scrn(i)=1014+Rand()*2
    Next
    
    Flg=0
    Flg2=5
    Flg3=0
    Yi=3
    ReStart=1
    FUEL=150

End Sub

Sub Init_All()

    MyShip=2
    Score=0
    Call Init_Screen

End Sub


前へ     目次へ

第7回 逆引き:プログラムを分解解説 「6.得点と最初と最後とまとめだよ」