在 vb.net 中按下按钮后如何取消突出显示按钮?

时间:2021-02-11 04:01:56

标签: vb.net

对于我在学校最后一年的主要工作项目,我正在创建一个 Space Invaders 游戏,我正在 VB.NET 上制作它,因为这是我最熟悉的。这将是一个非常冗长的问题,因为有很多因素可能会或可能不会导致我遇到的这个问题。我已经制作了这样的射击系统:

Private Sub SpaceInvaders_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress
    If fired = False Then
        If e.KeyChar = "W" Or e.KeyChar = "w" Then
            shotFired = True
            fired = True
        End If
    End If
End Sub

我使用此代码块来注册玩家是否尝试射击。我会把它放在 KeyDown 命令中,但这允许玩家连续射击,这非常糟糕,让我更难制作平衡的游戏。 shotFired 显示玩家已经射击了这一轮,而射击确保您在将手指从 W 键上移开之前无法再次射击。

Private Sub SpaceInvaders_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp
    Select Case e.KeyCode
        Case Keys.W
            fired = False
    End Select
End Sub

所有这些都是为了确保玩家在释放 W 键后可以再次射击。

Private Sub tmrMovement_Tick(sender As Object, e As EventArgs) Handles tmrMovement.Tick

    If shotFired = True Then
        My.Computer.Audio.Play(My.Resources.Laser_Shoot,
        AudioPlayMode.Background)
        shotFired = False
        bullet(bulletCount).Left = pbPlayer.Left + 25
        bullet(bulletCount).Top = pbPlayer.Top - 25
        bullet(bulletCount).Visible = True
        bulletCount += 1
        If bulletCount = bullet.Length - 1 Then
            bulletCount = 0
        End If
    End If

    For i As Integer = 0 To bullet.Length - 1
        bullet(i).Top -= 5
        If bullet(i).Top < -50 Then
            bullet(i).Visible = False
            bullet(i).Top = Me.Height
        End If
    Next

对于我的拍摄,这是我的程序中目前有问题的区域,我正在制作它,以便有一个音频队列首先播放,并且在后台继续播放时, shotFired 值将立即重置为 false,使其不会在短时间内发射多发子弹。我的子弹的工作方式是它们在一个数组中,当前设置为 20。我射击,我的数组将在直线上移动一个数字,确保最后发射的子弹不会一直移动回相同的位置当我射击时,我可以一次在屏幕上发射多个子弹。我用bulletCount 数字跟踪这个,一旦它等于我数组中的最大子弹数量,它就会重置,使其回到子弹(0),重置并确保我不必制作新子弹每次都想拍。

我让它们移动的方式是,它们每激活一次,它就会向上移动 5。如果它超过 -50,它就会消失并回到起始位置。但是,它不会影响碰撞,因为碰撞首先考虑两个变量是否可见。

无论如何,一旦我为我的游戏创建了菜单,问题就出现了。这是一个简单的菜单,只有一个带有游戏标题的标签,以及一个开始第一关的按钮。但是,一旦我开始第一个级别,我就无法射击。这是点击开始按钮时的代码:

Private Sub btnBegin_Click(sender As Object, e As EventArgs) Handles btnBegin.Click
    Me.KeyPreview = True
    lblTitle.Visible = False
    btnBegin.Visible = False
    pbPlayer.Visible = True
    pbGuard1.Visible = True
    pbGuard2.Visible = True
    pbGuard3.Visible = True
    btnBegin.Enabled = False

    If level = 1 Then
        enemy(0).Visible = True
        enemy(0).Left = 234
        enemy(1).Visible = True
        enemy(1).Left = 193
        tmrLevel1.Enabled = True
    End If
End Sub

我需要将按钮的启用值设为 false,就好像我保持它为真一样,从技术上讲,我的游戏仍然会突出显示它,因此如果玩家点击空格键,游戏将重生所有敌人并回到第 1 级的开始。然而,这成为一个大问题,因为一旦我禁用按钮,我的玩家角色就无法射击。我非常不确定这里的问题是什么,我看不出这两个值之间存在相关性。我试图找到取消突出显示按钮的方法,所以我不必禁用它,因此仍然可以拍摄,但我现在不知道该怎么做。

一旦关卡开始,我如何取消突出显示按钮?我需要禁用某个值吗?如果可能的话,有没有人知道按钮和投篮能力之间的相关性是什么,我该如何解决?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

当您单击 Button 时,它接收输入焦点。如果您想移除该焦点,那么您可以通过调用其 Select 方法来聚焦不同的控件,或者通过将表单的 ActiveControl 属性设置为 Nothing 来完全不聚焦任何控件。

如果您喜欢冒险,那么您实际上可以创建一个最初不会获得焦点的自定义 Button 控件。这是我大约 14 年前写的一个类来做到这一点:

''' <summary>
''' A button control that cannot receive focus.
''' </summary>
Public Class UnselectableButton
    Inherits System.Windows.Forms.Button
 
#Region " Constructors "
 
    ''' <summary>
    ''' Initialises a new instance of the <see cref="UnselectableButton"/> class.
    ''' </summary>
    Public Sub New()
        MyBase.New()
 
        'The button cannot receive focus.
        Me.SetStyle(ControlStyles.Selectable, False)
    End Sub
 
#End Region 'Constructors
 
#Region " Variables "
 
    ''' <summary>
    ''' Corresponds to the MA_NOACTIVATE window process reply.
    ''' </summary>
    Private Shared ReadOnly noActivate As New IntPtr(NativeConstants.MA_NOACTIVATE)
 
#End Region 'Variables
 
#Region " Methods "
 
    ''' <summary>
    ''' Processes Windows messages.
    ''' </summary>
    ''' <remarks>
    ''' Informs Windows not to activate the window when it is clicked with the mouse.  Note that this behaviour applies to the client area of the window only.
    ''' </remarks>
    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        MyBase.WndProc(m)
 
        If m.Msg = NativeConstants.WM_MOUSEACTIVATE Then
            'Tell Windows not to activate the window on a mouse click.
            m.Result = noActivate
        End If
    End Sub
 
    Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
        MyBase.OnClick(e)
    End Sub
 
#End Region 'Methods
 
End Class

如果您将该类添加到您的项目并构建,自定义控件将出现在工具箱的顶部,您可以使用它代替常规的 Button

这是一个包含上面使用的常量的类:

''' <summary>
''' Contains Win32 constant declarations.
''' </summary>
Friend NotInheritable Class NativeConstants
 
    ''' <summary>
    ''' Specifies that a window cannot be activated.
    ''' </summary>
    ''' <remarks>
    ''' If a child window has this style, clicking it does not cause its top-level parent to activate. Although a window that has this style will still receive mouse events, neither it nor its child windows can get the focus.
    ''' </remarks>
    Public Const WS_EX_NOACTIVATE As Integer = &H8000000
 
    ''' <summary>
    ''' This message is sent when the cursor is in an inactive window and the user presses a mouse button.
    ''' </summary>
    Public Const WM_MOUSEACTIVATE As Integer = &H21
 
    ''' <summary>
    ''' Does not activate the window, and does not discard the mouse message.
    ''' </summary>
    ''' <remarks>
    ''' This is one of the possible return values when the <see cref="WM_MOUSEACTIVATE"/> notification is received.
    ''' </remarks>
    Public Const MA_NOACTIVATE As Integer = 3
 
    ''' <summary>
    ''' Displays a window in its most recent size and position. This value is similar to <b>SW_SHOWNORMAL</b>, except the window is not actived.
    ''' </summary>
    ''' <remarks>
    ''' This is one of the possible values for the <b>nCmdShow</b> argument of the <see cref="NativeMethods.ShowWindow">ShowWindow</see> method.
    ''' </remarks>
    Public Const SW_SHOWNOACTIVATE As Integer = 4
 
End Class

您可以按原样使用该类,删除不需要的常量或将需要的常量复制到 UnselectableButton 类。我的原始代码包括许多使用这些常量的其他类。

相关问题