第7回 逆引き:プログラムを分解解説 「3.やっぱりスクロールからかな?」

7−3 やっぱりスクロールからかな?

 さて、やはり、一番気になるのは「横スクロール」ではないでしょうか?
横スクロールといっても、このサンプルの場合、結構大胆な動きをしていますね。ま、そのあたりはご勘弁、ということで、ますは、画面の構成を説明しましょう。

ゲームの中心となるスクロール部分は、幅150ピクセル、高さ120ピクセルの範囲です。そして、その中には幅15ピクセル、高さ120ピクセルの短冊状の画像が10枚敷き詰められています。
ちょうど、その様子をあらわすと、こんなイメージですね。

1015 1014 1015 1014 1012 1014 1015 1014 1010 1015

これらの情報は、配列変数 Scrn( )に入っており、左からScrn(1),Scrn(2),・・・・,Scrn(10)といった具合です。
このプログラムでは、変数Scrn()にビットマップのID番号を代入してあります。したがって、1008〜1016の何れかの値が入っていますので、表示には、For 〜 NextとDrawBitmapを使って、
    For i=1 to 10
        DrawBitmap Scrn(i),i*15-10,25
    Next
としています。また、短冊ビットマップの左上の座標は i*15-10 という計算式で与え、(5,25),(20,25),(35,25),・・・と15ピクセル毎に描いています。
変数Scrn()の初期値は、共通コードのInit_Screenというサブルーチンに含まれており、
    For i=1 to 10
        Scrn(i)=1014+Rand()*2
    Next
という部分です。この式だと初期値は、1014か1015の何れかになりますが、ここでは、隕石のないブランクのビットマップが選択されるようにしてあります。
いきなり、ゲームが始まって隕石では面白くありませんからね。

で、いよいよスクロールです。
スクロールをさせるには、いくつかの方法があるのですが、今回は、こんな方法を使ってみました。

    

画面に枠をつけて分かりやすくしてみましたが(カッコの数字はScrn()変数のインデックス番号です。)これを、左に1枠分移動させると、

    

となりますね。移動してしまった分、右端の枠が空いてしまいますが、その他の部分は15ピクセル分のスクロールをしました。
インデックス番号に注目すると、2のものが1へ、3のものが2へ、4のものが3へ、・・・と移動しているのが分かりますね。
一般的な式で表すと、nのものが(n−1)へ、もしくは、(n+1)のものがnへ、となり、これが今回のスクロールの原理なのです。
プログラムでは、
    For i=1 to 9
        Scrn(i)=Scrn(i+1)
    Next
この部分になります。このFor〜Nextのループで、1のものには2が、2のものには3が、3のものには4が、・・・と順に代入されます。
そして、ループの最後は i=9 ですから、9のものには10が入るわけですね。
図では10の位置が空いてしまっていますが、実際は、この時点では9と同じものが入っているはお分かりですね?

さて、次に、この右端の10の位置に新しい画像のインデックスを与えれば、あたかも新しい風景があらわれたように見える筈です。したがって、初期値と同様に乱数を使って設定すれば良い訳ですが、今回は、ちょっと工夫をして、5回スクロールする毎に隕石が出る可能性を与えてみました。
Flg2というグローバル変数を用意し、初期値に5を代入しておきます。そして、1回スクロールするたびにこの値を1つずつ減らして、0になった時に隕石がでる可能性を与えています。
    Flg2=Flg2-1
    If Flg2=0 Then
        Scrn(10)=1008+Int(rand()*9)
        Flg2=5
    Else
        Scrn(10)=1014+Int(rand()*2)
    End If
隕石が出る可能性、ですが、上の乱数式を見ると変数Flg2=0になった時には、Scrn(10)には1008〜1016の何れかの値が入ります。この範囲には、隕石のないブランク画像と、燃料画像も含まれますから、必ず、隕石が出るとは限らないわけです。
一方、通常の時は、1014か1015しかでませんから、隕石は出現しないようになっています。
もし、ゲーム性を上げるならば、得点が進むにつれて、Flg2の値を小さくすれば、隕石の出現確率が上がりますので、難しくすることが出来ます。

そして、これだけでは、1回表示されると、[After]の部分が終わってしまいますので、6−7で説明した SysEventAvailable()を使ったDo〜Loopを使って連続的に表示させているわけです。
    Do Until (SysEventAvailable()=1 And Flg=1) Or Flg3=1


    Loop
ただ、条件には、単純にSysEventAvailable()だけではなく、幾つかの組み合わせになっています。
この辺りは、また後から説明しますが、スクロールの動作が比較的簡単であることが分かったかと思います。
この方法を使えば、縦のスクロールも問題なく処理できますが、仕組みよりも、画像を用意するのが大変ではないかと思います。



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回 逆引き:プログラムを分解解説 「3.やっぱりスクロールからかな?」