【问题标题】:OutOfMemoryException when trying to draw tile map尝试绘制平铺地图时出现 OutOfMemoryException
【发布时间】:2011-12-04 04:38:23
【问题描述】:

我正在尝试用 C# 绘制平铺地图,而我遇到的问题在我看来很奇怪。

我有这个 int 数组,它应该保存 x 坐标和 y 坐标以在屏幕上绘制图块。 (不只有0的箭头是X,另一个是Y)

int[,] level1 = { { 0, 32, 64, 96 }, { 0, 0, 0, 0 } };

这是我如何使用 for 循环将图块的一部分渲染到屏幕上的方法,在这里我将在一行上得到一个“OutOfMemoryException”,我将对其进行注释:

public void DrawTest(SpriteBatch spriteBatch)
    {
        for (int x = 0;; x++)
        {
            for (int y = 0;; y++)
            {
                x = level1[x, 0];
                y = level1[0, y];

                //This line bellow is where it says OutOfMemoryException
                spriteBatch.Draw(tileSheet, new Rectangle(x, y, 32, 32), new Rectangle(0, 0, 32, 32), Color.White);

                if (x >= 5 | y >= 5)
                {
                    x = 0;
                    y = 0;
                }
            }
        }
    }

当我想调用这个渲染方法时,我会在主类渲染方法中执行它

levelLoader.DrawTest(this.spriteBatch);

在我使用此 DrawTest 方法尝试绘制瓷砖之前,它运行良好。但我完全不知道为什么这不能正常工作。

更新:

public void DrawTest(SpriteBatch spriteBatch)
        {
            for (int x = 0; x < 5 ; x++)
            {
                for (int y = 0; y < 5 ; y++)
                {
                    x = level1[x, 0];
                    y = level1[0, y];
                    spriteBatch.Draw(tileSheet, new Rectangle(x, y, 32, 32), new Rectangle(0, 0, 32, 32), Color.White);
                }
            }
        }

更新 2:

        public void DrawTest(SpriteBatch spriteBatch)
    {
        for (int x = 0; x < 5 ; x++)
        {
            for (int y = 0; y < 5 ; y++)
            {
                int tileXCord = level1[x, 0];
                int tileYCord = level1[0, y];
                spriteBatch.Draw(tileSheet, new Rectangle(tileXCord, tileYCord, 32, 32), new Rectangle(0, 0, 32, 32), Color.White);
            }
        }
    }

【问题讨论】:

  • 您可能尝试批量处理无限数量的绘图调用。你想用这个奇怪的循环做什么?
  • 我正在尝试创建一个类来绘制我正在制作的游戏地图..

标签: c# xna out-of-memory


【解决方案1】:

我在您的代码中发现了几个问题:

  1. 您的代码中有无限循环。嵌套循环的终止条件是什么?
  2. (重要!)spriteBatch.Draw() 方法不绘制任何东西,它只是安排你的精灵的绘制。此方法调用应该在spriteBatch.Begin() 之前(开始安排他的绘图),最终您必须调用spriteBatch.End() 将预定的恶意程序刷新到您的设备。您的无限循环会导致您的 sprite 绘图的无限调度,直到内存已满并且您面临内存不足异常。
  3. (注意!)在你的条件(x &gt;= 5 | y &gt;= 5)你使用按位或比较,你不应该这样做(除非是故意的,我在这里看不到,而是使用布尔值或:(x &gt;= 5 || y &gt;= 5)
  4. 在循环本身内修改循环计数器是一个非常糟糕的习惯。不仅容易出错,而且很难理解和支持以这种方式编写的代码。

我会这样重写你的代码

    spriteBatch.Begin();
    for (int x = 0; x < 5; x++)
    {
        for (int y = 0; y < 5; y++)
        {
            x = level1[x, 0];
            y = level1[0, y];

            //This line bellow is where it says OutOfMemoryException
            spriteBatch.Draw(tileSheet, new Rectangle(x, y, 32, 32), new Rectangle(0, 0, 32, 32), Color.White);
        }
    }
    spriteBatch.End();

它将在主游戏循环的每个 Draw() 事件上重新绘制所有图块(前提是您仍然从 Game 类的 Draw() 方法调用此方法。XNA 会根据您的 PC 性能以及必须在每一帧上完成的计算量。

【讨论】:

  • 它不需要使用 spriteBatch.Begin() 和 End() 我对播放器类做了同样的想法,它工作得很好。但在这里它有点不同。如果我在这里创建一个更新方法,那将是许多不同的 spriteBatch.Draw() 并且我还计划在多个级别上进行更新,这也将使其成为 spageti 代码。
  • 不,它是必需的(但最好每个 Draw() 事件只执行一次),阅读here。您可以在您的 Draw() 方法中只使用一次 Begin()End(),就在绘图的开头和结尾处,并在其间调用所有 Draw 方法。
  • +1 好答案。只是有点迂腐:XNA 的默认设置使用固定的帧速率。如果连续绘制也使用相同的纹理 (ref),那么将事物保持在一个开始/结束块中只会带来性能优势。
  • @AndrewRussell:如果Update() 花费的时间太长,XNA 不会跳过一些Draw() 事件的调用吗?我同意 SpriteBatch,我只是在我的回答中简化了它的作用。
  • 是的,这是真的。我想你可以说像这样丢帧会改变 FPS。但是 XNA 确实包含真正的可变帧速率模式——它不是默认的。
【解决方案2】:

我认为您陷入了无限循环。您需要以某种方式退出以避免内存不足异常。

【讨论】:

  • 我还要如何绘制要绘制的图块?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-09
  • 2016-05-02
  • 1970-01-01
  • 2018-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多