素人がゲームプログラム作成に挑戦
ゲームを買うお金がないから、ゲームを作るというゲームに挑戦!言語はVisual Basic(VB)をメインにC++、C#、Javaは参考程度
Latest Entries
- --------
- カテゴリ : スポンサー広告
- コメント : -
- トラックバック : -
15パズルを作ってみる その11
- ジャンル : コンピュータ
- スレッドテーマ : Visual Basic
15パズルを作ってみる その10の続きです。
今までの15パズルはプログラムを起動した瞬間からゲームスタートとなっていました。今回はそこをマウスクリックによりゲームスタートするように改造しておきました。
マウスクリックによりゲームが開始すると時間と手数をカウントしていきます。
以上で要望のあった時間と手数のカウント表示を追加したプログラムが完成となります。
今までの15パズルはプログラムを起動した瞬間からゲームスタートとなっていました。今回はそこをマウスクリックによりゲームスタートするように改造しておきました。
マウスクリックによりゲームが開始すると時間と手数をカウントしていきます。
Public Class GameClass
Dim _img As Bitmap '画像
Dim _iRect() As Rectangle '矩形配列
Dim _bList As List(Of Integer) 'パズル順番リスト
Dim cid As Integer 'マウスクリックされたリストのインデックス
Dim cFlg As Boolean 'マウスクリックフラグ
Dim gFlg As Boolean 'ゲームクリアフラグ
Dim sFlg As Boolean 'ゲーム開始フラグ
Dim sTime As Double 'ゲーム開始時間
Dim stFlg As Boolean 'ゲーム開始時間セットフラグ
Dim kTime As Double 'ゲーム経過時間
Dim jikan As String '画面表示時間
Dim cCnt As Integer '手数カウント
Public Sub New() 'コンストラクタ
Me.Init() '初期化メソッド
End Sub
Public Sub Init() '初期化独自メソッド
Dim i As Integer = 0 '矩形配列インデックス
sFlg = False 'ゲーム未開始状態にする
gFlg = False 'ゲーム未完成状態にする
_img = New Bitmap(My.Resources.fifteenpuzzle01) '画像の読み込み
_iRect = New Rectangle(15) {} '矩形配列の作成
For y As Integer = 0 To 3 '矩形配列に矩形データを追加
For x As Integer = 0 To 3
_iRect(i) = New Rectangle(x * 100, y * 100, 100, 100) '矩形領域を計算&保存
i += 1 '矩形配列インデックスを加算
Next
Next
_bList = New List(Of Integer) 'ブロックリストの作成
For j As Integer = 0 To 15 '順番を0から15の順で追加
_bList.Add(j)
Next
End Sub
Public Sub gStart()
Dim n As Integer '乱数が生成した数を保存
Dim rnd As Random = New Random() 'シャッフル用乱数
Dim tmp As List(Of Integer) = New List(Of Integer) 'バックアップ用リスト
sTime = 0 'ゲーム開始時間をリセット
stFlg = False 'ゲーム開始時間スタートフラグをリセット
cCnt = 0 '手数をリセット
For j As Integer = _bList.Count - 1 To 0 Step -1 'ブロックリストをランダムに並び替え
n = rnd.Next(_bList.Count) '乱数を作成
tmp.Add(_bList(n)) 'ブロックリストから乱数のデータをバックアップ
_bList.RemoveAt(n) 'ブロックリストからデータを削除=重複させないため
Next
_bList = tmp 'バックアップをコピー
End Sub
Public Sub Update(ByVal nowTime As Double) '変更処理
Dim jflg As Boolean = False '順番判定フラグ
If gFlg = False Then 'ゲーム未完成状態なら
If sFlg = True Then 'ゲームがスタートしていたら
If stFlg = False Then 'ゲーム開始時間を設定していなければ
sTime = nowTime '今の時間を設定
End If
stFlg = True 'ゲーム開始時間設定完了
kTime = nowTime - sTime '時間差を求める
End If
If cFlg Then 'マウスクリックフラグがTrueなら
If cid - 4 >= 0 Then 'クリックされたブロックの上にブロックが存在するなら
If _bList(cid - 4) = 15 Then 'クリックされたブロックの上が空ブロックなら
_bList(cid - 4) = _bList(cid)
_bList(cid) = 15
End If
End If
If cid Mod 4 <> 0 Then 'クリックされたブロックの左にブロックが存在するなら
If _bList(cid - 1) = 15 Then 'クリックされたブロックの左が空ブロックなら
_bList(cid - 1) = _bList(cid)
_bList(cid) = 15
End If
End If
If cid Mod 4 <> 3 Then 'クリックされたブロックの右にブロックが存在するなら
If _bList(cid + 1) = 15 Then 'クリックされたブロックの右が空ブロックなら
_bList(cid + 1) = _bList(cid)
_bList(cid) = 15
End If
End If
If cid + 4 < 16 Then 'クリックされたブロックの下にブロックが存在するなら
If _bList(cid + 4) = 15 Then 'クリックされたブロックの下が空ブロックなら
_bList(cid + 4) = _bList(cid)
_bList(cid) = 15
End If
End If
cFlg = False 'クリックフラグを降ろす
For i As Integer = 0 To _bList.Count - 1 '順番リスト内をチェック
If _bList(i) <> i Then '順番どおりの番号が入っていなければ
jflg = True '順番通りではなかった
End If
Next
If jflg = False Then 'すべてをチェックした結果、順番どおりに入っていたら
gFlg = True 'ゲーム完成フラグを立てる
End If
End If
End If
End Sub
Public Sub Draw(ByVal g As Graphics) '描画処理
Dim i As Integer = 0 '順番リストのインデックス番号
Dim bid As Integer '空ブロックの入っている順番リストインデックス
Dim myFont As Font
If sFlg = False Then
myFont = New Font("HG丸ゴシックM-PRO", 90, FontStyle.Regular, GraphicsUnit.Pixel)
g.DrawString("スタート", myFont, Brushes.Orange, 5, 150)
Else
For y As Integer = 0 To 3
For x As Integer = 0 To 3
g.DrawImage(_img, x * 100, y * 100, _iRect(_bList(i)), GraphicsUnit.Pixel)
i += 1
Next
Next
For x As Integer = 1 To 3 '縦線を表示
g.DrawLine(Pens.Blue, x * 100 - 1, 0, x * 100 - 1, 400)
Next
For y As Integer = 1 To 3 '横線を表示
g.DrawLine(Pens.Blue, 0, y * 100 - 1, 400, y * 100 - 1)
Next
bid = _bList.IndexOf(_bList.Count - 1) '空ブロックのインデックスを検索
g.FillRectangle(Brushes.Black, (bid Mod 4) * 100, (bid \ 4) * 100, 100, 100)
jikan = New TimeSpan(0, 0, kTime).ToString '時間表示用
myFont = New Font("HG丸ゴシックM-PRO", 20, FontStyle.Regular, GraphicsUnit.Pixel)
g.DrawString(jikan, myFont, Brushes.Orange, 0, 0)
If gFlg = True Then 'ゲーム完成状態なら
myFont = New Font("HG丸ゴシックM-PRO", 100, FontStyle.Regular, GraphicsUnit.Pixel)
g.DrawString("クリア!", myFont, Brushes.Orange, 0, 100)
myFont = New Font("HG丸ゴシックM-PRO", 50, FontStyle.Regular, GraphicsUnit.Pixel)
g.DrawString("手数:" & cCnt, myFont, Brushes.Orange, 100, 200)
End If
End If
End Sub
Public Sub MouseClick(ByVal x As Integer, ByVal y As Integer) 'マウスクリック処理
If sFlg = False Then
sFlg = True 'ゲーム開始
Me.gStart()
Else
If gFlg = False Then 'ゲーム未完成状態なら
Dim px, py As Integer
cCnt += 1
px = x \ 100 'クリックされたX座標からXブロック番号を求める
py = y \ 100 'クリックされたY座標からYブロック番号を求める
cid = px + 4 * py '2つのブロック番号から1次元配列インデックスを求める
cFlg = True 'マウスクリックフラグをTrue
Else 'ゲームクリアなら
Me.Init() 'ゲームの初期化
End If
End If
End Sub
End Class
Dim _img As Bitmap '画像
Dim _iRect() As Rectangle '矩形配列
Dim _bList As List(Of Integer) 'パズル順番リスト
Dim cid As Integer 'マウスクリックされたリストのインデックス
Dim cFlg As Boolean 'マウスクリックフラグ
Dim gFlg As Boolean 'ゲームクリアフラグ
Dim sFlg As Boolean 'ゲーム開始フラグ
Dim sTime As Double 'ゲーム開始時間
Dim stFlg As Boolean 'ゲーム開始時間セットフラグ
Dim kTime As Double 'ゲーム経過時間
Dim jikan As String '画面表示時間
Dim cCnt As Integer '手数カウント
Public Sub New() 'コンストラクタ
Me.Init() '初期化メソッド
End Sub
Public Sub Init() '初期化独自メソッド
Dim i As Integer = 0 '矩形配列インデックス
sFlg = False 'ゲーム未開始状態にする
gFlg = False 'ゲーム未完成状態にする
_img = New Bitmap(My.Resources.fifteenpuzzle01) '画像の読み込み
_iRect = New Rectangle(15) {} '矩形配列の作成
For y As Integer = 0 To 3 '矩形配列に矩形データを追加
For x As Integer = 0 To 3
_iRect(i) = New Rectangle(x * 100, y * 100, 100, 100) '矩形領域を計算&保存
i += 1 '矩形配列インデックスを加算
Next
Next
_bList = New List(Of Integer) 'ブロックリストの作成
For j As Integer = 0 To 15 '順番を0から15の順で追加
_bList.Add(j)
Next
End Sub
Public Sub gStart()
Dim n As Integer '乱数が生成した数を保存
Dim rnd As Random = New Random() 'シャッフル用乱数
Dim tmp As List(Of Integer) = New List(Of Integer) 'バックアップ用リスト
sTime = 0 'ゲーム開始時間をリセット
stFlg = False 'ゲーム開始時間スタートフラグをリセット
cCnt = 0 '手数をリセット
For j As Integer = _bList.Count - 1 To 0 Step -1 'ブロックリストをランダムに並び替え
n = rnd.Next(_bList.Count) '乱数を作成
tmp.Add(_bList(n)) 'ブロックリストから乱数のデータをバックアップ
_bList.RemoveAt(n) 'ブロックリストからデータを削除=重複させないため
Next
_bList = tmp 'バックアップをコピー
End Sub
Public Sub Update(ByVal nowTime As Double) '変更処理
Dim jflg As Boolean = False '順番判定フラグ
If gFlg = False Then 'ゲーム未完成状態なら
If sFlg = True Then 'ゲームがスタートしていたら
If stFlg = False Then 'ゲーム開始時間を設定していなければ
sTime = nowTime '今の時間を設定
End If
stFlg = True 'ゲーム開始時間設定完了
kTime = nowTime - sTime '時間差を求める
End If
If cFlg Then 'マウスクリックフラグがTrueなら
If cid - 4 >= 0 Then 'クリックされたブロックの上にブロックが存在するなら
If _bList(cid - 4) = 15 Then 'クリックされたブロックの上が空ブロックなら
_bList(cid - 4) = _bList(cid)
_bList(cid) = 15
End If
End If
If cid Mod 4 <> 0 Then 'クリックされたブロックの左にブロックが存在するなら
If _bList(cid - 1) = 15 Then 'クリックされたブロックの左が空ブロックなら
_bList(cid - 1) = _bList(cid)
_bList(cid) = 15
End If
End If
If cid Mod 4 <> 3 Then 'クリックされたブロックの右にブロックが存在するなら
If _bList(cid + 1) = 15 Then 'クリックされたブロックの右が空ブロックなら
_bList(cid + 1) = _bList(cid)
_bList(cid) = 15
End If
End If
If cid + 4 < 16 Then 'クリックされたブロックの下にブロックが存在するなら
If _bList(cid + 4) = 15 Then 'クリックされたブロックの下が空ブロックなら
_bList(cid + 4) = _bList(cid)
_bList(cid) = 15
End If
End If
cFlg = False 'クリックフラグを降ろす
For i As Integer = 0 To _bList.Count - 1 '順番リスト内をチェック
If _bList(i) <> i Then '順番どおりの番号が入っていなければ
jflg = True '順番通りではなかった
End If
Next
If jflg = False Then 'すべてをチェックした結果、順番どおりに入っていたら
gFlg = True 'ゲーム完成フラグを立てる
End If
End If
End If
End Sub
Public Sub Draw(ByVal g As Graphics) '描画処理
Dim i As Integer = 0 '順番リストのインデックス番号
Dim bid As Integer '空ブロックの入っている順番リストインデックス
Dim myFont As Font
If sFlg = False Then
myFont = New Font("HG丸ゴシックM-PRO", 90, FontStyle.Regular, GraphicsUnit.Pixel)
g.DrawString("スタート", myFont, Brushes.Orange, 5, 150)
Else
For y As Integer = 0 To 3
For x As Integer = 0 To 3
g.DrawImage(_img, x * 100, y * 100, _iRect(_bList(i)), GraphicsUnit.Pixel)
i += 1
Next
Next
For x As Integer = 1 To 3 '縦線を表示
g.DrawLine(Pens.Blue, x * 100 - 1, 0, x * 100 - 1, 400)
Next
For y As Integer = 1 To 3 '横線を表示
g.DrawLine(Pens.Blue, 0, y * 100 - 1, 400, y * 100 - 1)
Next
bid = _bList.IndexOf(_bList.Count - 1) '空ブロックのインデックスを検索
g.FillRectangle(Brushes.Black, (bid Mod 4) * 100, (bid \ 4) * 100, 100, 100)
jikan = New TimeSpan(0, 0, kTime).ToString '時間表示用
myFont = New Font("HG丸ゴシックM-PRO", 20, FontStyle.Regular, GraphicsUnit.Pixel)
g.DrawString(jikan, myFont, Brushes.Orange, 0, 0)
If gFlg = True Then 'ゲーム完成状態なら
myFont = New Font("HG丸ゴシックM-PRO", 100, FontStyle.Regular, GraphicsUnit.Pixel)
g.DrawString("クリア!", myFont, Brushes.Orange, 0, 100)
myFont = New Font("HG丸ゴシックM-PRO", 50, FontStyle.Regular, GraphicsUnit.Pixel)
g.DrawString("手数:" & cCnt, myFont, Brushes.Orange, 100, 200)
End If
End If
End Sub
Public Sub MouseClick(ByVal x As Integer, ByVal y As Integer) 'マウスクリック処理
If sFlg = False Then
sFlg = True 'ゲーム開始
Me.gStart()
Else
If gFlg = False Then 'ゲーム未完成状態なら
Dim px, py As Integer
cCnt += 1
px = x \ 100 'クリックされたX座標からXブロック番号を求める
py = y \ 100 'クリックされたY座標からYブロック番号を求める
cid = px + 4 * py '2つのブロック番号から1次元配列インデックスを求める
cFlg = True 'マウスクリックフラグをTrue
Else 'ゲームクリアなら
Me.Init() 'ゲームの初期化
End If
End If
End Sub
End Class
以上で要望のあった時間と手数のカウント表示を追加したプログラムが完成となります。
15パズルを作ってみる その10
- ジャンル : コンピュータ
- スレッドテーマ : Visual Basic
15パズルを作ってみる その9の続きです。
15パズルゲームで手数やクリア時間を出せるようにしてほしいという声がありましたので、ちょっと改造してみます。
手数は何回ブロックをクリックしたかをカウントすればよいのですぐ終わります。
クリア時間はゲームが始まって、クリアになるまでなのでこれもゲーム開始時と終了時の時間さえ取り出せれば差を求めて終わりになります。
以上の点をふまえつつ、プログラム自体を修正してみました。
まずはFormクラスです。
このクラスで変更したところは時間を管理するストップウォッチを追加したところくらいです。
次回はゲームプログラム本体を修正していきます。
15パズルゲームで手数やクリア時間を出せるようにしてほしいという声がありましたので、ちょっと改造してみます。
手数は何回ブロックをクリックしたかをカウントすればよいのですぐ終わります。
クリア時間はゲームが始まって、クリアになるまでなのでこれもゲーム開始時と終了時の時間さえ取り出せれば差を求めて終わりになります。
以上の点をふまえつつ、プログラム自体を修正してみました。
まずはFormクラスです。
このクラスで変更したところは時間を管理するストップウォッチを追加したところくらいです。
Public Class Form1
Dim _Game As GameClass 'ゲームクラス変数
Dim swatch As Stopwatch = New Stopwatch() 'ストップウォッチ
Public Sub New()
' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent( ) 呼び出しの後で初期化を追加します。
Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.OptimizedDoubleBuffer, True)
Me.ClientSize = New Size(400, 400) 'クライアント領域を400×400に設定
swatch.Reset()
swatch.Start()
Me.Init()
End Sub
Sub Init()
_Game = New GameClass 'ゲームクラスインスタンスの作成
End Sub
Private Sub Form1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
_Game.MouseClick(e.X, e.Y) 'クリックされた座標を渡す
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim nowTime As Double = swatch.ElapsedMilliseconds / 1000.0 'Paintメソッドを実行した瞬間の時間
'Update…変更処理
_Game.Update(nowTime)
'Draw…描画処理
_Game.Draw(e.Graphics)
Me.Invalidate() 'Formの強制描画
End Sub
End Class
Dim _Game As GameClass 'ゲームクラス変数
Dim swatch As Stopwatch = New Stopwatch() 'ストップウォッチ
Public Sub New()
' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent( ) 呼び出しの後で初期化を追加します。
Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.OptimizedDoubleBuffer, True)
Me.ClientSize = New Size(400, 400) 'クライアント領域を400×400に設定
swatch.Reset()
swatch.Start()
Me.Init()
End Sub
Sub Init()
_Game = New GameClass 'ゲームクラスインスタンスの作成
End Sub
Private Sub Form1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
_Game.MouseClick(e.X, e.Y) 'クリックされた座標を渡す
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim nowTime As Double = swatch.ElapsedMilliseconds / 1000.0 'Paintメソッドを実行した瞬間の時間
'Update…変更処理
_Game.Update(nowTime)
'Draw…描画処理
_Game.Draw(e.Graphics)
Me.Invalidate() 'Formの強制描画
End Sub
End Class
次回はゲームプログラム本体を修正していきます。
この本はExcel VBAでRPGゲームを作るために何をどうしていけばよいかを記した本です。
3129円とちょっと高い値段ですが、内容としては他の言語でも応用をすることができる内容となっています。
【目次】
序章 サンプルゲーム「真・魔討伝」の概要
第1章 Excelとビデオゲーム
第2章 ロールプレイングゲーム作成の基本
第3章 主人公の配置と操作
第4章 マップの作成と管理
第5章 街の住人の作成
第6章 戦闘シーンの作成
第7章 アイテムと魔法の管理
第8章 クエストの作成
第9章 システム設定とセーブデータの管理
付録 ドット絵作成ツール「色彩」の使い方
Excel VBAでできるRPGゲーム作成入門
3129円とちょっと高い値段ですが、内容としては他の言語でも応用をすることができる内容となっています。
【目次】
序章 サンプルゲーム「真・魔討伝」の概要
第1章 Excelとビデオゲーム
第2章 ロールプレイングゲーム作成の基本
第3章 主人公の配置と操作
第4章 マップの作成と管理
第5章 街の住人の作成
第6章 戦闘シーンの作成
第7章 アイテムと魔法の管理
第8章 クエストの作成
第9章 システム設定とセーブデータの管理
付録 ドット絵作成ツール「色彩」の使い方
4択クイズを作ってみる その11
- ジャンル : コンピュータ
- スレッドテーマ : Visual Basic
4択クイズを作ってみる その10の続きです。
前回は4択クイズゲームのメインとなるPlayClassを作成しました。このPlayClassの中では各動作ごとにモード移行チェック(ModeEventメソッド)を行うようにしていました。そのModeEventメソッドではいくつかのクラスオブジェクトを生成するようにしています。
今回はその中のセリフクラスを作成していきます。
このセリフクラスはクイズの問題とは別に、メッセージを表示するためのクラスとなります。
たとえば、正解率が60%を超えた時や70%を超えたときにイベントとして呼び出されるようになっています。
セリフクラスは、セリフ枠表示(VB)のコーナーで作成したプログラムを利用して作成します。
プログラムは以下のようになります。
これでセリフクラスは完成です。
次回は問題クラスを作成していきます。このクラスが問題を出して、正解かどうかを判定するクラスとなります。
前回は4択クイズゲームのメインとなるPlayClassを作成しました。このPlayClassの中では各動作ごとにモード移行チェック(ModeEventメソッド)を行うようにしていました。そのModeEventメソッドではいくつかのクラスオブジェクトを生成するようにしています。
今回はその中のセリフクラスを作成していきます。
このセリフクラスはクイズの問題とは別に、メッセージを表示するためのクラスとなります。
たとえば、正解率が60%を超えた時や70%を超えたときにイベントとして呼び出されるようになっています。
セリフクラスは、セリフ枠表示(VB)のコーナーで作成したプログラムを利用して作成します。
プログラムは以下のようになります。
Imports System.IO
Imports System.Text
Imports System.Drawing.Drawing2D
Public Class SerifuClass
Dim _sflg As Boolean 'セリフ全表示フラグ
Dim _sImg As Bitmap 'セリフ枠画像
Dim _sRect As Rectangle 'セリフ枠矩形
Dim _sData As String 'セリフデータ
Dim _dData As String '表示データ
Dim _dCnt As Integer '表示文字数
Dim _lasttime As Double '前回の実行時間
Public ReadOnly Property flag( ) As Boolean
Get
Return _sflg
End Get
End Property
Public Sub New(ByVal lv As Integer, ByVal no As Integer)
Dim sr As StreamReader = New StreamReader("データ\セリフ.txt", Encoding.GetEncoding("shift_jis"))
Dim buffer As String
Dim tmplist As List(Of String) = New List(Of String)
buffer = sr.ReadLine
Do Until buffer Is Nothing
If buffer.StartsWith(lv) Then
tmplist.Add(buffer)
End If
buffer = sr.ReadLine( )
Loop
_sData = tmplist(no)
_sData = _sData.Substring(2) '2文字目以降の読み込み
_dData = ""
_sImg = New Bitmap(My.Resources.frame)
_sImg.MakeTransparent( )
_sRect = New Rectangle(0, 432, 640, 160)
_lasttime = 0
End Sub
Public Sub Update(ByVal nowTime As Double, ByVal elapsedTime As Double)
If _sflg = True Then '問題&選択肢表示完了もしくはクリックされているなら
_dData = MakeSerifu(_sData) & vbCrLf
Else
If _lasttime = 0 Then
_lasttime = nowTime
_dData = _sData.Substring(0, 1) '1文字目をセット
_dCnt += 1
ElseIf nowTime - _lasttime > 0.1 Then
If _dCnt + 1 <= _sData.Length Then
_dData &= _sData.Substring(_dCnt, 1)
_dCnt += 1
If _dCnt Mod 28 = 0 Then '28文字目で改行を挿入
_dData &= vbCrLf
End If
_lasttime = nowTime
Else
_sflg = True
End If
End If
End If
End Sub
Public Sub Draw(ByVal g As Graphics)
Dim _fm As FontFamily = New FontFamily("MS ゴシック") 'フォントの種類...HG丸ゴシックM-PRO
Dim _pen As Pen = New Pen(Color.Black, 3) 'ペン
Dim gp As GraphicsPath = New GraphicsPath
Dim sf As StringFormat = New StringFormat
g.DrawImage(_sImg, 0, 320, _sRect, GraphicsUnit.Pixel)
gp.Reset( )
gp.AddString(_dData, _fm, FontStyle.Regular, 20, New Point(20, 340), sf)
gp.CloseFigure( )
g.SmoothingMode = SmoothingMode.AntiAlias
g.DrawPath(_pen, gp)
g.FillPath(Brushes.White, gp)
End Sub
Public Sub MouseClick( )
_sflg = True '全表示
End Sub
Function MakeSerifu(ByVal data As String) As String '問題文字列一括表示処理
Dim cnt As Integer = 28 '分割文字数
Dim zan As Integer '残り文字数
Dim row As Integer 'メッセージ行数
Dim kekka As String = "" '作成した文字列
row = 0 '行数
zan = data.Length '取り出したデータの文字数を取得
Do While zan > 0 '分割処理後に1文字以上文字が残っているなら
If zan >= cnt Then '分割文字数以上残っているなら
kekka &= data.Substring(cnt * row, cnt) & vbCrLf '特定の場所から28文字取り出す
Else '分割文字数未満しかなければ
kekka &= data.Substring(cnt * row) & vbCrLf '特定の場所からすべて取り出す
End If
row += 1 '行数を加算
zan -= cnt '残りの文字数を設定
Loop
Return kekka
End Function
End Class
Imports System.Text
Imports System.Drawing.Drawing2D
Public Class SerifuClass
Dim _sflg As Boolean 'セリフ全表示フラグ
Dim _sImg As Bitmap 'セリフ枠画像
Dim _sRect As Rectangle 'セリフ枠矩形
Dim _sData As String 'セリフデータ
Dim _dData As String '表示データ
Dim _dCnt As Integer '表示文字数
Dim _lasttime As Double '前回の実行時間
Public ReadOnly Property flag( ) As Boolean
Get
Return _sflg
End Get
End Property
Public Sub New(ByVal lv As Integer, ByVal no As Integer)
Dim sr As StreamReader = New StreamReader("データ\セリフ.txt", Encoding.GetEncoding("shift_jis"))
Dim buffer As String
Dim tmplist As List(Of String) = New List(Of String)
buffer = sr.ReadLine
Do Until buffer Is Nothing
If buffer.StartsWith(lv) Then
tmplist.Add(buffer)
End If
buffer = sr.ReadLine( )
Loop
_sData = tmplist(no)
_sData = _sData.Substring(2) '2文字目以降の読み込み
_dData = ""
_sImg = New Bitmap(My.Resources.frame)
_sImg.MakeTransparent( )
_sRect = New Rectangle(0, 432, 640, 160)
_lasttime = 0
End Sub
Public Sub Update(ByVal nowTime As Double, ByVal elapsedTime As Double)
If _sflg = True Then '問題&選択肢表示完了もしくはクリックされているなら
_dData = MakeSerifu(_sData) & vbCrLf
Else
If _lasttime = 0 Then
_lasttime = nowTime
_dData = _sData.Substring(0, 1) '1文字目をセット
_dCnt += 1
ElseIf nowTime - _lasttime > 0.1 Then
If _dCnt + 1 <= _sData.Length Then
_dData &= _sData.Substring(_dCnt, 1)
_dCnt += 1
If _dCnt Mod 28 = 0 Then '28文字目で改行を挿入
_dData &= vbCrLf
End If
_lasttime = nowTime
Else
_sflg = True
End If
End If
End If
End Sub
Public Sub Draw(ByVal g As Graphics)
Dim _fm As FontFamily = New FontFamily("MS ゴシック") 'フォントの種類...HG丸ゴシックM-PRO
Dim _pen As Pen = New Pen(Color.Black, 3) 'ペン
Dim gp As GraphicsPath = New GraphicsPath
Dim sf As StringFormat = New StringFormat
g.DrawImage(_sImg, 0, 320, _sRect, GraphicsUnit.Pixel)
gp.Reset( )
gp.AddString(_dData, _fm, FontStyle.Regular, 20, New Point(20, 340), sf)
gp.CloseFigure( )
g.SmoothingMode = SmoothingMode.AntiAlias
g.DrawPath(_pen, gp)
g.FillPath(Brushes.White, gp)
End Sub
Public Sub MouseClick( )
_sflg = True '全表示
End Sub
Function MakeSerifu(ByVal data As String) As String '問題文字列一括表示処理
Dim cnt As Integer = 28 '分割文字数
Dim zan As Integer '残り文字数
Dim row As Integer 'メッセージ行数
Dim kekka As String = "" '作成した文字列
row = 0 '行数
zan = data.Length '取り出したデータの文字数を取得
Do While zan > 0 '分割処理後に1文字以上文字が残っているなら
If zan >= cnt Then '分割文字数以上残っているなら
kekka &= data.Substring(cnt * row, cnt) & vbCrLf '特定の場所から28文字取り出す
Else '分割文字数未満しかなければ
kekka &= data.Substring(cnt * row) & vbCrLf '特定の場所からすべて取り出す
End If
row += 1 '行数を加算
zan -= cnt '残りの文字数を設定
Loop
Return kekka
End Function
End Class
これでセリフクラスは完成です。
次回は問題クラスを作成していきます。このクラスが問題を出して、正解かどうかを判定するクラスとなります。
4択クイズを作ってみる その10
- ジャンル : コンピュータ
- スレッドテーマ : Visual Basic
4択クイズを作ってみる その9の続きです。
前回はタイトルクラス(TitleClass)を作成しました。このクラスによって、ユーザがどのメニューを選んだかがGameClassに返されます。
GameClassではその情報を利用し、プレイクラス(PlayClass)に渡すようにしています。
今回はこのプレイクラスを作成していきます。このクラスが4択クイズのメインプログラムとなります。
このプレイクラスの役割は、
出題する問題の作成は問題ファイルからデータを読み込み、レベルに合わせた問題数だけリストに記録させるようにしました。
背景画像はリソースとして登録した画像ファイルをレベルに合わせた画像のみビットマップ配列として記録させました。
正解率に合わせて背景画像を変化させるのは、出題予定数と正解数での計算でタイミングを決めています。
最後のモード変更の確認は一番重要な役割で、モード変更のチェックをするModeEventメソッドはその時の状態に応じてセリフモードに入ったり、問題表示モードに入ったりと変化するようになっています。プレイクラスでの各メソッドが実行されるたびモード変更チェックが行われるようになっていますので、このModeEventメソッドのやってることはポイントとなります。
今回のクラスではModeEventメソッドの中でSerifuClass、QuestionClass、ResultClass、GameOverClass、ErrorClassを生成するようにしています。
次回はこれらのクラスを作成していきます。
前回はタイトルクラス(TitleClass)を作成しました。このクラスによって、ユーザがどのメニューを選んだかがGameClassに返されます。
GameClassではその情報を利用し、プレイクラス(PlayClass)に渡すようにしています。
今回はこのプレイクラスを作成していきます。このクラスが4択クイズのメインプログラムとなります。
このプレイクラスの役割は、
- 問題ファイルを読み込み出題する問題を抽出すること
- ユーザが選択したレベルの背景画像を読み込むこと
- クイズの正解率に応じて背景画像を変更すること
- クイズをするたびにモード変更を確認すること
出題する問題の作成は問題ファイルからデータを読み込み、レベルに合わせた問題数だけリストに記録させるようにしました。
背景画像はリソースとして登録した画像ファイルをレベルに合わせた画像のみビットマップ配列として記録させました。
正解率に合わせて背景画像を変化させるのは、出題予定数と正解数での計算でタイミングを決めています。
最後のモード変更の確認は一番重要な役割で、モード変更のチェックをするModeEventメソッドはその時の状態に応じてセリフモードに入ったり、問題表示モードに入ったりと変化するようになっています。プレイクラスでの各メソッドが実行されるたびモード変更チェックが行われるようになっていますので、このModeEventメソッドのやってることはポイントとなります。
Imports System.IO
Imports System.Text
Public Class PlayClass
Enum MODE As Integer
serifu 'セリフモード
question '出題モード
result '最終結果発表モード
perfect '100%モード
over 'ゲームオーバー
err 'エラー
End Enum
Structure SerifuFlag 'セリフモード実行フラグ構造体
Dim sc60 As Boolean '60%
Dim sc70 As Boolean '70%
Dim sc80 As Boolean '80%
Dim sc90 As Boolean '90%
End Structure
Dim _pMode As MODE '現在のモード
Dim _vflg As Boolean '画面表示フラグ
Dim _mImg( ) As Bitmap '背景画像
Dim _mNo As Integer '表示背景画像No
Dim _question As QuestionClass '質問クラス
Dim _serifu As SerifuClass 'セリフクラス
Dim _result As ResultClass '結果クラス
Dim _over As GameOverClass 'ゲームオーバークラス
Dim _err As ErrorClass 'エラークラス
Dim _sNo As Integer 'セリフ番号
Dim _qList As List(Of String) '質問&選択肢リスト
Dim _lv As Integer 'レベル
Dim _qcnt As Integer '問題数
Dim _qNo As Integer '出題番号
Dim _rPoint As Integer '正解数
Dim _sflag As SerifuFlag 'セリフクラスのフラグ状態
Dim _eflg As Boolean 'ゲーム終了フラグ
Public ReadOnly Property EndFlag( ) As Boolean
Get
Return _eflg 'ゲーム終了フラグを返す
End Get
End Property
Public Sub New(ByVal lv As Integer)
Dim sr As StreamReader = New StreamReader("データ\問題.txt", Encoding.GetEncoding("shift_jis"))
Dim tmplist As List(Of String) = New List(Of String)
Dim buffer As String
Dim rnd As Random = New Random( )
Dim no As Integer
Dim cnt As Integer
_lv = lv 'レベルを設定
_qcnt = _lv * 10
_vflg = True '表示
_mNo = 0 '表示画像No
_rPoint = 0 '正解数
_qList = New List(Of String)
buffer = sr.ReadLine
Do Until buffer Is Nothing '出題する問題の読み込み
tmplist.Add(buffer)
buffer = sr.ReadLine
Loop
If tmplist.Count >= _qcnt Then '登録問題数が出題集以上なら
_pMode = MODE.serifu
_sNo = 0 '表示セリフ番号
Do While cnt < _qcnt
no = rnd.Next(tmplist.Count)
_qList.Add(tmplist(no))
tmplist.RemoveAt(no)
cnt += 1
Loop
_qNo = 0
Else '登録問題数が出題数未満なら
_pMode = MODE.err
End If
Select Case _lv '背景画像の読み込み
Case 1
_mImg = New Bitmap(5) {My.Resources.lv01_01, My.Resources.lv01_02, My.Resources.lv01_03, My.Resources.lv01_04, My.Resources.lv01_05, My.Resources.lv01_06}
Case 2
_mImg = New Bitmap(5) {My.Resources.lv02_01, My.Resources.lv02_02, My.Resources.lv02_03, My.Resources.lv02_04, My.Resources.lv02_05, My.Resources.lv02_06}
Case 3
_mImg = New Bitmap(5) {My.Resources.lv03_01, My.Resources.lv03_02, My.Resources.lv03_03, My.Resources.lv03_04, My.Resources.lv03_05, My.Resources.lv03_06}
Case 4
_mImg = New Bitmap(5) {My.Resources.lv04_01, My.Resources.lv04_02, My.Resources.lv04_03, My.Resources.lv04_04, My.Resources.lv04_05, My.Resources.lv04_06}
Case 5
_mImg = New Bitmap(5) {My.Resources.lv05_01, My.Resources.lv05_02, My.Resources.lv05_03, My.Resources.lv05_04, My.Resources.lv05_05, My.Resources.lv05_06}
End Select
ModeEvent( ) 'モード処理
End Sub
Public Sub Update(ByVal nowTime As Double, ByVal elapsedTime As Double)
Dim score As Decimal
If _vflg Then
Select Case _pMode
Case MODE.serifu
_serifu.Update(nowTime, elapsedTime)
Case MODE.question
_question.Update(nowTime, elapsedTime)
If _question.qmode = QuestionClass.MODE.owari Then
If _question.flag Then '正解していたら
_rPoint += 1 '正解数を加算
End If
score = (_rPoint / _qcnt) * 100 '正解率
If score = 100 Then
_pMode = MODE.result
ElseIf score >= 90 Then
If _sflag.sc90 = False Then '90%時のセリフモードを実行していなければ
_pMode = MODE.serifu
_mNo = 4
_sNo = 4
_sflag.sc90 = True
End If
ElseIf score >= 80 Then
If _sflag.sc80 = False Then '80%時のセリフモードを実行していなければ
_pMode = MODE.serifu
_mNo = 3
_sNo = 3
_sflag.sc80 = True
End If
ElseIf score >= 70 Then
If _sflag.sc70 = False Then '70%時のセリフモードを実行していなければ
_pMode = MODE.serifu
_mNo = 2
_sNo = 2
_sflag.sc70 = True
End If
ElseIf score >= 60 Then
If _sflag.sc60 = False Then '60%時のセリフモードを実行していなければ
_pMode = MODE.serifu
_mNo = 1
_sNo = 1
_sflag.sc60 = True
End If
ElseIf _qNo = _qcnt - 1 Then
_pMode = MODE.result
End If
_qNo += 1
ModeEvent( ) 'モード変更時処理の呼び出し
End If
Case MODE.perfect
_serifu.Update(nowTime, elapsedTime)
End Select
End If
End Sub
Public Sub Draw(ByVal g As Graphics)
g.DrawImage(_mImg(_mNo), 0, 0) '背景描画
If _vflg Then
Select Case _pMode
Case MODE.serifu
_serifu.Draw(g)
Case MODE.question
_question.Draw(g)
Case MODE.result
_result.Draw(g)
Case MODE.perfect
_serifu.Draw(g)
Case MODE.over
_over.Draw(g)
Case MODE.err
_err.Draw(g)
End Select
End If
End Sub
Public Sub MouseMove(ByVal p As Point)
If _vflg Then '表示モードなら
Select Case _pMode
Case MODE.question
_question.MouseMove(p)
End Select
End If
End Sub
Public Sub MouseClick(ByVal p As Point, ByVal b As MouseButtons)
If b = MouseButtons.Left Then
If _vflg Then '表示モードなら
Select Case _pMode
Case MODE.serifu
If _serifu.flag Then '全表示していたら
If _qNo = _qcnt Then '出題番号が最終番号なら
_pMode = MODE.result
ModeEvent( ) 'モード変更時処理の呼び出し
Else
_pMode = MODE.question
ModeEvent( ) 'モード変更時処理の呼び出し
End If
Else
_serifu.MouseClick( )
End If
Case MODE.question
_question.MouseClick(p)
Case MODE.result
If (_rPoint / _qcnt) * 100 = 100 Then '100%なら
_pMode = MODE.perfect
_mNo = 5
_sNo = 5
Else
_pMode = MODE.over
End If
ModeEvent( ) 'モード変更時処理の呼び出し
Case MODE.perfect
If _serifu.flag Then '全表示していたら
_pMode = MODE.over
ModeEvent( ) 'モード変更時処理の呼び出し
Else
_serifu.MouseClick( )
End If
Case MODE.over
_eflg = True 'ゲーム終了
Case MODE.err
_eflg = True 'ゲーム終了
End Select
End If
ElseIf b = MouseButtons.Right Then
_vflg = Not _vflg
End If
End Sub
Sub ModeEvent( ) 'モード変更時に呼び出される独自メソッド
Select Case _pMode
Case MODE.serifu
_serifu = New SerifuClass(_lv, _sNo)
Case MODE.question
_question = New QuestionClass(_qList(_qNo), _qNo)
Case MODE.result
Dim score As Decimal
score = (_rPoint / _qcnt) * 100
score = Math.Floor(score * 10) / 10
_result = New ResultClass(score)
Case MODE.perfect
_serifu = New SerifuClass(_lv, _sNo)
Case MODE.over
_over = New GameOverClass
Case MODE.err
_err = New ErrorClass
End Select
End Sub
End Class
Imports System.Text
Public Class PlayClass
Enum MODE As Integer
serifu 'セリフモード
question '出題モード
result '最終結果発表モード
perfect '100%モード
over 'ゲームオーバー
err 'エラー
End Enum
Structure SerifuFlag 'セリフモード実行フラグ構造体
Dim sc60 As Boolean '60%
Dim sc70 As Boolean '70%
Dim sc80 As Boolean '80%
Dim sc90 As Boolean '90%
End Structure
Dim _pMode As MODE '現在のモード
Dim _vflg As Boolean '画面表示フラグ
Dim _mImg( ) As Bitmap '背景画像
Dim _mNo As Integer '表示背景画像No
Dim _question As QuestionClass '質問クラス
Dim _serifu As SerifuClass 'セリフクラス
Dim _result As ResultClass '結果クラス
Dim _over As GameOverClass 'ゲームオーバークラス
Dim _err As ErrorClass 'エラークラス
Dim _sNo As Integer 'セリフ番号
Dim _qList As List(Of String) '質問&選択肢リスト
Dim _lv As Integer 'レベル
Dim _qcnt As Integer '問題数
Dim _qNo As Integer '出題番号
Dim _rPoint As Integer '正解数
Dim _sflag As SerifuFlag 'セリフクラスのフラグ状態
Dim _eflg As Boolean 'ゲーム終了フラグ
Public ReadOnly Property EndFlag( ) As Boolean
Get
Return _eflg 'ゲーム終了フラグを返す
End Get
End Property
Public Sub New(ByVal lv As Integer)
Dim sr As StreamReader = New StreamReader("データ\問題.txt", Encoding.GetEncoding("shift_jis"))
Dim tmplist As List(Of String) = New List(Of String)
Dim buffer As String
Dim rnd As Random = New Random( )
Dim no As Integer
Dim cnt As Integer
_lv = lv 'レベルを設定
_qcnt = _lv * 10
_vflg = True '表示
_mNo = 0 '表示画像No
_rPoint = 0 '正解数
_qList = New List(Of String)
buffer = sr.ReadLine
Do Until buffer Is Nothing '出題する問題の読み込み
tmplist.Add(buffer)
buffer = sr.ReadLine
Loop
If tmplist.Count >= _qcnt Then '登録問題数が出題集以上なら
_pMode = MODE.serifu
_sNo = 0 '表示セリフ番号
Do While cnt < _qcnt
no = rnd.Next(tmplist.Count)
_qList.Add(tmplist(no))
tmplist.RemoveAt(no)
cnt += 1
Loop
_qNo = 0
Else '登録問題数が出題数未満なら
_pMode = MODE.err
End If
Select Case _lv '背景画像の読み込み
Case 1
_mImg = New Bitmap(5) {My.Resources.lv01_01, My.Resources.lv01_02, My.Resources.lv01_03, My.Resources.lv01_04, My.Resources.lv01_05, My.Resources.lv01_06}
Case 2
_mImg = New Bitmap(5) {My.Resources.lv02_01, My.Resources.lv02_02, My.Resources.lv02_03, My.Resources.lv02_04, My.Resources.lv02_05, My.Resources.lv02_06}
Case 3
_mImg = New Bitmap(5) {My.Resources.lv03_01, My.Resources.lv03_02, My.Resources.lv03_03, My.Resources.lv03_04, My.Resources.lv03_05, My.Resources.lv03_06}
Case 4
_mImg = New Bitmap(5) {My.Resources.lv04_01, My.Resources.lv04_02, My.Resources.lv04_03, My.Resources.lv04_04, My.Resources.lv04_05, My.Resources.lv04_06}
Case 5
_mImg = New Bitmap(5) {My.Resources.lv05_01, My.Resources.lv05_02, My.Resources.lv05_03, My.Resources.lv05_04, My.Resources.lv05_05, My.Resources.lv05_06}
End Select
ModeEvent( ) 'モード処理
End Sub
Public Sub Update(ByVal nowTime As Double, ByVal elapsedTime As Double)
Dim score As Decimal
If _vflg Then
Select Case _pMode
Case MODE.serifu
_serifu.Update(nowTime, elapsedTime)
Case MODE.question
_question.Update(nowTime, elapsedTime)
If _question.qmode = QuestionClass.MODE.owari Then
If _question.flag Then '正解していたら
_rPoint += 1 '正解数を加算
End If
score = (_rPoint / _qcnt) * 100 '正解率
If score = 100 Then
_pMode = MODE.result
ElseIf score >= 90 Then
If _sflag.sc90 = False Then '90%時のセリフモードを実行していなければ
_pMode = MODE.serifu
_mNo = 4
_sNo = 4
_sflag.sc90 = True
End If
ElseIf score >= 80 Then
If _sflag.sc80 = False Then '80%時のセリフモードを実行していなければ
_pMode = MODE.serifu
_mNo = 3
_sNo = 3
_sflag.sc80 = True
End If
ElseIf score >= 70 Then
If _sflag.sc70 = False Then '70%時のセリフモードを実行していなければ
_pMode = MODE.serifu
_mNo = 2
_sNo = 2
_sflag.sc70 = True
End If
ElseIf score >= 60 Then
If _sflag.sc60 = False Then '60%時のセリフモードを実行していなければ
_pMode = MODE.serifu
_mNo = 1
_sNo = 1
_sflag.sc60 = True
End If
ElseIf _qNo = _qcnt - 1 Then
_pMode = MODE.result
End If
_qNo += 1
ModeEvent( ) 'モード変更時処理の呼び出し
End If
Case MODE.perfect
_serifu.Update(nowTime, elapsedTime)
End Select
End If
End Sub
Public Sub Draw(ByVal g As Graphics)
g.DrawImage(_mImg(_mNo), 0, 0) '背景描画
If _vflg Then
Select Case _pMode
Case MODE.serifu
_serifu.Draw(g)
Case MODE.question
_question.Draw(g)
Case MODE.result
_result.Draw(g)
Case MODE.perfect
_serifu.Draw(g)
Case MODE.over
_over.Draw(g)
Case MODE.err
_err.Draw(g)
End Select
End If
End Sub
Public Sub MouseMove(ByVal p As Point)
If _vflg Then '表示モードなら
Select Case _pMode
Case MODE.question
_question.MouseMove(p)
End Select
End If
End Sub
Public Sub MouseClick(ByVal p As Point, ByVal b As MouseButtons)
If b = MouseButtons.Left Then
If _vflg Then '表示モードなら
Select Case _pMode
Case MODE.serifu
If _serifu.flag Then '全表示していたら
If _qNo = _qcnt Then '出題番号が最終番号なら
_pMode = MODE.result
ModeEvent( ) 'モード変更時処理の呼び出し
Else
_pMode = MODE.question
ModeEvent( ) 'モード変更時処理の呼び出し
End If
Else
_serifu.MouseClick( )
End If
Case MODE.question
_question.MouseClick(p)
Case MODE.result
If (_rPoint / _qcnt) * 100 = 100 Then '100%なら
_pMode = MODE.perfect
_mNo = 5
_sNo = 5
Else
_pMode = MODE.over
End If
ModeEvent( ) 'モード変更時処理の呼び出し
Case MODE.perfect
If _serifu.flag Then '全表示していたら
_pMode = MODE.over
ModeEvent( ) 'モード変更時処理の呼び出し
Else
_serifu.MouseClick( )
End If
Case MODE.over
_eflg = True 'ゲーム終了
Case MODE.err
_eflg = True 'ゲーム終了
End Select
End If
ElseIf b = MouseButtons.Right Then
_vflg = Not _vflg
End If
End Sub
Sub ModeEvent( ) 'モード変更時に呼び出される独自メソッド
Select Case _pMode
Case MODE.serifu
_serifu = New SerifuClass(_lv, _sNo)
Case MODE.question
_question = New QuestionClass(_qList(_qNo), _qNo)
Case MODE.result
Dim score As Decimal
score = (_rPoint / _qcnt) * 100
score = Math.Floor(score * 10) / 10
_result = New ResultClass(score)
Case MODE.perfect
_serifu = New SerifuClass(_lv, _sNo)
Case MODE.over
_over = New GameOverClass
Case MODE.err
_err = New ErrorClass
End Select
End Sub
End Class
今回のクラスではModeEventメソッドの中でSerifuClass、QuestionClass、ResultClass、GameOverClass、ErrorClassを生成するようにしています。
次回はこれらのクラスを作成していきます。
この本はHIRO's.NETを運営している方が出版したものです。
このサイトにはVBの様々な小技が紹介されておりかなり勉強になります。
今回出版した本はVBの基本を対象としていますが、クラス関係のところは詳しく書いてありますのでお奨めです。
Visual Studio 2010が発売
- ジャンル : コンピュータ
- スレッドテーマ : Visual Basic
Visual Studio 2010が5月18日から予約販売開始となるみたいです。
で、今回もVisual Basic 2010のexpressがダウンロードできるようになっていますので、早速ダウンロード&インストールしてみました。
動くことは動きましたが・・・重過ぎる・・・。
RAMが512ではさすがにきついですね。
早く新しいPCがほしい今日この頃です。
Visual Studio 2010 Expressのダウンロードはこちら
で、今回もVisual Basic 2010のexpressがダウンロードできるようになっていますので、早速ダウンロード&インストールしてみました。
動くことは動きましたが・・・重過ぎる・・・。
RAMが512ではさすがにきついですね。
早く新しいPCがほしい今日この頃です。
Visual Studio 2010 Expressのダウンロードはこちら








