VB2008
配列を使い、ボウリングのピンを10本描画しようと考えてます。
Dim pinpozition As List(Of Point) = New List(Of Point)( ) 'ピンの位置
Dim pintype As List(Of PictureBox) = New List(Of PictureBox)( ) 'ピンの状態(立っているか、倒れているか)
Dim bmp As Bitmap = New Bitmap(PictureBox1.Width, PictureBox1.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
img = Image.FromFile("\pin5.gif") ’立っているピンの画像
img2 = Image.FromFile("\xpin1a.gif") ’倒れているピンの画像
10本のピンを画面に配置していくのですが、ここではたと思考が止まってしまいました。
抽象化を図ろうとしてますが、いかんせん飽和状態になってしまいました。
何かヒントがあればお願いします。
> Dim pinpozition As List(Of Point) = New List(Of Point)( ) 'ピンの位置
> Dim pintype As List(Of PictureBox) = New List(Of PictureBox)( ) 'ピンの状態(立っているか、倒れているか)
List はコレクションの一種ですが、配列ではありませんよ。
それと、ポジションのスペルは pozition ではなく position です。
また、「立っているかどうか」を保持させるのであれば、それは
PictureBox ではなく、Boolean で表した方が良いとおもいます。
「立っている時の画像/倒れている時の画像」を表す情報と、
「立っているのか/倒れているのか」を表す情報は、別物ですから。
> 10本のピンを画面に配置していくのですが、ここではたと思考が止まってしまいました。
ゲーム画面を描画する前に、まずは、ピンの状態を定義しましょう。
・ピンは何本ありますか? 10本なら、配列なり List なりに
“10個分の領域”を準備しておく必要があります。
・それぞれのピンの座標は決まっていますか? 倒れているかどうかの状態は?
決まっているなら、まずはそれらの状態をセットしておきましょう。
たとえば、Point の配列を 10 個用意する場合には、
Dim x(9) As Point
などと記述します。これにより、x(0) 〜 x(9) までの 10 個分の Point が用意されますので、
x(0) = New Point(100, 100)
x(1) = New Point(100, 150)
x(2) = New Point(100, 200)
x(3) = New Point(150, 100)
x(4) = New Point(150, 150)
x(5) = New Point(150, 200)
などとして、それぞれのピンの座標をセットしておきます。
一方、配列の代わりに List(Of Point) を使う場合には、New で器を用意した後、
Dim x As New List(Of Point)()
x.Add(New Point(100, 100))
x.Add(New Point(100, 150))
x.Add(New Point(100, 200))
x.Add(New Point(150, 100))
x.Add(New Point(150, 150))
x.Add(New Point(150, 200))
などとして、それぞれの座標をセットします。
次に、それらに併せて画面を描画します。
> Dim bmp As Bitmap = New Bitmap(PictureBox1.Width, PictureBox1.Height)
> Dim g As Graphics = Graphics.FromImage(bmp)
この「Graphics.FromImage(Bitmap)」で Graphics を得る手法は、
主に背景画面などの動きの無い(動きの少ない)領域のために用いると良いでしょう。
一方、ボールやピンなど、動きのあるデータは Paint イベントの e.Graphics で
得られる Graphics に対して描画した方が良いかと思います。
> img = Image.FromFile("\pin5.gif") ’立っているピンの画像
> img2 = Image.FromFile("\xpin1a.gif") ’倒れているピンの画像
一つの PictureBox に、それぞれのピンを描画していく場合には、
それぞれのピン座標に、上記の画像いずれかを .DrawImage メソッドで
描画していくことになります。
一方、ピンそれぞれに PictureBox を 1 つずつ用意しておき、
それぞれの PictureBox の .Image を切り替えるという手法もあります。
丁寧にコードまで書いていただき有り難うございます。
コードを見ると「ああそうだった」と思えますが、
なかなか自力で考えつかない私は、悲しいかな適性に欠けるのかも
しれませんね。
>一方、ピンそれぞれに PictureBox を 1 つずつ用意しておき、
>それぞれの PictureBox の .Image を切り替えるという手法もあります。
こちらの手法で以前作ってはみたのですが、一つの PictureBox に、それぞれのピンを描画していく方法が一般的なのかな、と思ってチャレンジしてみた次第です。どちらの方法でも良いということなのですか?
> 一つの PictureBox に、それぞれのピンを描画していく方法
私はその方法をお奨めしておきます。
# WPF で作る場合は、また話が変わってくるでしょけれども。
>WPF で作る場合は、また話が変わってくるでしょけれども
WPFはさわったことがないのですが、ゲーム的なアプリを作るには
こちらの方が高機能なものがつくれるのでしょうか
こっちにも居ましたか。^^;
Listは難しいから、まず1番簡単なやつからやろうよ。
イメージファイルを使うと、もっと綺麗になるけど。
こんな感じで、どうですか?
’VisualBasic2008無料版
'PictureBox1をフォームに入れる
Option Strict On
Public Class Form1
Dim pin() As Integer = {135, 200, 100, 160, 170, 160, 65, 120, 135, 120, 205, 120, 30, 80, 100, 80, 170, 80, 240, 80}
Dim myFont As Font = New Font("ui gothic", 20)
Public Sub New()
' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
Me.StartPosition = FormStartPosition.CenterScreen
Me.BackColor = Color.Gray
Me.Size = New Size(500, 700)
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
With PictureBox1
.Size = New Size(300, 620)
.BackColor = Color.Black
.Location = New Point(20, 20)
End With
End Sub
Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
Dim g As Graphics = e.Graphics
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
Dim i As Integer
For i = 0 To 9
g.FillEllipse(Brushes.White, pin(i * 2), pin(i * 2 + 1), 20, 30)
g.FillEllipse(Brushes.White, pin(i * 2) - 5, pin(i * 2 + 1) + 20, 30, 50)
g.DrawLine(Pens.Red, pin(i * 2) + 2, pin(i * 2 + 1) + 25, pin(i * 2) + 19, pin(i * 2 + 1) + 25)
g.DrawLine(Pens.Red, pin(i * 2) + 2, pin(i * 2 + 1) + 22, pin(i * 2) + 19, pin(i * 2 + 1) + 22)
g.DrawString(CStr(i), myFont, Brushes.Red, pin(i * 2) - 1, pin(i * 2 + 1) + 30)
Next
End Sub
End Class
これはすばらしいです。こんなことができるのですね。
書籍では得られない貴重なサンプルで本当に有り難いです。
参考にさせていただきます。
聖帝さんは、お世辞抜きで、まさしく天才ですね。
ゲーム作りのサイト、ぜひぜひ作ってください。
楽しみにしてます。
何度もすまません。
ピンの配置は理解できましたが、次に玉をころがしてピンを倒す
描画ですが、
これは、ピンと同じ形状で黒で塗りつぶした図形を描画して
元の画像の幅と高さの数値を入れ替えればピンが倒れた画像が描画
させると思うのですが、やってみると輪郭が消えずに残ってしまいます
このへんの処理は、けっこう面倒そうなのですが、いかがでしょうか
何度もすみません。
ピンの配置は理解できましたが、次に玉をころがしてピンを倒す
描画ですが、
1ピンと同じ形状で黒で塗りつぶした図形を描画する
2元の画像の幅と高さの数値を入れ替えれた画像を描画する(倒れたピン)
1、2の処理が必要と考えました。
しかし、やってみると輪郭が消えずに残ってしまいます
このへんの処理は、けっこう面倒そうなのですが、ワザがあるのでしょうか
うむぅ。ボクは、たまごさん用のコードでボーリングを作ってます。
自分で本気モードで作るならイメージファイルを配列に入れて使用します。
そうすると、ピンが倒れるシーンをアニメーションのように綺麗に作成できます。
単純配列しか使用してませんが、実際は配列の中に配列を作り、さらに、その中にも配列をつくります。
ですから、多次元配列やList的レベル以上の知識が必要です。
で、
たまごさんが次の問題をできるようでしたら、ボク流のアイデアを提供します。
まぁボクが暇なら作るかもしれませんが。
問題
オリンピックの5色を使い、5輪の輪を1枚のピクチャーBoxで描画してください。
かなり簡単だと思いますが。
それと、条件として
配列とループを使用してください。
う〜ん。これでいいとは思うのですが、エラーがでます。
Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
Dim gorinki(4) As Point
gorinki(0) = New Point(10, 10)
gorinki(1) = New Point(70, 60)
gorinki(2) = New Point(130, 10)
gorinki(3) = New Point(190, 60)
gorinki(4) = New Point(250, 10)
Dim hatacolor(4) As Pen
hatacolor(0) = New Pen(Color.Blue, 3)
hatacolor(1) = New Pen(Color.Yellow, 3)
hatacolor(2) = New Pen(Color.Black, 3)
hatacolor(3) = New Pen(Color.Green, 3)
hatacolor(4) = New Pen(Color.Red, 3)
Dim g As Graphics = e.Graphics
g.Clear(Color.White)
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
Dim i As Integer
For i = 0 To 4
g.DrawEllipse(hatacolor(0), gorinki(0), 100, 100)
Next
訂正です
For i = 0 To 4
g.DrawEllipse(hatacolor(i), gorinki(i), 100, 100)
いちおうできました。
Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
Dim gorinki(4) As Point
gorinki(0) = New Point(10, 10)
gorinki(1) = New Point(70, 60)
gorinki(2) = New Point(130, 10)
gorinki(3) = New Point(190, 60)
gorinki(4) = New Point(250, 10)
Dim hatacolor(4) As Pen
hatacolor(0) = New Pen(Color.Blue, 3)
hatacolor(1) = New Pen(Color.Yellow, 3)
hatacolor(2) = New Pen(Color.Black, 3)
hatacolor(3) = New Pen(Color.Green, 3)
hatacolor(4) = New Pen(Color.Red, 3)
Dim w As Integer = 100
Dim h As Integer = 100
Dim g As Graphics = e.Graphics
g.Clear(Color.White)
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
Dim i As Integer
For i = 0 To 4
g.DrawEllipse(hatacolor(i), gorinki(i).X, gorinki(i).Y, w, h)
Next
End Sub
高度なボーリングについては、次回に暇があれば解説します。
で、たまごさんがヤリタイのはピンを消すだけの処理ですよね。
この思考は麻雀ゲームでも使用できます。
人によってはインチキ的と思う人もいますが、本物のゲームプログラマーも使っている人もいます。シンプル簡単法です。
思考演算処理をしていないからです。
’VisualBasic2008無料版
'PictureBox1をフォームに入れる
'Button1をフォームに入れる
Option Strict On
Public Class Form1
Dim pin() As Integer = {135, 200, 100, 160, 170, 160, 65, 120, 135, 120, 205, 120, 30, 80, 100, 80, 170, 80, 240, 80}
Dim myFont As Font = New Font("ui gothic", 20)
Dim pin_jyoutai() As Integer = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
Dim random1 As Random
Public Sub New()
' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
Me.StartPosition = FormStartPosition.CenterScreen
Me.BackColor = Color.Gray
Me.Size = New Size(500, 700)
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
With PictureBox1
.Size = New Size(300, 620)
.BackColor = Color.Black
.Location = New Point(20, 20)
End With
Button1.Location = New Point(350, 30)
Button1.Size = New Size(120, 30)
Button1.Text = "1投目"
End Sub
Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
Dim g As Graphics = e.Graphics
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
For i = 0 To 9
iro(e.Graphics, Brushes.White, Pens.Red, i)
Next
For i = 0 To 9
If pin_jyoutai(i) = 0 Then
iro(e.Graphics, Brushes.Blue, Pens.SkyBlue, i)
End If
Next
End Sub
Sub iro(ByVal x As Graphics, ByVal y As Brush, ByVal z As Pen, ByVal i As Integer)
x.FillEllipse(y, pin(i * 2), pin(i * 2 + 1), 20, 30)
x.FillEllipse(y, pin(i * 2) - 5, pin(i * 2 + 1) + 20, 30, 50)
x.DrawLine(z, pin(i * 2) + 2, pin(i * 2 + 1) + 25, pin(i * 2) + 19, pin(i * 2 + 1) + 25)
x.DrawLine(z, pin(i * 2) + 2, pin(i * 2 + 1) + 22, pin(i * 2) + 19, pin(i * 2 + 1) + 22)
x.DrawString(CStr(i), myFont, Brushes.Red, pin(i * 2) - 1, pin(i * 2 + 1) + 30)
End Sub
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
For i = 0 To 9
pin_jyoutai(i) = 1
Next
random1 = New Random()
Dim x As Integer
x = random1.Next(4)
Select Case x
Case 0 'ストライク
For i = 0 To 9
pin_jyoutai(i) = 0
Next
Case 1 'ピンの倒れるパターン1
pin_jyoutai(0) = 0 : pin_jyoutai(1) = 0 : pin_jyoutai(3) = 0 : pin_jyoutai(6) = 0 : pin_jyoutai(7) = 0
Case 2 'パターン2
pin_jyoutai(0) = 0 : pin_jyoutai(2) = 0 : pin_jyoutai(4) = 0 : pin_jyoutai(7) = 0 : pin_jyoutai(8) = 0
Case 3 'パターン3
pin_jyoutai(1) = 0 : pin_jyoutai(2) = 0 : pin_jyoutai(3) = 0 : pin_jyoutai(7) = 0
Case 4 'パターン4
pin_jyoutai(2) = 0 : pin_jyoutai(4) = 0 : pin_jyoutai(5) = 0 : pin_jyoutai(8) = 0 : pin_jyoutai(9) = 0
Case 5
'
'caseをどんどん増やす
'以下略
End Select
PictureBox1.Invalidate()
End Sub
End Class
貴重なサンプルありがとうございます。
このサンプルではピンが消えていますが、同時に倒れたピンの画像を
描画すれば良いのですね。
すみません。勝手に改造させてもらいました。
でも、倒れたピンの輪郭が残っているのと、倒れたピンの数字が
横向きになりません。あと、立っているピンと倒れているピンが
重なり合っている境界線が明瞭でないのが気になってます。
Public Class Form1
Dim pin() As Integer = {135, 200, 100, 160, 170, 160, 65, 120, 135, 120, 205, 120, 30, 80, 100, 80, 170, 80, 240, 80}
Dim myFont As Font = New Font("ui gothic", 20)
Dim pin_jyoutai() As Integer = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
Dim random1 As Random
Public Sub New()
' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
Me.StartPosition = FormStartPosition.CenterScreen
Me.BackColor = Color.Gray
Me.Size = New Size(500, 700)
End Sub
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
With PictureBox1
.Size = New Size(300, 620)
.BackColor = Color.Black
.Location = New Point(20, 20)
End With
Button1.Location = New Point(350, 30)
Button1.Size = New Size(120, 30)
Button1.Text = "1投目"
End Sub
Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
Dim g As Graphics = e.Graphics
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
For i = 0 To 9
iro(e.Graphics, Brushes.White, Pens.Red, i)
Next
For i = 0 To 9
If pin_jyoutai(i) = 0 Then
iro(e.Graphics, Brushes.Black, Pens.Black, i)
g.FillEllipse(New SolidBrush(Color.Black), pin(i * 2) - 1, pin(i * 2 + 1) + 30, 20, 30)
iro2(e.Graphics, Brushes.White, Pens.Red, i)
End If
Next
End Sub
Sub iro(ByVal x As Graphics, ByVal y As Brush, ByVal z As Pen, ByVal i As Integer)
x.FillEllipse(y, pin(i * 2), pin(i * 2 + 1), 20, 30)
x.FillEllipse(y, pin(i * 2) - 5, pin(i * 2 + 1) + 20, 30, 50)
x.DrawLine(z, pin(i * 2) + 2, pin(i * 2 + 1) + 25, pin(i * 2) + 19, pin(i * 2 + 1) + 25)
x.DrawLine(z, pin(i * 2) + 2, pin(i * 2 + 1) + 22, pin(i * 2) + 19, pin(i * 2 + 1) + 22)
x.DrawString(CStr(i), myFont, Brushes.Red, pin(i * 2) - 1, pin(i * 2 + 1) + 30)
End Sub
Sub iro2(ByVal x As Graphics, ByVal y As Brush, ByVal z As Pen, ByVal i As Integer)
x.FillEllipse(y, pin(i * 2 + 1), pin(i * 2), 30, 20)
x.FillEllipse(y, pin(i * 2 + 1) + 20, pin(i * 2) - 5, 50, 30)
x.DrawLine(z, pin(i * 2 + 1) + 25, pin(i * 2) + 2, pin(i * 2 + 1) + 25, pin(i * 2) + 19)
x.DrawLine(z, pin(i * 2 + 1) + 22, pin(i * 2) + 2, pin(i * 2 + 1) + 22, pin(i * 2) + 19)
x.DrawString(CStr(i), myFont, Brushes.Red, pin(i * 2 + 1) + 30, pin(i * 2) - 1)
End Sub
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
For i = 0 To 9
pin_jyoutai(i) = 1
Next
random1 = New Random()
Dim x As Integer
x = random1.Next(4)
Select Case x
Case 0 'ストライク
For i = 0 To 9
pin_jyoutai(i) = 0
Next
Case 1 'ピンの倒れるパターン1
pin_jyoutai(0) = 0 : pin_jyoutai(1) = 0 : pin_jyoutai(3) = 0 : pin_jyoutai(6) = 0 : pin_jyoutai(7) = 0
Case 2 'パターン2
pin_jyoutai(0) = 0 : pin_jyoutai(2) = 0 : pin_jyoutai(4) = 0 : pin_jyoutai(7) = 0 : pin_jyoutai(8) = 0
Case 3 'パターン3
pin_jyoutai(1) = 0 : pin_jyoutai(2) = 0 : pin_jyoutai(3) = 0 : pin_jyoutai(7) = 0
Case 4 'パターン4
pin_jyoutai(2) = 0 : pin_jyoutai(4) = 0 : pin_jyoutai(5) = 0 : pin_jyoutai(8) = 0 : pin_jyoutai(9) = 0
Case 5
'
'caseをどんどん増やす
'以下略
End Select
PictureBox1.Invalidate()
End Sub
End Class
黒の四角で塗りつぶしてみましたが、今度はピンの前後関係を
どうにかしなければという課題がでてきたような気がします。
このあたりはどのような解決策があるのでしょうか
Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
Dim g As Graphics = e.Graphics
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
For i = 0 To 9
iro(e.Graphics, Brushes.White, Pens.Red, i)
Next
For i = 0 To 9
If pin_jyoutai(i) = 0 Then
g.FillRectangle(New SolidBrush(Color.Black), pin(i * 2), pin(i * 2 + 1), 30, 50)
g.FillRectangle(New SolidBrush(Color.Black), pin(i * 2) - 5, pin(i * 2 + 1) + 20, 30, 50)
iro2(e.Graphics, Brushes.White, Pens.Red, i)
End If
Next
End Sub
上記のコードで特に解せないのは、黒く塗りつぶしてから
倒れたピンを描画しているのにもかかわらず、倒れたピンの
画像に黒の四角がのさっていることです。
普通、描画順に画像の上下は決まってくるものですよね
たまごさんは、イメージファイルの使い方がわかりますか?
リソースの入れ方がわかりますか?
この2点が理解できていれば、別の方法も提供できます。
ボーリングの作りかたは20種類以上あり、その中のほんの2通りほどを簡単に説明します。
1_イメージファイルでボーリングの倒れる様子を5〜10枚用意して、アニメーションのように描画していく。
2_ちょっと忘れたけど、RotateAtでピンを左とか右とかに少しずつ回転させる。
製品並みのを作る場合は、かなり難しいですね。
☆_もし1ピンにボールが当たると仮想します、そうすると1ピンがどの方向に飛ぶか演算処理しなきゃならない、ビリヤードとかに匹敵する難易度です。
とりあえずヒントは提供しますよ、がんばってね。
今の私のレベルでは、やはり難易度が高いということがわかりました。
もう少し他のサンプルで鍛えてから挑戦したいと思います。
いろいろとありがとうございました。