とりあえずピンの配置(ボウリングゲーム)

解決


たまご  2009-11-11 01:41:57  No: 142790

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本のピンを画面に配置していくのですが、ここではたと思考が止まってしまいました。
抽象化を図ろうとしてますが、いかんせん飽和状態になってしまいました。
何かヒントがあればお願いします。


魔界の仮面弁士  2009-11-11 03:01:00  No: 142791

> 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 を切り替えるという手法もあります。


たまご  2009-11-11 03:38:35  No: 142792

丁寧にコードまで書いていただき有り難うございます。
コードを見ると「ああそうだった」と思えますが、
なかなか自力で考えつかない私は、悲しいかな適性に欠けるのかも
しれませんね。

>一方、ピンそれぞれに PictureBox を 1 つずつ用意しておき、
>それぞれの PictureBox の .Image を切り替えるという手法もあります。

こちらの手法で以前作ってはみたのですが、一つの PictureBox に、それぞれのピンを描画していく方法が一般的なのかな、と思ってチャレンジしてみた次第です。どちらの方法でも良いということなのですか?


魔界の仮面弁士  2009-11-11 05:02:04  No: 142793

> 一つの PictureBox に、それぞれのピンを描画していく方法
私はその方法をお奨めしておきます。

# WPF で作る場合は、また話が変わってくるでしょけれども。


たまご  2009-11-11 21:52:46  No: 142794

>WPF で作る場合は、また話が変わってくるでしょけれども

WPFはさわったことがないのですが、ゲーム的なアプリを作るには
こちらの方が高機能なものがつくれるのでしょうか


聖帝  2009-11-13 06:28:52  No: 142795

こっちにも居ましたか。^^;
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


たまご  2009-11-13 06:54:57  No: 142796

これはすばらしいです。こんなことができるのですね。
書籍では得られない貴重なサンプルで本当に有り難いです。
参考にさせていただきます。

聖帝さんは、お世辞抜きで、まさしく天才ですね。
ゲーム作りのサイト、ぜひぜひ作ってください。
楽しみにしてます。


たまご  2009-11-14 04:04:41  No: 142797

何度もすまません。
ピンの配置は理解できましたが、次に玉をころがしてピンを倒す
描画ですが、
これは、ピンと同じ形状で黒で塗りつぶした図形を描画して
元の画像の幅と高さの数値を入れ替えればピンが倒れた画像が描画
させると思うのですが、やってみると輪郭が消えずに残ってしまいます
このへんの処理は、けっこう面倒そうなのですが、いかがでしょうか


たまご  2009-11-14 04:07:52  No: 142798

何度もすみません。
ピンの配置は理解できましたが、次に玉をころがしてピンを倒す
描画ですが、
1ピンと同じ形状で黒で塗りつぶした図形を描画する
2元の画像の幅と高さの数値を入れ替えれた画像を描画する(倒れたピン)

1、2の処理が必要と考えました。
しかし、やってみると輪郭が消えずに残ってしまいます
このへんの処理は、けっこう面倒そうなのですが、ワザがあるのでしょうか


聖帝  2009-11-14 04:41:27  No: 142799

うむぅ。ボクは、たまごさん用のコードでボーリングを作ってます。
自分で本気モードで作るならイメージファイルを配列に入れて使用します。
そうすると、ピンが倒れるシーンをアニメーションのように綺麗に作成できます。
単純配列しか使用してませんが、実際は配列の中に配列を作り、さらに、その中にも配列をつくります。
ですから、多次元配列やList的レベル以上の知識が必要です。
で、
たまごさんが次の問題をできるようでしたら、ボク流のアイデアを提供します。
まぁボクが暇なら作るかもしれませんが。

問題
オリンピックの5色を使い、5輪の輪を1枚のピクチャーBoxで描画してください。
かなり簡単だと思いますが。


聖帝  2009-11-14 04:44:03  No: 142800

それと、条件として
配列とループを使用してください。


たまご  2009-11-14 18:46:47  No: 142801

う〜ん。これでいいとは思うのですが、エラーがでます。

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


たまご  2009-11-14 18:49:56  No: 142802

訂正です
  For i = 0 To 4
            g.DrawEllipse(hatacolor(i), gorinki(i), 100, 100)


たまご  2009-11-14 21:09:16  No: 142803

いちおうできました。 

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


聖帝  2009-11-15 05:52:14  No: 142804

高度なボーリングについては、次回に暇があれば解説します。
で、たまごさんがヤリタイのはピンを消すだけの処理ですよね。
この思考は麻雀ゲームでも使用できます。
人によってはインチキ的と思う人もいますが、本物のゲームプログラマーも使っている人もいます。シンプル簡単法です。
思考演算処理をしていないからです。
’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


たまご  2009-11-15 17:45:12  No: 142805

貴重なサンプルありがとうございます。
このサンプルではピンが消えていますが、同時に倒れたピンの画像を
描画すれば良いのですね。


たまご  2009-11-15 19:10:06  No: 142806

すみません。勝手に改造させてもらいました。
でも、倒れたピンの輪郭が残っているのと、倒れたピンの数字が
横向きになりません。あと、立っているピンと倒れているピンが
重なり合っている境界線が明瞭でないのが気になってます。

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


たまご  2009-11-15 19:50:01  No: 142807

黒の四角で塗りつぶしてみましたが、今度はピンの前後関係を
どうにかしなければという課題がでてきたような気がします。
このあたりはどのような解決策があるのでしょうか 

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


たまご  2009-11-15 20:23:35  No: 142808

上記のコードで特に解せないのは、黒く塗りつぶしてから
倒れたピンを描画しているのにもかかわらず、倒れたピンの
画像に黒の四角がのさっていることです。
普通、描画順に画像の上下は決まってくるものですよね


聖帝  2009-11-15 20:30:17  No: 142809

たまごさんは、イメージファイルの使い方がわかりますか?
リソースの入れ方がわかりますか?
この2点が理解できていれば、別の方法も提供できます。
ボーリングの作りかたは20種類以上あり、その中のほんの2通りほどを簡単に説明します。
1_イメージファイルでボーリングの倒れる様子を5〜10枚用意して、アニメーションのように描画していく。
2_ちょっと忘れたけど、RotateAtでピンを左とか右とかに少しずつ回転させる。
製品並みのを作る場合は、かなり難しいですね。
☆_もし1ピンにボールが当たると仮想します、そうすると1ピンがどの方向に飛ぶか演算処理しなきゃならない、ビリヤードとかに匹敵する難易度です。
とりあえずヒントは提供しますよ、がんばってね。


たまご  2009-11-15 20:37:48  No: 142810

今の私のレベルでは、やはり難易度が高いということがわかりました。
もう少し他のサンプルで鍛えてから挑戦したいと思います。
いろいろとありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加