正如标题所暗示的那样,我在问一个关于我制作的游戏的问题,我想加快速度。这是一个非常普遍的问题。所以这里是: 我制作了一个程序,你是一个圆圈,敌人就是正方形。按空格键进行射击,每次击中时都会获得分数,使用箭头键移动,有拾音器等等。
但是,我不再想使用这样绘制的占位符圈:
e.Graphics.FillEllipse(Brushes.Orange,Player)
这里的玩家是定义玩家的矩形。因此,为了尝试替换图形,我下载了一个JPEG图像,即地球(玩家)和太空船(敌人)。我用它绘制了它:
e.Graphics.DrawImage(ImgEarth,Player.X,Player.Y,Player.Width,Player.Height)
和绘制敌人的技术相同。
然而,移动外星人的结果非常缓慢。它不是一个慢速计时器或任何东西(我有两个同时工作)但FPS很差。它可能是我的系统但是当我检查它时只需要大约10MB的内存。我知道VB.NET不是游戏制作的首选,因为它不像其他一些语言(C ++,C#)那么快,但有什么方法可以在不牺牲FPS的情况下绘制它们吗?
如果有帮助,我有一个配备GeForce 8400M GS的1.66 GHz处理器。 (在我看来,能够做到这么简单的事情)
编辑:我使用双缓冲。Me.DoubleBuffered = True
。 ImgEarth是一张310x310的图像。我会尝试缩小它,因为在表格上它被绘制为50x50 - 好点。
好的,这是整个Form1.Paint程序。我会在它之后解释一切。
e.Graphics.DrawImage(ImageEarth, Player.x,Player.y,Player.Width,Player.Height)
'Projectiles
Dim i As Integer = 0
Do
If Current_Projectile(i).IsEmpty = False Then e.Graphics.FillRectangle(Brushes.Red, Current_Projectile(i))
i += 1
Loop Until i = UBound(Current_Projectile)
i = 0
Do
If Advanced_Projectiles(i).IsEmpty = False Then e.Graphics.FillRectangle(Brushes.Green, Advanced_Projectiles(i))
i += 1
Loop Until i = UBound(Advanced_Projectiles)
i = 0
Do
If Pickups(i).IsEmpty = False Then
If PickUpType = 0 Then e.Graphics.FillEllipse(Brushes.Green, Pickups(i))
If PickUpType = 1 Then e.Graphics.FillEllipse(Brushes.Red, Pickups(i))
If PickUpType = 2 Then e.Graphics.FillEllipse(Brushes.Yellow, Pickups(i))
End If
i += 1
Loop Until i = UBound(Pickups)
'Objects
i = 0
Do
If Objects(i).IsEmpty = False Then e.Graphics.FillRectangle(Brushes.Blue, Objects(i))
i += 1
Loop Until i = UBound(Objects)
好。 Current_Projectile是一个数组,存储有关玩家(子弹)发射的射弹的数据。然后,高级抛射物是相同的,除了它发射前者更“强大”的版本。 Pickups是一个数组,存储有关向玩家发射的拾取器的数据。它的颜色在另一个子程序中确定。最后,对象(i)是一个数组,用于存储有关向您射击的敌方矩形的数据。
编辑2:好的,想你们可能需要Timer.Tick程序。
计时器名为Tmr_Main,它处理游戏过程中发生的所有事情的约90%。它将大部分工作委托给单独的子程序,但有些是在计时器本身完成的。这是整个表单中第二个最复杂的代码块。这是:
Dim i As Integer = 0
CollisionDetect()
CheckForDead()
If ReadyToReset = True Then ResetInt += 1
If ResetInt = 80 Then
ResetPowerUps()
ReadyToReset = False
ResetInt = 0
End If
'Projectiles(Bullets)
i = 0
Do
If Current_Projectile(i).IsEmpty = False Then
Current_Projectile(i).X += Projectile_Speed
If Current_Projectile(i).X > Me.Width Then
Current_Projectile(i) = Nothing
No_Of_Projectiles -= 1
End If
End If
i += 1
Loop Until i = UBound(Current_Projectile)
'Advanced Projectiles
i = 0
Do
If Advanced_Projectiles(i).IsEmpty = False Then
Advanced_Projectiles(i).X += AdvProjectile_Speed
End If
If Advanced_Projectiles(i).X >= Me.Width Then
Advanced_Projectiles(i) = Nothing
End If
i += 1
Loop Until i = UBound(Advanced_Projectiles)
'Pickups
GeneratePickups()
i = 0
Do
If Pickups(i).IsEmpty = False Then
Pickups(i).X -= Pickup_Speed
End If
If Pickups(i).X < 0 Then
Pickups(i) = Nothing
End If
i += 1
Loop Until i = UBound(Pickups)
LblScore.Text = "Score: " & Score
CheckForWin()
Me.Invalidate()
好的,再一次,从顶部解释一切。 CollisionDetect()
包含用于评估整个游戏中的内容的逻辑。这包括玩家和皮卡,玩家和物体,物体和弹丸,物体和高级弹丸,物体和玩家。接下来,它评估是否使用了拾取器。当玩家点击拾取时,布尔值设置为true。这意味着此计时器的每次迭代都会添加到变量ResetInt
。当它达到80或4秒(50ms计时器)时,拾音器的效果会被重置。另外,布尔值为false,所以它不会再这样做了。
接下来,它会移动表单上的所有对象。这些包括物体,射弹和拾音器。它还会检查它们是否已经到达“路径”的末端(即如果射弹远远超出右侧,则将其从游戏中移除)。
最后,它会检查玩家是否赢了,并更新一个告诉玩家得分的标签。然后重绘。
想法?
答案 0 :(得分:3)
尝试一些想法......
(1)使用Option Strict On
,它至少会引导您远离任何低效的自动类型转换。
(2)而不是Do ... Loop Until i = UBound( ... )
使用For i = 0 To UBound( ... ) - 1
(除非你真的期望数组在循环期间可能添加或丢失元素); For
只会调用UBound
一次,Do
会在每次迭代时调用它。更好的是,为什么不使用Length
数组成员而不是UBound
?
(3)对于那些测试If
的{{1}}语句,请使用If-ElseIf阶梯:
PickUpType
毕竟,如果If PickUpType = 0 Then
e.Graphics.FillEllipse(Brushes.Green, Pickups(i))
ElseIf PickUpType = 1 Then
e.Graphics.FillEllipse(Brushes.Red, Pickups(i))
ElseIf PickUpType = 2 Then
e.Graphics.FillEllipse(Brushes.Yellow, Pickups(i))
End If
,为什么要浪费时间PickUpType = 0
和PickUpType = 1
?
(4)使用PickUpType = 2
(http://msdn.microsoft.com/en-us/library/wc500chb(v=vs.100).aspx)进行实验。而不是:
With
尝试:
If Advanced_Projectiles(i).IsEmpty = False Then
Advanced_Projectiles(i).X += AdvProjectile_Speed
End If
(5)如果你在Microsoft.VisualBasic命名空间(例如UBound)中使用任何东西(不是常数),试着找到一种方法来在框架的更“标准”部分完成相同的操作。 Microsoft.VisualBasic可能有你可能不需要的额外图层或VB6怪癖。
答案 1 :(得分:1)
你应该使用双缓冲。这是您执行所有绘画和绘制到内存位图以响应游戏事件等的地方。然后在您的OnPaint中,您对该缓冲区的屏幕执行单个blit。