【问题标题】:Scrolling lag during draw绘制期间的滚动延迟
【发布时间】:2016-03-08 09:15:08
【问题描述】:

我已经开始使用 xna/monogame 开发一款新游戏。我之前设计了一些 2D 游戏,但决定制作这款等距游戏,这对我来说是新的。我一直在使用 reimers 等距平铺引擎教程,并且大多数最简单的绘图代码都是这个的副本。

在地图上滚动时,屏幕上会出现卡顿,我只能将其描述为延迟。我设置了一个 FPS 计数器,它一直保持在 60,所以我相信这是某种图形问题。

我已尝试注释掉绘图代码的部分以缩小问题范围,但似乎无法取得任何进展,但几周前并没有发生这种情况,所以我相信这是我添加的内容,可能是一个问题与导致它的图块集有关吗?

感谢任何建议。我没有在这里放任何代码,因为它变成了一个相当大的项目,我不知道该专注于哪个领域,但如果有人愿意调查,我已经上传了整个项目here

【问题讨论】:

  • Micky,什么部分有用?昨晚我进行了更深入的测试,当游戏第一次开始时似乎更糟,在滚动一段时间后几乎停止,几乎就像它在你第一次看到它们时加载纹理并且在那之后工作正常一样。跨度>
  • .NET 游戏中的卡顿可能是由 GC 启动引起的。请查看 Shawn Hargreaves 和 Riemer 在各自 XNA 博客中的提示。至于启动滞后,您是否会做任何形式的按需加载资产?
  • 谢谢,我会看看。我没有加载按需加载,想知道 XNA 是否自己做任何事情,但我很确定情况并非如此?

标签: xna 2d monogame


【解决方案1】:

Tl;dr 您正在对DrawMiniMap 方法的每次调用 创建一个名为dummyTexture 的新Texture2D 实例(1x1 像素)。这是一个坏主意,因为每次都需要将纹理发送到 GPU(然后处理和收集)。添加一个名为dummyTexture 的字段,并在LoadContent 中对其进行完全初始化。

但请阅读帖子的其余部分,了解如何识别这些问题。

您的 Update 方法以 60fps 的速度被调用,但 Draw 方法也不一定如此。由于Game.IsFixedTimeStep 默认设置为true,一旦Monogame 发现Draw 的完成时间比预期的要长,您的Draw 方法就会跳帧。

由于您现在编写游戏逻辑的方式,这是 Monogame 确保所有更新都在固定时间步长内完成的唯一方法。

为了更好地了解正在发生的事情,首先为Draw 方法 fps 创建一组额外的 fps 变量,然后在屏幕上渲染这两个值。您会看到 Update 以 60 fps 的速度绘制,但 Draw 低于该速度。

protected override void Draw(GameTime gameTime)
{
    // similar to what you have inside `Update`
    drawFpsTimer += gameTime.ElapsedGameTime;
    drawFpsCount++;
    if (drawFpsTimer >= TimeSpan.FromSeconds(1))
    { drawFpsTimer = TimeSpan.FromSeconds(0); drawFps = drawFpsCount; drawFpsCount = 0; }

    ...

有了这个,就很容易在Draw 中查明有问题的方法,并将你的 fps 恢复到 60。

此外,通过将IsFixedTimeStep 设置为false,您可以同时调用UpdateDraw,但您的Update 帧速率也会下降——这意味着您应该更改所有更新逻辑使用gameTime.ElapsedGameTime 而不是假定固定步骤:

protected override void Initialize()
{
    // use variable time step
    this.IsFixedTimeStep = false;
    this.TargetElapsedTime = TimeSpan.FromSeconds(1 / 60.0);
    this.graphics.SynchronizeWithVerticalRetrace = true;

    ...

在我的所有项目中,我更喜欢可变时间步长,尤其是当您发现 XNA sometimes takes up 100% CPU time on one core when the default value of Game.IsFixedTimeStep is used,但准备好进行一些重构时。

至于 为什么 帧被跳过,似乎是 DrawMiniMap 方法有问题。对此发表评论会在我的机器上提供 60 fps 更新 + 60 fps 绘制速率。

经过进一步检查,发现您在每次调用此方法时创建了一个名为 dummyTexture 的新 Texture2D 实例(1x1 像素)。这是一个坏主意。添加一个名为dummyTexture 的字段并在LoadContent 中完全初始化它。您还可以通过使tileColour 成为Tile 类的成员来稍微加快此方法的速度,以避免在每次迭代中进行大量if 测试,但可能有很多这样的优化,除非您是部署到移动设备。

【讨论】:

  • 感谢您提供的所有信息,非常有帮助,我将对此进行研究。我会注意到小地图代码是新添加的,在那之前我遇到了问题。不过完全忘记移动虚拟纹理了,谢谢提醒! :p
  • 真的很好读,不是每个人都会从标记为可疑的网站下载文件并调试/阅读除相关文件之外的所有文件以写出详细的答案。
  • @user3218507:嗯,这就是我在我的机器上看到的。对于这样一个看似简单的游戏,游戏已经奇怪地cpu沉重了;例如如果我禁用 vsync 并注释掉除 DrawCursor 部分(这是您绘制 fps 的地方)之外的所有内容,帧速率将达到 ~400fps,正如预期的那样。但是,随着一切都被绘制出来,帧速率接近 80fps(禁用垂直同步),这意味着你没有太多空间了。因此,我建议您使用分析器并尝试找出所有其他瓶颈。
  • 我有一些想法可能是什么原因造成的。我一直误以为我有一个恒定的 60 fps 哈哈。感谢大家的帮助,希望我现在可以解决问题
  • @user3218507:如果你在使用 VS2015 社区,你有一个分析器,所以使用它来避免在错误的地方进行优化。此外,现在我仔细查看了DrawMiniMap,这肯定是有问题的,因为它会为地图上的每个像素进行大量绘制。在我的机器上,它几乎负责Draw 内花费的所有 CPU。您应该重写它以绘制到屏幕外缓冲区并使用此数据更新纹理(切勿在 DrawUpdate 内创建新实例)。
猜你喜欢
  • 1970-01-01
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多