我写的弹跳球的代码(过去有效,从内存中重新创建)是行不通的。当球应该从侧面反射并沿着那个方向继续时,它只是恢复并再次击中墙壁。击中球后,球在两个位置之间闪烁。
Public Class Form1
Dim XVel As Integer = 10
Dim YVel As Integer = 20
Dim XPos As Integer = 12
Dim YPos As Integer = 12
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
pbBall.Left = XPos
pbBall.Top = YPos
Label1.Text = XPos
Label2.Text = YPos
Label3.Text = YVel
Label4.Text = XVel
XPos += XVel
YPos += YVel
If pbBall.Top <= 0 Then
YVel = YVel * -1
End If
If pbBall.Left <= 0 Then
XVel = XVel * -1
End If
If pbBall.Bottom >= Me.Height Then
YVel = YVel * -1
End If
If pbBall.Right >= Me.Width Then
XVel = XVel * -1
End If
End Sub
End Class
我不知道出了什么问题,而且现在已经搞错了一两个小时了。
答案 0 :(得分:1)
如果Top
变为0,XPos
= - 1,则更改方向。
下一轮,Top变为-1,XPos = 0,然后再次更改直接。你将永远重复这一点。
更改所有方向时,应重新计算XPos和YPos。例如:
If pbBall.Right >= Me.Width Then
XVel = XVel * -1
End If
XPos = pbBall.Left
YPos = pbBall.Top
XPos += XVel
YPos += YVel
答案 1 :(得分:1)
代码的作用:
比如,你的框架高度为100像素,你的球的大小(直径)为10像素
然后,你的球以20(正)的速度向下移动,当时距离顶部80像素(在底部框架上方)
调用Timer1_Tick时会发生什么:
pbBall.Top = YPos ' which were calculated from the previous call
' pbBall.Top becomes 100 (which were 80 + 20)
' ...
YPos += YVel ' prepares the next location, YPos becomes 100 + 20 = 120
' ...
' Then comes your conditional tests :
If pbBall.Bottom >= Me.Height Then
YVel = YVel * -1 ' YVel => 20 * -1 = -20
End If
' pbBall.Bottom is .Top + .Size = 100 + 10 = 110
' so the condition is True, so YVel becomes -20
' Sound good isn't it ?
' BUT IT ISN'T !
在Timer1_Tick被称为secund时间之前,你的pbBall.Top是100,你的YVel是-20。应该上去,但它不会...
pbBall.Top = YPos ' .. and YPos were 120,
' because Velocity +20 were added before it was switched to -20
' your ball is now way below the frame.
' ...
YPos += YVel ' where YVel were switched to -20 as expected.
' But 120 - 20 = 100
' Note that top position "100" will be used the NEXT time Timer1_Tick is called,
' NOT at the moment the condition test performed below occurs..!
' ANYWAY, your If condition is True one more time :
If pbBall.Bottom >= Me.Heigt Then ' Bottom = 120 + 10 = 130
YVel = YVel * -1 ' YVel = -20 * - 1 = 20 => Your ball will go down again !
End If
' When Timer1_Tick is called again, the Ball will rise at 110,
' but next location will move it down again at 130...
' and again, and again...
一个简单的事情就是修复基本的算法:移动这段代码:
XPos += XVel
YPos += YVel
你的Timer1_Tick方法的最后 (在End Sub之前)这将更新球的NEXT位置 AFTER 速度已被切换并阻止你的球溢出边界TWICE。实际上,当你的球碰到一个边界时,你的代码不会让它立即反弹,而是让它再一次进行。所以,它被困在一个无尽的速度开关......
旁注:
这是我在StackOverflow上的第9篇文章。对不起,如果还不合适的话。对不起,如果它很长..我说法语,我不确定我写的是正确的。我不是专家,我可能错了;随便纠正我:)我只是喜欢VB,看到了这个问题,以为我可以帮忙,瞧!“
附注2:
我不知道提出建议是否合适,但是:
如果你只处理一个球,为什么不使用比控制小一点的框架结构(边缘球的大小)并假设你的球是一个点(点)这允许你丢弃右,底和尺寸属性。当然,从你想要更多可以碰撞的球的那一刻起,这种方法就变得毫无用处。
关于球可以溢出边界的事实(即使有修复)你可以想到更准确的球的下一个位置的计算,(XPos = XVel - 当球与左侧碰撞时的XPos边界。在右边,它有点复杂)
您还可以使用IsMovingLeft As Boolean
(IsMovingUp
)来避免每次将X / YVel乘以-1。只是一个建议虽然:)
最后,我会把XVel和YVel作为Ball的属性,而不是全局变量,这样,我可以有多个不同速度的球。