none
VB2005移動限制的問題!! RRS feed

  • 問題

  • 我用Picturebox為成類似迷宮的範圍,然後在拉一個Picturebox就是在按↑↓←→時他會移動。那如何做到限制他移動的範圍?

    EX:

        ● ● ● ● ●

        ●          ●    ● ● ●   

        ●          ●    ●    ● 

        ●          ● ● ●    ●

        ● ● ●                ●

           ● ●       ●       ●

           ●          ● ● ● ●

           ● ● ● ● ●

    像這樣子的範圍如何將其可移動的範圍限制在黑點裡面不要讓他跑出來!!

    我現在想不到辦法解決,我只能設定讓他在一個正方型裡面移動。

    像這種我沒有想法,不知道如何做,所以希望知道的人提點我一下唄!!

    2007年12月24日 上午 07:04

解答

  •  

    偷懶的做法, 不知道這是不是你要的東西....

     

    在 Form1 上拉兩個 PictureBox , 分別為 PictureBox1, PictureBox2

    然後, 方向鍵不會進 Form1.KeyDown (我也不知道為什麼....), 所以我寫在 Form1.KeyUp

    按下方向鍵(這裡寫在 KeyUp 所以是放開), 一次移動一個單位, 所以只需要判斷之後要移動過去的位置是否符合條件即可

     

    程式碼區塊

    Public Class Form1

        Dim A1(9, 9) As Boolean '假設是一個 10 x 10 的方陣
        Dim CurXY As New Point  'PictureBox2 目前的位置
        Dim dW As Integer       'PictureBox1.ClientSize.Width / 10
        Dim dH As Integer       'PictureBox1.ClientSize.Height / 10

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

            '調整大小
            Me.PictureBox1.BorderStyle = BorderStyle.FixedSingle
            Me.PictureBox1.Size = New Size(Me.ClientSize.Width * 0.8, Me.ClientSize.Height * 0.8)
            Me.PictureBox1.Location = New Point(Me.ClientSize.Width * 0.1, Me.ClientSize.Height * 0.1)

            '算出等分寬、高
            dW = Me.PictureBox1.ClientSize.Width \ A1.GetUpperBound(0)
            dH = Me.PictureBox1.ClientSize.Height \ A1.GetUpperBound(1)

            '調整寬高為整數倍, 以免等等畫線不好看
            Me.PictureBox1.ClientSize = New Size(dW * A1.GetUpperBound(0), dH * A1.GetUpperBound(1))

            '迷宮的位置
            Dim myX() As String = Split("0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,4,4,4,4,4,5,5,5,5,6,6,6,6,7,7,8,8,8,8,8,8", ",")
            Dim myY() As String = Split("0,1,2,3,4,0,4,5,6,7,0,4,5,7,0,7,0,1,2,3,7,3,5,6,7,1,2,3,6,1,6,1,2,3,4,5,6", ",")

            '把迷宮放到 Image 上, 讓 PictureBox1 自己去 ReDraw
            Me.PictureBox1.Image = New Bitmap(Me.PictureBox1.ClientSize.Width, Me.PictureBox1.ClientSize.Height)
            Dim g As Graphics = Graphics.FromImage(Me.PictureBox1.Image)
            g.Clear(Color.White)
            '格線
            For i As Integer = 1 To A1.GetUpperBound(0)
                g.DrawLine(Pens.Black, i * dW, 0, i * dW, Me.PictureBox1.ClientRectangle.Bottom)
            Next
            For i As Integer = 1 To A1.GetUpperBound(1)
                g.DrawLine(Pens.Black, 0, i * dH, Me.PictureBox1.ClientRectangle.Right, i * dH)
            Next

            '照著題目那樣畫個圓
            For i As Integer = 0 To myX.Length - 1
                A1(Val(myX(i)), Val(myY(i))) = True
                g.FillEllipse(Brushes.Black, New Rectangle(dW * (0.2 + Val(myX(i))), dH * (0.2 + Val(myY(i))), dW * 0.6, dH * 0.6))
            Next
            g.Dispose()

            'Init PictureBox2
            Me.PictureBox2.Parent = Me.PictureBox1
            Me.PictureBox2.BackColor = Color.Transparent
            Me.PictureBox2.Size = New Size(dW * 0.6, dH * 0.6)

            '決定一開始的坐標
            CurXY.X = 1
            CurXY.Y = 1
            SetCurPos()

        End Sub

        Private Sub SetCurPos()
            Me.PictureBox2.Location = New Point((0.2 + CurXY.X) * dW, (0.2 + CurXY.Y) * dH)
        End Sub

        Private Sub Form1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp

            '先算出目的地
            Dim tXY As Point = CurXY
            Select Case e.KeyCode
                Case Keys.Up
                    tXY.Y -= 1
                Case Keys.Down
                    tXY.Y += 1
                Case Keys.Left
                    tXY.X -= 1
                Case Keys.Right
                    tXY.X += 1
                Case Else
                    Exit Sub
            End Select

            '判斷超出範圍或是目的地是迷宮用掉的點則不移動
            If tXY.X < 0 OrElse tXY.Y < 0 OrElse tXY.X > A1.GetUpperBound(0) OrElse tXY.Y > A1.GetUpperBound(1) OrElse A1(tXY.X, tXY.Y) Then Exit Sub
            CurXY = tXY
            SetCurPos()

        End Sub


        Private Sub PictureBox2_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox2.Paint
            '也是畫個圓
            e.Graphics.FillEllipse(Brushes.Red, CType(sender, PictureBox).ClientRectangle)
        End Sub

    End Class

     

     

    2007年12月24日 上午 09:11

所有回覆

  •  

    偷懶的做法, 不知道這是不是你要的東西....

     

    在 Form1 上拉兩個 PictureBox , 分別為 PictureBox1, PictureBox2

    然後, 方向鍵不會進 Form1.KeyDown (我也不知道為什麼....), 所以我寫在 Form1.KeyUp

    按下方向鍵(這裡寫在 KeyUp 所以是放開), 一次移動一個單位, 所以只需要判斷之後要移動過去的位置是否符合條件即可

     

    程式碼區塊

    Public Class Form1

        Dim A1(9, 9) As Boolean '假設是一個 10 x 10 的方陣
        Dim CurXY As New Point  'PictureBox2 目前的位置
        Dim dW As Integer       'PictureBox1.ClientSize.Width / 10
        Dim dH As Integer       'PictureBox1.ClientSize.Height / 10

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

            '調整大小
            Me.PictureBox1.BorderStyle = BorderStyle.FixedSingle
            Me.PictureBox1.Size = New Size(Me.ClientSize.Width * 0.8, Me.ClientSize.Height * 0.8)
            Me.PictureBox1.Location = New Point(Me.ClientSize.Width * 0.1, Me.ClientSize.Height * 0.1)

            '算出等分寬、高
            dW = Me.PictureBox1.ClientSize.Width \ A1.GetUpperBound(0)
            dH = Me.PictureBox1.ClientSize.Height \ A1.GetUpperBound(1)

            '調整寬高為整數倍, 以免等等畫線不好看
            Me.PictureBox1.ClientSize = New Size(dW * A1.GetUpperBound(0), dH * A1.GetUpperBound(1))

            '迷宮的位置
            Dim myX() As String = Split("0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,4,4,4,4,4,5,5,5,5,6,6,6,6,7,7,8,8,8,8,8,8", ",")
            Dim myY() As String = Split("0,1,2,3,4,0,4,5,6,7,0,4,5,7,0,7,0,1,2,3,7,3,5,6,7,1,2,3,6,1,6,1,2,3,4,5,6", ",")

            '把迷宮放到 Image 上, 讓 PictureBox1 自己去 ReDraw
            Me.PictureBox1.Image = New Bitmap(Me.PictureBox1.ClientSize.Width, Me.PictureBox1.ClientSize.Height)
            Dim g As Graphics = Graphics.FromImage(Me.PictureBox1.Image)
            g.Clear(Color.White)
            '格線
            For i As Integer = 1 To A1.GetUpperBound(0)
                g.DrawLine(Pens.Black, i * dW, 0, i * dW, Me.PictureBox1.ClientRectangle.Bottom)
            Next
            For i As Integer = 1 To A1.GetUpperBound(1)
                g.DrawLine(Pens.Black, 0, i * dH, Me.PictureBox1.ClientRectangle.Right, i * dH)
            Next

            '照著題目那樣畫個圓
            For i As Integer = 0 To myX.Length - 1
                A1(Val(myX(i)), Val(myY(i))) = True
                g.FillEllipse(Brushes.Black, New Rectangle(dW * (0.2 + Val(myX(i))), dH * (0.2 + Val(myY(i))), dW * 0.6, dH * 0.6))
            Next
            g.Dispose()

            'Init PictureBox2
            Me.PictureBox2.Parent = Me.PictureBox1
            Me.PictureBox2.BackColor = Color.Transparent
            Me.PictureBox2.Size = New Size(dW * 0.6, dH * 0.6)

            '決定一開始的坐標
            CurXY.X = 1
            CurXY.Y = 1
            SetCurPos()

        End Sub

        Private Sub SetCurPos()
            Me.PictureBox2.Location = New Point((0.2 + CurXY.X) * dW, (0.2 + CurXY.Y) * dH)
        End Sub

        Private Sub Form1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp

            '先算出目的地
            Dim tXY As Point = CurXY
            Select Case e.KeyCode
                Case Keys.Up
                    tXY.Y -= 1
                Case Keys.Down
                    tXY.Y += 1
                Case Keys.Left
                    tXY.X -= 1
                Case Keys.Right
                    tXY.X += 1
                Case Else
                    Exit Sub
            End Select

            '判斷超出範圍或是目的地是迷宮用掉的點則不移動
            If tXY.X < 0 OrElse tXY.Y < 0 OrElse tXY.X > A1.GetUpperBound(0) OrElse tXY.Y > A1.GetUpperBound(1) OrElse A1(tXY.X, tXY.Y) Then Exit Sub
            CurXY = tXY
            SetCurPos()

        End Sub


        Private Sub PictureBox2_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox2.Paint
            '也是畫個圓
            e.Graphics.FillEllipse(Brushes.Red, CType(sender, PictureBox).ClientRectangle)
        End Sub

    End Class

     

     

    2007年12月24日 上午 09:11
  • 看程式碼後我現在邊界會設了!!主要是在這個部分

    If tXY.X < 0 OrElse tXY.Y < 0 OrElse tXY.X > A1.GetUpperBound(0) OrElse tXY.Y > A1.GetUpperBound(1) OrElse A1(tXY.X, tXY.Y) Then Exit Sub
            CurXY = tXY
            SetCurPos()

        End Sub

    還有!!我要寫的是倉庫番!!也就是推箱子的遊戲^__^

    最後謝謝你的幫助唷!!

     

    2007年12月24日 上午 09:44
  • 我是覺得你使用矩陣方式來設計會比較好。

     

    程式碼區塊

     

    00000000000000000000000000000000000000000

    01111111111110001111111111000000001111110

    00000000011110001111000011111110000011110

    00000111111110001111111111111111111111110

    01111111111111111111111111111111111111110

    00001111111111111111111111111111111111110

    01100000000000000000000011111111111111110

    01111111111111111111111111111111111111110

    01111111111111111111111111111111111111110

    00000000000000000000000000000000000000000

     

     

    這樣的話你只要判斷說上下左右是不是 0,就知道有沒有撞到邊界(障礙物)了。

    如果要做像倉庫番那樣的,那麼旗標值可以放不同的,例如 2 = 箱子的所在地。
    2007年12月24日 上午 10:06
    版主
  • 小朱!!你的方法看起來好像比我原本想的方式還容易耶,我原本的想法是判斷他的座標。所以有一堆的座標。而且在轉角的地方會有BUG。

    但是你所說的方式我不會用,能否提供個例子??

    2007年12月24日 上午 10:19
  •  

    前面的程式碼就是用矩陣的方式去作判斷, 

    把 boolean array 改成 integer (可以利用 enum 比較清楚), 然後判斷 true / false 的地方改成判斷數字,

    就可以判斷多種不同的 item (牆壁, 箱子...等)

     

    剛剛跑去看看倉庫番怎麼玩, 然後改了一下原本的程式碼, 你看看這樣行不行.

    程式碼區塊

    Public Class Form1
        Enum myEnum As Integer
            space = 0
            wall = 1
            box = 2
            dist = 3
            ok = 4
        End Enum
        Dim A1(9, 9) As myEnum '假設是一個 10 x 10 的方陣
        Dim CurXY As New Point  'PictureBox2 目前的位置
        Dim dW As Integer       'PictureBox1.ClientSize.Width / 10
        Dim dH As Integer       'PictureBox1.ClientSize.Height / 10

        Dim picBox(1) As PictureBox ' 2 個箱子
        Dim posBox(1) As Point      ' 2 個箱子的位置

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

            '調整大小
            Me.PictureBox1.BorderStyle = BorderStyle.FixedSingle
            Me.PictureBox1.Size = New Size(Me.ClientSize.Width * 0.8, Me.ClientSize.Height * 0.8)
            Me.PictureBox1.Location = New Point(Me.ClientSize.Width * 0.1, Me.ClientSize.Height * 0.1)

            '算出等分寬、高
            dW = Me.PictureBox1.ClientSize.Width \ (A1.GetUpperBound(0) + 1)
            dH = Me.PictureBox1.ClientSize.Height \ (A1.GetUpperBound(1) + 1)

            '調整寬高為整數倍, 以免等等畫線不好看
            Me.PictureBox1.ClientSize = New Size(dW * (A1.GetUpperBound(0) + 1), dH * (A1.GetUpperBound(1) + 1))

            '迷宮的位置
            Dim myX() As Integer = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8}
            Dim myY() As Integer = {0, 1, 2, 3, 4, 0, 4, 5, 6, 7, 8, 9, 0, 4, 5, 9, 0, 9, 0, 1, 2, 3, 9, 3, 7, 8, 9, 1, 2, 3, 6, 1, 6, 1, 2, 3, 4, 5, 6}

            '把迷宮放到 Image 上, 讓 PictureBox1 自己去 ReDraw
            Me.PictureBox1.Image = New Bitmap(Me.PictureBox1.ClientSize.Width, Me.PictureBox1.ClientSize.Height)
            Dim g As Graphics = Graphics.FromImage(Me.PictureBox1.Image)
            g.Clear(Color.White)
            '格線
            For i As Integer = 1 To A1.GetUpperBound(0)
                g.DrawLine(Pens.Black, i * dW, 0, i * dW, Me.PictureBox1.ClientRectangle.Bottom)
            Next
            For i As Integer = 1 To A1.GetUpperBound(1)
                g.DrawLine(Pens.Black, 0, i * dH, Me.PictureBox1.ClientRectangle.Right, i * dH)
            Next

            '照著題目那樣畫個圓
            For i As Integer = 0 To myX.Length - 1
                A1(Val(myX(i)), Val(myY(i))) = 1
                g.FillEllipse(Brushes.Black, GetRect(myX(i), myY(i)))
            Next

            '目的地
            Dim myDisX() As Integer = {7, 7}
            Dim myDisY() As Integer = {2, 3}

            For i As Integer = 0 To myDisX.Length - 1
                A1(myDisX(i), myDisY(i)) = myEnum.dist
                g.FillEllipse(Brushes.LightBlue, GetRect(myDisX(i), myDisY(i)))
            Next

            g.Dispose()

            'Init PictureBox2
            Me.PictureBox2.Parent = Me.PictureBox1
            Me.PictureBox2.BackColor = Color.Transparent
            Me.PictureBox2.Size = New Size(dW * 0.6, dH * 0.6)

            '決定一開始的坐標
            CurXY.X = 1
            CurXY.Y = 1
            SetCurPos()

            ' 2 個箱子
            Dim myBoxX() As Integer = {4, 5}
            Dim myBoxY() As Integer = {4, 5}

            For i As Integer = 0 To Me.picBox.Length - 1
                posBox(i) = New Point(myBoxX(i), myBoxY(i))

                A1(myBoxX(i), myBoxY(i)) = myEnum.box

                picBox(i) = New PictureBox
                Me.Controls.Add(picBox(i))
                With picBox(i)
                    .Parent = Me.PictureBox1
                    .BackColor = Color.Transparent
                    .Size = Me.PictureBox2.Size
                    .Image = New Bitmap(.ClientSize.Width, .ClientSize.Height)
                    Dim g1 As Graphics = Graphics.FromImage(.Image)
                    g1.FillRectangle(Brushes.Brown, .ClientRectangle)
                    g.Dispose()
                    .Location = GetLocation(posBox(i))
                    .Visible = True
                End With
            Next


        End Sub

        Private Function GetRect(ByVal x As Integer, ByVal y As Integer) As Rectangle
            Return New Rectangle(dW * (0.2 + x), dH * (0.2 + y), dW * 0.6, dH * 0.6)
        End Function
        Private Function GetLocation(ByVal pos As Point) As Point
            Return New Point((0.2 + pos.X) * dW, (0.2 + pos.Y) * dH)
        End Function
        Private Sub SetCurPos()
            Me.PictureBox2.Location = GetLocation(CurXY)
        End Sub

        Private Sub Form1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
            Dim Finished As Boolean = False

            '先算出目的地
            Dim tXY As Point = CurXY
            Select Case e.KeyCode
                Case Keys.Up
                    tXY.Y -= 1
                Case Keys.Down
                    tXY.Y += 1
                Case Keys.Left
                    tXY.X -= 1
                Case Keys.Right
                    tXY.X += 1
                Case Else
                    Exit Sub
            End Select

            '判斷超出範圍或是目的地是迷宮用掉的點則不移動
            If OutOfRange(tXY) OrElse A1(tXY.X, tXY.Y) = myEnum.wall Then Exit Sub
            '如果目的地是箱子
            If A1(tXY.X, tXY.Y) = myEnum.box OrElse A1(tXY.X, tXY.Y) = myEnum.ok Then
                Dim boxPos As Point = tXY
                Select Case e.KeyCode
                    Case Keys.Up
                        boxPos.Y -= 1
                    Case Keys.Down
                        boxPos.Y += 1
                    Case Keys.Left
                        boxPos.X -= 1
                    Case Keys.Right
                        boxPos.X += 1
                End Select

                '判斷箱子移動後是否超出範圍, 或是遇到另一個箱子
                If OutOfRange(New Point(boxPos)) OrElse (A1(boxPos.X, boxPos.Y) <> myEnum.space AndAlso A1(boxPos.X, boxPos.Y) <> myEnum.dist) Then Exit Sub
                '移動箱子
                If A1(boxPos.X, boxPos.Y) = myEnum.space Then
                    A1(boxPos.X, boxPos.Y) = myEnum.box
                Else
                    A1(boxPos.X, boxPos.Y) = myEnum.ok
                End If

                Dim oldPosIndex As Integer = Array.IndexOf(posBox, tXY)
                Me.picBox(oldPosIndex).Location = GetLocation(boxPos)
                posBox(oldPosIndex) = boxPos
                If A1(tXY.X, tXY.Y) = myEnum.box Then
                    A1(tXY.X, tXY.Y) = myEnum.space
                Else
                    A1(tXY.X, tXY.Y) = myEnum.dist
                End If


                '判斷是否所有箱子都到目的地
                Finished = True
                For i As Integer = 0 To posBox.Length - 1
                    If A1(posBox(i).X, posBox(i).Y) <> myEnum.ok Then
                        Finished = False : Exit For
                    End If
                Next
            End If

            CurXY = tXY
            SetCurPos()

            If finished Then MsgBox("Finished.")
        End Sub

        Private Function OutOfRange(ByVal pos As Point) As Boolean
            Return (pos.X < 0 OrElse pos.Y < 0 OrElse pos.X > A1.GetUpperBound(0) OrElse pos.Y > A1.GetUpperBound(1))
        End Function

        Private Sub PictureBox2_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox2.Paint
            '也是畫個圓
            e.Graphics.FillEllipse(Brushes.Red, CType(sender, PictureBox).ClientRectangle)
        End Sub

    End Class

     

     

    2007年12月25日 上午 06:16
  • 先看看這個關鍵字的搜尋結果:

    http://forums.microsoft.com/MSDN-CHT/Search/Search.aspx?words=PtInRegion&localechoice=31748&SiteID=14&searchscope=allforums

     

    不考慮精度的話,整數座標可參考 API PtInRegion 或是 .Net 類別的 Region.Visible 。

     

    實數高解析度的話,可參考上面我回覆的內容,裡面有我網站上的演算法。

     

    搜尋國際期刊可用關鍵字:point in areal

    2007年12月25日 上午 08:01
    版主
  • 謝謝各位的熱心幫助唷^___^

    讓我學到了不少!!問題也順利解決了!!

    2007年12月27日 下午 02:24