因此,我正在为我的编程课制作游戏,这是我最终项目的一部分。目前,我正处于计划和试验阶段,因此决定在图形和碰撞方面抢占先机。我首先通过尝试VB必须提供的Graphics
类而不是使用PictureBox
es来编写程序。除此之外,我还添加了键盘输入来移动Image
。当我决定通过intersectsWith()
类的Image
方法添加碰撞检测时,事情变得很奇怪。
[基本上,在我的代码中,“玩家”实体具有三个不同的图像-图像的变化取决于它们所面对的方式,而图像又取决于用户所按下的键。没有任何碰撞检测代码,移动和图像更改就可以正常工作,并且图像可以移动。但是,一旦添加了碰撞检测功能,玩家就根本不会移动,只会改变他们面对的方式。即使玩家的Image
不在我要测试交叉点(美元符号)的图像附近,也会发生这种情况。这是我的完整代码:
Public Class Form1
Enum DirectionFacing
FORWARDS
BACKWARD
LEFT
RIGHT
End Enum
' Player X position.
Dim pX As Integer = 100
' Player Y position.
Dim pY As Integer = 100
' The direction the player is facing - by default, backward.
Dim dir As DirectionFacing = DirectionFacing.BACKWARD
' The image of the player.
Dim pI As Image = My.Resources.MainCharacter_Forward
' Another image designed to test for collision detection.
Dim dI As Image = My.Resources.DollarSign
Private Sub Form1_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
If (e.KeyCode = Keys.W) Then
' If they press W, move forward.
dir = DirectionFacing.FORWARDS
pI = My.Resources.MainCharacter_Forward
movePlayer(DirectionFacing.FORWARDS, 10)
ElseIf (e.KeyCode = Keys.S) Then
' If they press S, move backward.
dir = DirectionFacing.BACKWARD
pI = My.Resources.MainCharacter_Behind
movePlayer(DirectionFacing.BACKWARD, 10)
ElseIf (e.KeyCode = Keys.A) Then
' If they press A, move to the left.
pI = My.Resources.MainCharacter_Side
dir = DirectionFacing.LEFT
movePlayer(DirectionFacing.LEFT, 10)
ElseIf (e.KeyCode = Keys.D) Then
' If they press D, move to the right. To make the player face rightward,
' the image can be flipped.
Dim flipped As Image = My.Resources.MainCharacter_Side
flipped.RotateFlip(RotateFlipType.RotateNoneFlipX)
pI = flipped
dir = DirectionFacing.LEFT
movePlayer(DirectionFacing.RIGHT, 10)
End If
End Sub
' Moves the player by a certain amount AND checks for collisions.
Private Sub movePlayer(dir As DirectionFacing, amount As Integer)
If (dI.GetBounds(GraphicsUnit.Pixel).IntersectsWith(pI.GetBounds(GraphicsUnit.Pixel))) Then
Return
End If
If (dir = DirectionFacing.FORWARDS) Then
pY -= 10
ElseIf (dir = DirectionFacing.BACKWARD) Then
pY += 10
ElseIf (dir = DirectionFacing.LEFT) Then
pX -= 10
ElseIf (dir = DirectionFacing.RIGHT) Then
pX += 10
End If
End Sub
Private Sub draw(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
Dim g As Graphics = e.Graphics()
g.DrawImage(dI, 400, 350)
g.DrawImage(pI, pX, pY)
Me.Invalidate()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.DoubleBuffered = True
End Sub
End Class
[基本上,每次我按下一个键并想要移动图像时,图像都不会移动(即使当播放器距离美元符号不远时也是如此),但是它们所面对的方向仍然会改变。如何保持播放器移动并仍然阻止播放器与其他图像碰撞?
嗯,>]
If (dI.GetBounds(GraphicsUnit.Pixel).IntersectsWith(pI.GetBounds(GraphicsUnit.Pixel)))
将始终返回False
,因为GetBounds
方法不会返回每个矩形的当前位置。因此它们永远不会相交,并且您的绘图场景保持不变。
所以让我们尝试解决这个问题。
Enum DirectionFacing FORWARDS BACKWARD LEFT RIGHT End Enum ' The image of the player. Dim pI As New Bitmap(My.Resources.MainCharacter_Forward) ' Another image designed to test for collision detection. Dim dI As New Bitmap(My.Resources.DollarSign) 'The rectangle of the player's image. Dim pIrect As New Rectangle(100, 100, pI.Width, pI.Height) 'The static rectangle of the collision's image. Dim dIrect As New Rectangle(400, 350, dI.Width, dI.Height)
现在
IntersectWith
功能应该可以在movePlayer
方法中使用:
Private Sub movePlayer(dir As DirectionFacing, amount As Integer) Dim px = pIrect.X Dim py = pIrect.Y Select Case dir Case DirectionFacing.FORWARDS py -= amount Case DirectionFacing.BACKWARD py += amount Case DirectionFacing.LEFT px -= amount Case DirectionFacing.RIGHT px += amount End Select If Not New Rectangle(px, py, pI.Width, pI.Height).IntersectsWith(dIrect) Then pIrect = New Rectangle(px, py, pI.Width, pI.Height) Invalidate() End If End Sub
注意,
px
和py
变量现在都是本地变量,因为我们已经有pIrect
,其中包括当前的x
和y
。我认为,将If
语句替换为Select Case
是更好的方法。我们创建了一个新的矩形以检查是否可能发生碰撞,如果没有,则更新pIrect
并刷新图形。
除了通过W
S A D键移动图像之外,您还可以使用&leftarrow; &uparrow; < [&rightarrow; &downarrow;键。要在KeyDown
事件中拦截它们,只需重写IsInputKey
函数,如下所示:Protected Overrides Function IsInputKey(keyData As Keys) As Boolean
Select Case keyData And Keys.KeyCode
Case Keys.Left, Keys.Up, Keys.Right, Keys.Down
Return True
Case Else
Return MyBase.IsInputKey(keyData)
End Select
End Function
因此,KeyDown
事件:
Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
Select Case e.KeyCode
Case Keys.W, Keys.Up
pI?.Dispose()
pI = New Bitmap(My.Resources.MainCharacter_Forward)
movePlayer(DirectionFacing.FORWARDS, 10)
Case Keys.S, Keys.Down
pI?.Dispose()
pI = New Bitmap(My.Resources.MainCharacter_Behind)
movePlayer(DirectionFacing.BACKWARD, 10)
Case Keys.A, Keys.Left
pI?.Dispose()
pI = New Bitmap(My.Resources.MainCharacter_Side)
movePlayer(DirectionFacing.LEFT, 10)
Case Keys.D, Keys.Right
pI?.Dispose()
pI = New Bitmap(My.Resources.MainCharacter_Side)
pI.RotateFlip(RotateFlipType.RotateNoneFlipX)
movePlayer(DirectionFacing.RIGHT, 10)
End Select
End Sub
同样,我们将If Then Else
语句替换为Select Case
。如果您不应该这样做,我相信您可以轻松还原和使用If e.KeyCode = Keys.W OrElse e.KeyCode = Keys.Up Then ...
。
Paint
例程:
Private Sub draw(sender As Object, e As PaintEventArgs) Handles Me.Paint
Dim g As Graphics = e.Graphics()
g.DrawImage(dI, dIrect)
g.DrawImage(pI, pIrect)
End Sub
最后,不要忘了清理:
Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
pI?.Dispose()
dI?.Dispose()
End Sub
祝你好运
嗯,>]
If (dI.GetBounds(GraphicsUnit.Pixel).IntersectsWith(pI.GetBounds(GraphicsUnit.Pixel)))
将始终返回False
,因为GetBounds
方法不会返回每个矩形的当前位置。因此它们永远不会相交,并且您的绘图场景保持不变。
所以让我们尝试解决这个问题。
Enum DirectionFacing FORWARDS BACKWARD LEFT RIGHT End Enum ' The image of the player. Dim pI As New Bitmap(My.Resources.MainCharacter_Forward) ' Another image designed to test for collision detection. Dim dI As New Bitmap(My.Resources.DollarSign) 'The rectangle of the player's image. Dim pIrect As New Rectangle(100, 100, pI.Width, pI.Height) 'The static rectangle of the collision's image. Dim dIrect As New Rectangle(400, 350, dI.Width, dI.Height)
现在
IntersectWith
功能应该可以在movePlayer
方法中使用:
Private Sub movePlayer(dir As DirectionFacing, amount As Integer) Dim px = pIrect.X Dim py = pIrect.Y Select Case dir Case DirectionFacing.FORWARDS py -= amount Case DirectionFacing.BACKWARD py += amount Case DirectionFacing.LEFT px -= amount Case DirectionFacing.RIGHT px += amount End Select If Not New Rectangle(px, py, pI.Width, pI.Height).IntersectsWith(dIrect) Then pIrect = New Rectangle(px, py, pI.Width, pI.Height) Invalidate() End If End Sub
注意,
px
和py
变量现在都是本地变量,因为我们已经有pIrect
,其中包括当前的x
和y
。我认为,将If
语句替换为Select Case
是更好的方法。我们创建了一个新的矩形以检查是否可能发生碰撞,如果没有,则更新pIrect
并刷新图形。
除了通过W
,S,A和D键移动图像之外,您还可以使用箭头键。要在KeyDown
事件中拦截它们,只需重写IsInputKey
函数,如下所示:Protected Overrides Function IsInputKey(keyData As Keys) As Boolean Select Case keyData And Keys.KeyCode Case Keys.Left, Keys.Up, Keys.Right, Keys.Down Return True Case Else Return MyBase.IsInputKey(keyData) End Select End Function
因此,
KeyDown
事件:
Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown Select Case e.KeyCode Case Keys.W, Keys.Up pI?.Dispose() pI = New Bitmap(My.Resources.MainCharacter_Forward) movePlayer(DirectionFacing.FORWARDS, 10) Case Keys.S, Keys.Down pI?.Dispose() pI = New Bitmap(My.Resources.MainCharacter_Behind) movePlayer(DirectionFacing.BACKWARD, 10) Case Keys.A, Keys.Left pI?.Dispose() pI = New Bitmap(My.Resources.MainCharacter_Side) movePlayer(DirectionFacing.LEFT, 10) Case Keys.D, Keys.Right pI?.Dispose() pI = New Bitmap(My.Resources.MainCharacter_Side) pI.RotateFlip(RotateFlipType.RotateNoneFlipX) movePlayer(DirectionFacing.RIGHT, 10) End Select End Sub
同样,我们将
If..Then..Else
语句替换为Select Case
。如果您不应该这样做,我相信您可以轻松还原和使用If e.KeyCode = Keys.W OrElse e.KeyCode = Keys.Up Then ...
。
Paint
例程:
Private Sub draw(sender As Object, e As PaintEventArgs) Handles Me.Paint Dim g As Graphics = e.Graphics() g.DrawImage(dI, dIrect) g.DrawImage(pI, pIrect) End Sub
最后,不要忘了清理:
Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed pI?.Dispose() dI?.Dispose() End Sub
祝你好运