对于我在学校最后一年的主要工作项目,我正在创建一个 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 级的开始。然而,这成为一个大问题,因为一旦我禁用按钮,我的玩家角色就无法射击。我非常不确定这里的问题是什么,我看不出这两个值之间存在相关性。我试图找到取消突出显示按钮的方法,所以我不必禁用它,因此仍然可以拍摄,但我现在不知道该怎么做。
一旦关卡开始,我如何取消突出显示按钮?我需要禁用某个值吗?如果可能的话,有没有人知道按钮和投篮能力之间的相关性是什么,我该如何解决?任何帮助将不胜感激。
答案 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
类。我的原始代码包括许多使用这些常量的其他类。