ゲーム実装で身に付くプログラミング 7

タイトル画面を表示する

タイトル画面を表示する

デバッグすると実行ファイル(bin¥debug¥net10.0-windows¥colorVBForms.exe)が書き出されます。そこからの相対パスで「Title.png」画像を読み込みます。「title」メソッドでゲーム状態をタイトル画面にし、マウスが押されたら「onClick2Start」関数を呼び出します。この関数ではマウスが押された時のトリガーを解除し、「init」関数でゲーム状態をメインループにします。図2のようにタイトル画面では中央にタイトル画像を表示します。

ところで、先に「Go」言語で解説した際、プロパティやメソッドの頭文字をprivateは小文字、publicは大文字にしたので、C#やVisual Basic.NETでも同様にしました。ただし、C#やVB.NETではメソッド名の頭文字はアクセス修飾子に関わらず大文字にするのが一般的なようです。

図2:タイトル画面を表示

・サンプルコード「Forms1.vb」ファイル

Imports System.Drawing
Imports System.Runtime.Intrinsics
Imports System.Windows.Forms

Partial Public Class Form1
    Inherits Form
    Private img(3) As Image
    Enum GAME_STATE
        TITLE
        MAIN_LOOP
        GAME_OVER
        STAGE_CLEAR
    End Enum
    Private gameState As GAME_STATE

    Public Sub New()
        InitializeComponent()
        Me.DoubleBuffered = True ' チラつき防止
        ' 画像読み込み
        img(3) = Image.FromFile("../../../images/Title.png")
        title()
    End Sub

    Private Sub title()
        gameState = GAME_STATE.TITLE
        AddHandler Me.MouseDown, AddressOf onClick2Start
    End Sub

    Private Sub onClick2Start(sender As Object, e As MouseEventArgs)
        RemoveHandler Me.MouseDown, AddressOf onClick2Start
        init()
    End Sub

    Private Sub init()
        gameState = GAME_STATE.MAIN_LOOP
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        MyBase.OnPaint(e)
        Select Case gameState
            Case GAME_STATE.TITLE
                Dim x As Integer = Me.ClientSize.Width \ 2 - img(3).Width \ 4
                Dim y As Integer = Me.ClientSize.Height \ 2 - img(3).Height \ 4
                e.Graphics.DrawImage(img(3), x, y)
        End Select
    End Sub
End Class

【サンプルコードの解説】
「Form1」コンストラクタでタイトル画像をimg(3)プロパティに読み込みます。
「title」メソッドでゲーム状態を「GAME_STATE.TITLE」にし、マウスが押されたら「onClick2Start」メソッドをトリガーします。
onClick2Startメソッドでマウスが押された時のトリガーを解除します。
「init」メソッドでゲーム状態を「GAME_STATE.MAIN_LOOP」にします。
「OnPaint」メソッドでタイトル画面で画像を表示します。

色ブロックを表示する

「Sprite.vb」ファイルをcolorVBFormsフォルダ内に「Add」→「New Item」メニューで新規作成します。タイトル画面でマウスを押したらゲーム画面に遷移し、色ブロックが複数表示されて移動し、画面外に出たら削除されましたね(図3)。

図3:色ブロックを表示

・サンプルコード「Sprite.vb」ファイル

Imports System.Drawing
Imports System.Windows.Forms

Public Class Sprite
    Public X As Single
    Public Y As Single
    Public VX As Single
    Public VY As Single
    Public Img As Image
    Public Col As Integer
    Private rand As New Random()

    Public Sub New(clientSize As Size, img() As Image, col As Integer)
        X = rand.Next(0, clientSize.Width)
        Y = rand.Next(0, clientSize.Height)
        VX = rand.Next(-4, 4)
        VY = rand.Next(-4, 4)
        Me.Col = col
        Me.Img = img(col)
    End Sub

    Public Function Update(clientSize As Size) As Boolean
        X += VX
        Y += VY
        ' 画面外なら削除
        If X > clientSize.Width OrElse
            Y > clientSize.Height OrElse
            X + Img.Width < 0 OrElse
            Y + Img.Height < 0 Then
            Return True
        End If
        Return False
    End Function
End Class

【サンプルコードの解説】
「Sprite」クラスで色ブロック1個ずつの座標(X,Y)プロパティ、移動量(VX,VY)プロパティ、色「Col」プロパティ、画像データ「Img」プロパティ、乱数「rand」プロパティを宣言します。
Spriteクラスの「New」コンストラクタでランダムな座標、移動量、ブロックの色、画像をセットします。
「Update」メソッドで色ブロックを移動し、画面外に出たらTrueを戻り値で返します。そうでなければFalseを返します。

・サンプルコード「Forms1.vb」ファイル

Imports System.Drawing
Imports System.Runtime.Intrinsics
Imports System.Windows.Forms

Partial Public Class Form1
    Inherits Form
    Private timer As New Timer()
    Private sprites As New List(Of Sprite)()
    Private rand As New Random()
    Private img(3) As Image
    Private stage As Integer = 2
    Enum GAME_STATE
        TITLE
        MAIN_LOOP
        GAME_OVER
        STAGE_CLEAR
    End Enum
    Private gameState As GAME_STATE

    Public Sub New()
        InitializeComponent()
        Me.DoubleBuffered = True ' チラつき防止
        ' 画像読み込み
        img(0) = Image.FromFile("../../../images/0.png")
        img(1) = Image.FromFile("../../../images/1.png")
        img(2) = Image.FromFile("../../../images/2.png")
        img(3) = Image.FromFile("../../../images/Title.png")
        title()
    End Sub

    Private Sub title()
        gameState = GAME_STATE.TITLE
        RemoveHandler timer.Tick, AddressOf update
        timer.Stop()
        RemoveHandler Me.MouseDown, AddressOf onMouseDown
        AddHandler Me.MouseDown, AddressOf onClick2Start
    End Sub

    Private Sub onClick2Start(sender As Object, e As MouseEventArgs)
        RemoveHandler Me.MouseDown, AddressOf onClick2Start
        init()
        ' タイマー(10fps)
        timer.Interval = 100
        AddHandler timer.Tick, AddressOf update
        timer.Start()
        AddHandler Me.MouseDown, AddressOf onMouseDown
    End Sub

    Private Sub init()
        gameState = GAME_STATE.MAIN_LOOP
        sprites.Clear()
        ' 初期生成
        For i As Integer = 0 To stage * 3 - 1
            sprites.Add(New Sprite(Me.ClientSize, img, i Mod 3))
        Next
    End Sub

    Private Sub update(sender As Object, e As EventArgs)
        For i As Integer = sprites.Count - 1 To 0 Step -1
            If sprites(i).Update(Me.ClientSize) Then
                sprites.RemoveAt(i)
            End If
        Next
        Me.Invalidate() ' 再描画
    End Sub

    Protected Overrides Sub OnPaint(e As PaintEventArgs)
        MyBase.OnPaint(e)
        Select Case gameState
            Case GAME_STATE.TITLE
                Dim x As Integer = Me.ClientSize.Width \ 2 - img(3).Width \ 4
                Dim y As Integer = Me.ClientSize.Height \ 2 - img(3).Height \ 4
                e.Graphics.DrawImage(img(3), x, y)
            Case GAME_STATE.MAIN_LOOP
                For Each s As Sprite In sprites
                    e.Graphics.DrawImage(s.Img, s.X, s.Y)
                Next
        End Select
    End Sub

    Private Sub onMouseDown(sender As Object, e As MouseEventArgs)
    End Sub
End Class

【サンプルコードの解説】
Form1クラスで「sprites」プロパティをSpriteクラスのリストとして宣言します。
img(0)~img(2)に赤緑青の色ブロックの画像を読み込んでインスタンスを代入します。
onClick2Startメソッドでタイマー(Timerクラス)を使って100ミリ秒ごと(10FPS)にupdateメソッドを呼び出します。titleメソッドではそれらを停止し、マウスが押された時の処理のトリガーを付け替えます。
「init」メソッドで、Spriteクラスのインスタンスとして色ブロックをstageの数値の3倍(3色分)追加します。
updateメソッドで色ブロックを移動し、画面外で削除し、再描画します。
OnPaintメソッドでゲーム状態がメインループ時、色ブロックを表示します。

【コラム】アートは最後の砦

大西拓磨さんという芸術家が「人と面白くコミュニケーションできないから、面白いものを作るしかない。アートは最後の砦」みたいに言っていました。まさに筆者もそんな感じです。

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored