确定XNA游戏的延迟问题

6
我正在使用C#和XNA创建一款塔防游戏。游戏运行良好,流畅无卡顿,但在玩了一段时间(敌人/塔/子弹已经生成)后,游戏似乎会呈指数级减速。即使清除所有实例,卡顿仍然存在。
起初我认为这可能与垃圾回收有关(也许是),但为了测试它,我编写了析构函数来打印对象何时被回收,一切看起来都很好(所有对象都被回收)。所以我很好奇是否有人有XNA卡顿的经验以及可能的原因?
编辑:这是针对PC的。

建议:一个更好的(总体)问题可能是->我该怎么做才能确定延迟发生在哪里?看起来这可能是由很多不同的事情引起的,我们需要看到你的很多代码才能确定延迟问题的根本原因。 - Josh Darnell
有太多的代码需要查看。我更多地是在寻求理论解决方案或延迟可能原因。目前没有涉及网络,所以这不应该是一个问题。 - Hanna
1
我建议的一件事是在进入和退出较大的子程序/可疑区域时打印时间戳(到调试日志文件或其他地方)。这样,您就可以看到您失去时间的地方,并向内部解决问题。 - Josh Darnell
创建堆转储可能有助于识别问题,如果您获取多个堆转储并进行比较,您可能能够看到哪些对象一直存在。此链接可能有所帮助:http://msdn.microsoft.com/en-us/library/bb975827.aspx - Stuart Thomson
这是在360、PC还是WP7上? - scottheckel
这是考虑到计算机的制作。 - Hanna
4个回答

1

1
如果您担心垃圾回收会影响性能,那么您可以学习使用CLR Profiler这个工具。该实用程序允许您对程序执行的堆分配进行分析,以便您可以确定生成垃圾的确切方法。请记住,许多不明显的事情都可以分配到堆上:字符串连接、枚举键索引字典、闭包、委托等等。即使是一点点垃圾,在每秒60帧的情况下,也可能在适当的情况下快速累积。
话虽如此,根据您所描述的情况,我认为这并不像是垃圾回收的问题。即使在完整的回收过程中,GC通常也足够快,只会导致少数帧被丢弃--换句话说,您会偶尔注意到一个小的、令人烦恼的抖动,但不会有持续的减速。
(警告:这仅适用于PC,与其他XNA平台相比,PC具有非常复杂的GC。)
你应该尝试将分析器附加到你的代码上,以确定哪些方法需要最长时间才能完成;如果你的问题与垃圾回收无关,这可能会提供有用信息。过去,我曾使用EQATEC,尽管我在一些较新版本中遇到了一些问题。你可以尝试使用它,或者在谷歌上寻找其他替代方案。

0
游戏循环时间是否增加?在Update循环和Draw循环的开头和结尾添加秒表。如果时间正在增加,请尝试排除(移动stopwatch.Start()和/或stopwatch.Stop()),直到找到导致减速的原因。如果时间没有增加,则是由其他原因引起的。
尝试将此行代码添加到代码中:
SpriteBatch.DrawInt64(Font, GC.GetTotalMemory(false) / 1000 /* in kilobytes */,
POSITION, Color.White, 0f);

DrawInt64/32是一个非常有用的扩展,可以让您在不生成垃圾的情况下绘制数字,可在此处获得:http://pastebin.com/pVw66mGy。或者只需使用DrawString和.ToString()。

每当显示的数字减少时,都会运行垃圾收集。


一个更好的确定垃圾回收是否正在发生的方法是使用GC.CollectionCount()。这将允许您查看每个单独的代被收集的时间。0代收集可能不太重要;当涉及到性能时,1代和2代收集则更为重要。 - Cole Campbell

0

你不会忘记取消事件绑定了吧?在下面的例子中,我将4个精灵添加到列表中,每个精灵都从游戏中绑定了一个事件。然后我删除一个精灵并触发该事件。

在这种情况下,所有4个精灵仍然处于活动状态,并且因为它们在游戏中仍然有引用,所以它们的事件被触发了。

只是一个想法,如果你正在为你的游戏对象使用事件,那么你可能会让它们一直运行下去。

class Game
{
  public event EventHandler SomeEvent;
  List<Sprite> sprites;

  public Game()
  {
    sprites = new List<Sprite>();
    sprites.Add(new Sprite(this));
    sprites.Add(new Sprite(this));
    sprites.Add(new Sprite(this));
    sprites.Add(new Sprite(this));

    sprites.RemoveAt(0);

    EventHandler temp = SomeEvent;
    if (temp != null)
    {
        temp(this, EventArgs.Empty);
    }
  }

  static void Main(string[] args)
  {
      Game newProgram = new Game();
  }



  class Sprite
  {
      public Sprite(Game gameReference)
      {
          gameReference.SomeEvent += new EventHandler(gameReference_SomeEvent);
      }

      void gameReference_SomeEvent(object sender, EventArgs e)
      {
          Debug.WriteLine("Event");
      }    
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接