一千萬個為什麽

搜索

當我按住鍵時,為什麽我的VB.NET Snake遊戲會凍結?

我試圖在VB.NET中制作經典的Snake遊戲,但是如果我在遊戲過程中持有一把鑰匙(任何鑰匙),幾秒鐘後遊戲會凍結,直到我釋放鑰匙。我已經嘗試了很多來解決這個問題,但沒有任何作用,可能是因為我不明白這個問題。

我假設當我按住一個鍵時,會調用Form1_KeyDown函數,幾秒後,當鍵進入“我被按下”模式時,該函數會不斷被調用,因此定時器不會被調用沒有機會更新。但就像我說的那樣,我可能錯了。

任何幫助都會受到贊賞,我一直在努力解決這個問題。我認為這是所有必要的代碼,如果不是,請告訴我。

關鍵事件代碼:

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

    ' Sorts out all the key presses: movement, resetting, pausing

    ' Change direction, unless the player tries to travel backwards into themself
    Select Case e.KeyCode
        Case upKey
            If previousDirection <> "D" Then
                nextDirection = "U"
            End If
        Case leftKey
            If previousDirection <> "R" Then
                nextDirection = "L"
            End If
        Case rightKey
            If previousDirection <> "L" Then
                nextDirection = "R"
            End If
        Case downKey
            If previousDirection <> "U" Then
                nextDirection = "D"
            End If
        Case resetKey
            resetGame()
        Case pauseKey
            paused = Not paused
            If paused Then
                lblPaused.Visible = True
                tmrTime.Stop()
                tmrFruit.Stop()
                tmrMove.Stop()
            Else
                lblPaused.Visible = False
                tmrTime.Start()
                tmrFruit.Start()
                tmrMove.Start()
            End If
    End Select

End Sub

更新/移動蛇的計時器代碼(我知道這是非常低效的):

 Private Sub tmrMove_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrMove.Tick

    ' Adds a new head in direction of travel, and removes the tail, giving the illusion of snake movement

    Dim head As Object = bodyParts(bodyParts.Count - 1)
    Dim tail As Object = bodyParts(0)
    Dim newHead As Object

    head.Text = ""

    ' Add new head
    Select Case nextDirection

        Case "R"
            ' If snake goes out of bounds
            If head.Tag(0) + 1 >= numberOfColumns Then
                newHead = grid(0, head.Tag(1))
                If newHead.BackColor = snakeColor Then
                    killSnake()
                End If
            Else
                ' If snake overlaps itself
                If bodyParts.Contains(grid(head.Tag(0) + 1, head.Tag(1))) Then
                    killSnake()
                    Exit Sub
                Else
                    ' If snake is fine
                    newHead = grid(head.Tag(0) + 1, head.Tag(1))
                End If
            End If

            ' If fruit taken
            If newHead.BackColor = fruitColor Then
                eatFruit(newHead, tail)
            End If

        Case "L"
            If head.Tag(0) - 1 < 0 Then
                newHead = grid(numberOfColumns - 1, head.Tag(1))
                If newHead.BackColor = snakeColor Then
                    killSnake()
                End If
            Else
                If bodyParts.Contains(grid(head.Tag(0) - 1, head.Tag(1))) Then
                    killSnake()
                    Exit Sub
                Else
                    newHead = grid(head.Tag(0) - 1, head.Tag(1))
                End If
            End If

            If newHead.BackColor = fruitColor Then
                eatFruit(newHead, tail)
            End If

        Case "U"
            If head.Tag(1) - 1 < 0 Then
                newHead = grid(head.Tag(0), numberOfRows - 1)
                If newHead.BackColor = snakeColor Then
                    killSnake()
                End If
            Else
                If bodyParts.Contains(grid(head.Tag(0), head.Tag(1) - 1)) Then
                    killSnake()
                    Exit Sub
                Else
                    newHead = grid(head.Tag(0), head.Tag(1) - 1)
                End If
            End If

            If newHead.BackColor = fruitColor Then
                eatFruit(newHead, tail)
            End If

        Case "D"
            If head.Tag(1) + 1 >= numberOfRows Then
                newHead = grid(head.Tag(0), 0)
            Else
                If bodyParts.Contains(grid(head.Tag(0), head.Tag(1) + 1)) Then
                    killSnake()
                    Exit Sub
                Else
                    newHead = grid(head.Tag(0), head.Tag(1) + 1)
                End If
            End If

            If newHead.BackColor = fruitColor Then
                eatFruit(newHead, tail)
            End If

        Case Else
            newHead = grid(head.Tag(0), head.Tag(1))

    End Select

    bodyParts.Add(newHead)
    newHead.BackColor = snakeColor
    newHead.Font = headFont
    newHead.Text = headText

    ' Remove tail
    tail.BackColor = gridColor
    bodyParts.RemoveAt(0)

    previousDirection = nextDirection

End Sub

最佳答案

我假設當我按住某個鍵時,會調用Form1_KeyDown函數,幾秒後,當鍵進入“我被按下”模式時,該函數會不斷被調用,所以計時器沒有機會更新。但就像我說的那樣,我可能錯了。

事實上,你是對的。

在Windows中,一旦按下該鍵,您將收到 WM_KEYDOWN 消息,然後,在一定的間隔後,您將獲得大量的 WM_KEYDOWN 消息它們之間有一定的間隔

如果您轉到控制面板 - 鍵盤,您可以找到這些間隔。

修復它的最簡單方法是在密鑰處理程序的末尾添加對 DoEvents 的調用。

嘗試完全刪除keydown處理程序。而是通過檢查 tmrMove_Tick 的beginnig中找到 nextDirection 。 input.keyboard.iskeydown.aspx“rel =”nofollow“> Keyboard.IsKeyDown

嘗試完全刪除keydown處理程序。而是通過檢查 GetAsyncKeyState ,在 tmrMove_Tick 的開頭計算 nextDirection ,您可以聲明如下:

Private Declare Function GetAsyncKeyState Lib "user32" Alias "GetAsyncKeyState" (ByVal vKey As Keys) As Short

Private Shared Function IsKeyDown(ByVal Key As Keys) As Boolean
    Return (GetAsyncKeyState(Key) And &H8000S) = &H8000S
End Function

轉載註明原文: 當我按住鍵時,為什麽我的VB.NET Snake遊戲會凍結?