为什么当我按住某个键时,我的VB.NET Snake游戏会冻结吗? [英] Why does my VB.NET Snake game freeze when I hold a key down?
问题描述
我正在尝试在VB.NET中制作经典的Snake游戏,但是如果我在游戏中按住某个键(任何键),则几秒钟后游戏将冻结,直到我释放该键为止.我已经尝试了很多方法来解决此问题,但是没有任何效果,也许是因为我不了解问题所在.
I'm trying to make the classic Snake game in VB.NET, but if I hold a key (any key) during the game, after a few seconds the game freezes until I release the key. I've tried lots to fix this, but nothing works, maybe because I don't understand the problem.
我假设当我按下一个键时,调用Form1_KeyDown函数,并且在几秒钟后,该键进入我被按下"模式时,该函数会不断被调用,因此计时器没有更新的机会.但是就像我说的那样,我可能错了.
I'm assuming that when I hold down a key, the Form1_KeyDown function gets called, and when, after a few seconds, the key goes into "I'm being held down" mode, that function is constantly called, so the timers don't get a chance to update. But like I said, I'm probably wrong.
任何帮助都将不胜感激,我已经为此苦苦挣扎了一段时间.我认为这是所有必需的代码,如果不是,请通知我.
Any help at all would be appreciated, I've been struggling with this for a while. I think this is all the necessary code, please let me know if it isn't.
按键事件的代码:
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
更新/移动蛇的计时器代码(我知道这确实效率很低):
Code for the timer that updates/moves the snake (I'm aware this is really inefficient):
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函数,并且在几秒钟后,该键进入我被按下"模式时,该函数会不断被调用,因此计时器没有更新的机会.但是就像我说的那样,我可能错了.
I'm assuming that when I hold down a key, the Form1_KeyDown function gets called, and when, after a few seconds, the key goes into "I'm being held down" mode, that function is constantly called, so the timers don't get a chance to update. But like I said, I'm probably wrong.
事实上,你是对的.
在Windows中,一旦按下该键,您将收到一条WM_KEYDOWN
消息,然后,在一定的时间间隔之后,您将收到许多WM_KEYDOWN
消息,并且它们之间又有一定的间隔.
In Windows you'll get a WM_KEYDOWN
message as soon as the key is pressed, and then, after a certain interval, you'll be getting lots of WM_KEYDOWN
messages with another certain interval between them.
如果您进入控制面板-键盘",则可以找到这些间隔.
You can find these intervals if you go to Control Panel - Keyboard.
最简单的解决方法是在密钥处理程序的末尾添加对 DoEvents
的调用.
尝试完全删除keydown处理程序.而是,通过检查tmrMove_Tick开头中显示 nextDirection
. "nofollow"> Keyboard.IsKeyDown
.
Try removing the keydown handler completely. Instead, figure nextDirection
in the beginnig of tmrMove_Tick
by examining Keyboard.IsKeyDown
.
尝试完全删除keydown处理程序.相反,通过检查GetAsyncKeyState
在tmrMove_Tick
的开头显示nextDirection
,您可以这样声明:
Try removing the keydown handler completely. Instead, figure nextDirection
in the beginning of tmrMove_Tick
by examining GetAsyncKeyState
, which you can declare as follows:
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游戏会冻结吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!