DirectXプログラミング講座 〜Vol19. 【2Dシューティング】ショット(弾)の発射〜

今回はプレイヤーがスペースキーを押すことで、自機から弾を発射するプログラムを作ってみます。


今回のサンプルプロジェクト

コーディング作業

前回のVol18. 【2Dシューティング】自機を動かそうで作成したコードに手を加える形で作業を進めます。赤色で示すコードが前回からの変更点または追加点です。

"fight.abp" の先頭部分のコーディング

弾は一つのシーンの中で無数に発射されるため、それぞれの動きを常に監視しなければなりません。

まずはゲーム内に存在できる(管理可能な)弾の個数をMAX_SHOTS定数に指定します。弾の一つ一つは、CShotオブジェクトとして生成するのですが、それらを総括して管理しなければなりません。ここではpShotsArrayというオブジェクト配列を用意して、複数のオブジェクトを一つの配列で管理できるようにしています。ShotTime及びTempTime_Shotは、スペースキーが長押しされた場合に、弾を一定間隔で発射するためのカウンタとして利用します。

#include "fight.idx"


Dim ScreenX=640 As Long	'ディスプレイの幅  (ピクセル単位)
Dim ScreenY=480 As Long	'ディスプレイの高さ(ピクセル単位)

' TODO: この位置にグローバル変数を定義してください。

Const SCREENBASE_X=140   'ゲーム画面左上のスクリーンX座標
Const SCREENBASE_Y=0     'ゲーム画面左上のスクリーンY座標
Const SCREEN_WIDTH=360   'ゲーム画面の幅
Const SCREEN_HEIGHT=480  'ゲーム画面の高さ

Const MAX_SHOTS=50     '弾の最大数

'DirectInput用
Dim pInKey As *CInputKeyboard

'背景画像
Dim pImage_BackGround As *CImage2D

'キャラクタマップ画像
Dim pImage_CharaMap1 As *CImage2D
Dim pImage_CharaMap2 As *CImage2D

'ショット(弾)を管理する配列
Dim pShotsArray[ELM(MAX_SHOTS)] As *CShot
Dim ShotTime As Long, TempTime_Shot As Long

'自機クラス
Dim pMyPlane As *CPlane

CPlaneのコーディング

自機が弾を発射するためのメンバ関数CPlane::Shotを定義します。自機はあくまでも弾を発射するだけなので、このCPlane::Shot関数の内容は、CShotオブジェクトを生成するだけになります。その後の動作は、CShotオブジェクトに委ねられます。

'---------------
' 自機クラス
'---------------
Class CPlane
    '位置・高さ・幅
    x As Long
    y As Long
    width As Long
    height As Long

    '移動スピード
    speed As Long

    '傾き
    RudderSituation As Single


    '自機が画面からはみ出さないようにチェックする関数
    Sub EreaOutCheck()
        If x-width/2<0 Then
            x=width/2
        End If
        If x+width/2>SCREEN_WIDTH Then
            x=SCREEN_WIDTH-width/2
        End If

        If y-height/2<0 Then
            y=height/2
        End If
        If y+height/2>SCREEN_HEIGHT Then
            y=SCREEN_HEIGHT-height/2
        End If
    End Sub

Public

    'コンストラクタ
    Sub CPlane()
        width=32
        height=32

        '初期位置
        x=SCREEN_WIDTH/2
        y=SCREEN_HEIGHT*0.8

        '初期スピード
        speed=5
    End Sub

    'デストラクタ
    Sub ~CPlane()
    End Sub


    '描画
    Sub Draw()
        Dim TextureX As Long, TextureY As Long
        TextureX=32*(Fix(RudderSituation)+2)
        TextureY=0

        pImage_CharaMap1->DrawStretch(
            x-width/2    +SCREENBASE_X,
            y-height/2   +SCREENBASE_Y,
            width,
            height,

            TextureX,
            TextureY,
            32,
            32)
    End Sub

    '自機を移動させる関数
    Sub MoveUp()
        y=y-speed
        EreaOutCheck()
    End Sub
    Sub MoveDown()
        y=y+speed
        EreaOutCheck()
    End Sub
    Sub MoveLeft()
        x=x-speed
        EreaOutCheck()

        If RudderSituation>-2 Then
            '左方向に移動中は自機の傾きをマイナス値にする
            RudderSituation=RudderSituation-1/speed
        End If
    End Sub
    Sub MoveRight()
        x=x+speed
        EreaOutCheck()

        If RudderSituation<2 Then
            '右方向に移動中は自機の傾きをプラス値にする
            RudderSituation=RudderSituation+1/speed
        End If
    End Sub
    Sub NoMove()
        '移動していないときは自機の傾きを0に近づける
        If RudderSituation<0 Then
            RudderSituation=RudderSituation+1/speed
        ElseIf RudderSituation>0 Then
            RudderSituation=RudderSituation-1/speed
        End If
    End Sub

    Sub Shot()
        '弾を撃つ
        Dim pShot As *CShot

        pShot=New CShot(x,y-width/2)
    End Sub
End Class

弾の管理及びCShotのコーディング

まずは、CShotオブジェクトが生成されたときに呼び出されるAddShot関数、消滅するときに呼び出されるDeleteShot関数を定義します。AddShot関数は、弾を管理するためのオブジェクト配列pShotsArrayに生成直後のCShotオブジェクトを登録する働きをします。DeleteShot関数はその逆で、CShotオブジェクトが破棄されるときにpShotsArrayからそのオブジェクトを排除する働きをします。

'-----------------------
' ショット(弾)の管理
'-----------------------
Sub AddShot(pShot As *CShot)
    Dim i As Long

    For i=0 To ELM(MAX_SHOTS)
        If pShotsArray[i]=0 Then
            pShotsArray[i]=pShot
            Exit For
        End If
    Next
End Sub
Sub DeleteShot(pShot As *CShot)
    Dim i As Long

    For i=0 To ELM(MAX_SHOTS)
        If pShotsArray[i]=pShot Then
            pShotsArray[i]=0
            Exit For
        End If
    Next
End Sub

'--------------
' ショット(弾)クラス
'--------------
Class CShot
    x As Long
    y As Long
    width As Long
    height As Long

    speed As Long

    Sub EreaOutCheck()
        'はみ出しチェック
        If y-height/2<0 Then
            '画面をはみ出したので、自爆させる
            Delete VarPtr(This)
        End If
    End Sub

Public
    Sub CShot(sx As Long, sy As Long)
        width=4
        height=16

        speed=15

        '初期位置
        x=sx
        y=sy

        AddShot(VarPtr(This))
    End Sub

    Sub ~CShot()
        DeleteShot(VarPtr(This))
    End Sub

    '描画
    Sub Draw()
        pImage_CharaMap2->DrawStretch(
            x-width/2    +SCREENBASE_X,
            y-height/2   +SCREENBASE_Y,
            width,
            height,

            6,
            48,
            width,
            height)

        y=y-speed
        EreaOutCheck()
    End Sub
End Class

InputActionProc関数のコーディング

スペースキーが押されたときにCPlane::Shot関数を呼び出すためのコードを記述します。カウンタ変数ShotTime及びTempTime_Shotを活用して、スペースキーが長押しされたときは一定間隔で弾を発射されるようにします。この関数は60FPS(一秒間に60回)で呼ばれるため、ここに示すコードでは一秒間に20回の連射ができるようになっています。

Sub InputActionProc()
    ' TODO: この位置に入力に関するコードを記述してください。
    '       (キーボード、マウス、ジョイパッド、ジョイスティックなどによる入力)

    ' メモ - キャラクタの移動など、状況進行(アクション)を意味するコードを
    '        記述することもできます。

    Dim KeyState[255] As Byte
    pInKey->GetState(KeyState)

    'ESCキーが押されたときは終了する
    If KeyState[DIK_ESCAPE] and &H80 Then
        PostQuitMessage(0)
    End If

    If KeyState[DIK_UP] and &H80 Then
        '方向キー(上)が押されているとき
        pMyPlane->MoveUp()
    ElseIf KeyState[DIK_DOWN] and &H80 Then
        '方向キー(下)が押されているとき
        pMyPlane->MoveDown()
    End If

    If KeyState[DIK_LEFT] and &H80 Then
        '方向キー(左)
        pMyPlane->MoveLeft()
    ElseIf KeyState[DIK_RIGHT] and &H80 Then
        '方向キー(右)
        pMyPlane->MoveRight()
    Else
        '左右キーが押されていないとき
        pMyPlane->NoMove()
    End If

    ShotTime=ShotTime+1
    If KeyState[DIK_SPACE] and &H80 Then
        'スペースキーが押された、弾を発射
        If ShotTime>TempTime_Shot+3 Then
            pMyPlane->Shot()

            TempTime_Shot=ShotTime
        End If
    End If
End Sub

RenderProc関数のコーディング

弾を描画するためのコードを追加します。

Sub RenderProc()
    ' TODO: この位置に描画に関するコードを記述してください。

    Dim i As Long

    '背景を描画
    pImage_BackGround->Draw(
        SCREENBASE_X,
        SCREENBASE_Y,
        SCREEN_WIDTH,
        SCREEN_HEIGHT)

    '自機を描画
    pMyPlane->Draw()

    '弾を描画
    For i=0 To ELM(MAX_SHOTS)
        If pShotsArray[i] Then
            pShotsArray[i]->Draw()
        End If
    Next
End Sub

実行してみよう

スペースキーを押すと、弾の連発ができるようになっているはずです。次回は、敵機を出現させてみます。



講座インデックスへ戻る ©2005 Discoversoft