如何加快VB.NET中的游戏速度

时间:2012-04-18 17:40:16

标签: vb.net optimization

正如标题所暗示的那样,我在问一个关于我制作的游戏的问题,我想加快速度。这是一个非常普遍的问题。所以这里是: 我制作了一个程序,你是一个圆圈,敌人就是正方形。按空格键进行射击,每次击中时都会获得分数,使用箭头键移动,有拾音器等等。

但是,我不再想使用这样绘制的占位符圈:

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,所以它不会再这样做了。

接下来,它会移动表单上的所有对象。这些包括物体,射弹和拾音器。它还会检查它们是否已经到达“路径”的末端(即如果射弹远远超出右侧,则将其从游戏中移除)。

最后,它会检查玩家是否赢了,并更新一个告诉玩家得分的标签。然后重绘。

想法?

2 个答案:

答案 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 = 0PickUpType = 1

(4)使用PickUpType = 2http://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。