2011-12-24 3 views
1

VB.NET에서 고전적인 스네이크 게임을 만들려고하는데, 게임 중에 키 (모든 키)를 누르고 있으면 몇 초 후에 키를 놓을 때까지 게임이 멈 춥니 다. 이 문제를 해결하기 위해 많은 노력을했지만 아무 것도 작동하지 않습니다. 문제를 이해할 수 없기 때문일 수 있습니다.키를 누르고있을 때 내 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 

코드 업데이트/뱀 (I이 정말 비효율적 알고 있어요) 이동 : 난

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 
+0

이렇게해도 시스템이 해당 이벤트를 계속 발생시키지 않습니다. – UnhandledExcepSean

답변

3

을 키를 누르고 있으면 Form1_KeyDown 함수가 호출되고 몇 초 후에 키가 "계속 누르고있어"모드로 전환되면 해당 함수가 계속 호출되므로 타이머가 작동하지 않는다고 가정합니다 업데이트 할 기회. 하지만 내가 말했듯이, 나는 틀린 것 같다.

사실, 당신 말이 맞습니다.

Windows에서 키를 누르면 바로 WM_KEYDOWN 메시지가 표시되고 일정한 간격이 지나면 다른 특정 간격으로 많은 메시지가 나타납니다 (WM_KEYDOWN).

제어판 - 키보드로 이동하면 이러한 간격을 찾을 수 있습니다.

가장 쉬운 수정 방법은 키 처리기 끝에 DoEvents에 대한 호출을 추가하는 것입니다.

keydown 처리기를 완전히 제거해보십시오. 대신 Keyboard.IsKeyDown을 검토하여 tmrMove_Tick의 시작 부분에 nextDirection을 입력하십시오.

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 
+0

맞습니다. Windows가 보유한 것으로 간주 할 때까지 지연을 변경하면 Snake가 정지하는 데 더 오래 걸립니다. 고마워요. 지금 당장 문제가 생길 거예요. – SiliconCelery

+0

Application.DoEvents()를 이벤트 처리기의 끝에 추가 한 다음 시작하려고 시도했지만 어느 것도 작동하지 않았습니다. – SiliconCelery

+0

@SiliconCelery 확인. 내 편집을 참조하십시오. – GSerg

1

내가 대신 KeyUp 이벤트를 시도하는 것이 좋습니다. 키 누르기 나 keydown 이벤트처럼 스팸하지 않습니다.

+0

정확히 똑같은 문제, 나는 두렵다. – SiliconCelery

+0

keydown 이벤트 사용을 중단 했습니까? Keyup은 키 누르기 1 회만 발생합니다. – UnhandledExcepSean

+0

모든 keyDown을 keyUp로 변경했습니다. 움직임이 부드럽게 보였지만 몇 초 동안 키를 누른 채로는 여전히 멈췄습니다. – SiliconCelery

0

키를 반복하는 중에 문제가 발생했습니다. 나는 과거에 keystate를 보유하고 keypressed 이벤트를 종료하기 위해 변수를 사용했습니다. 지연 시간을 충분히 확보 할 수있는 타이머로 리셋하고 있습니다.

If oldKeyData = e.KeyCode Then 
    e.Handled = True 
    Exit Sub 
End If 

oldKeyData = e.KeyCode 
tmrKeyReset.Enabled = True 

편집 : @SpectralGhosts 대답은 개별 키를 눌러 이동하려는 경우 작동합니다.

+0

느린 것에 대해 용서해주세요. 그렇지만 타이머는 무엇을합니까? 코드가 필요한가요? – SiliconCelery

+0

타이머는 oldKeyData를 다시 설정하여 KeyCode를 다시 처리합니다. 컴퓨터의 글로벌 설정에 영향을 미치지 않고 처리중인 KeyDowns의 속도가 느려지고 있습니다. –

+0

작동하지 않는 것 같습니다. 이 아이디어가 기능을 빠져 ​​나오더라도, 그 기능은 나중에 아무리해도 여전히 즉시 호출되고 타이머에 아무 것도 할 수있는 기회를주지 않는다는 것이 문제가 아닙니까? – SiliconCelery

관련 문제