【问题标题】:XNA 4.0 SpriteBatch.Draw Out Of Memory Exception ThrownXNA 4.0 SpriteBatch.Draw 抛出内存异常
【发布时间】:2012-12-18 14:35:44
【问题描述】:

嗯,首先,我的猜测是我多次调用spritebatch.draw() 方法,但我需要(或者,这是我弄清楚如何做的唯一方法)绘制我的游戏窗口.我会继续转储我的代码。

我的窗口类;

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace System.Window
{
class Window
{
    #region Variables

    public Texture2D importedTexture;
    public Texture2D WindowSkin;
    public RenderTarget2D currentWindow;
    public RenderTarget2D windowTexture;

    public Vector2 pos;

    public int prevWindowWidth;
    public int prevWindowHeight;
    public int windowWidth;
    public int windowHeight;

    public bool visible;
    public bool active;
    public bool drawNew;

    #region Rectangles

    public Rectangle clickRect;
    public Rectangle topLeftRect;
    public Rectangle topRightRect;
    public Rectangle buttonRect;
    public Rectangle botLeftRect;
    public Rectangle botRightRect;


    #endregion

    #endregion

    public Window()
    {

    }

    public void Initialize(GraphicsDevice g, Texture2D ws, Texture2D it, int w, int h, bool v, bool a)
    {
        WindowSkin = ws;
        importedTexture = it;

        windowWidth = w;
        prevWindowWidth = w;

        windowHeight = h;
        prevWindowHeight = h;

        windowTexture = new RenderTarget2D(g, windowWidth, windowHeight);
        currentWindow = windowTexture;

        visible = v;
        active = a;

        drawNew = true;

        topLeftRect = new Rectangle(0, 0, 32, 32);
        topRightRect = new Rectangle(32, 0, 32, 32);
        buttonRect = new Rectangle(64, 0, 32, 32);
        botLeftRect = new Rectangle(0, 64, 32, 32);
        botRightRect = new Rectangle(64, 64, 32, 32);

    }

    public void Update(GraphicsDevice g, Vector2 p, int width, int height)
    {
        prevWindowWidth = windowWidth;
        prevWindowHeight = windowHeight;

        pos = p;
        windowWidth = width;
        windowHeight = height;
        windowTexture = new RenderTarget2D(g, windowWidth+2, windowHeight+2);

    }

    public void Draw(SpriteBatch s, GraphicsDevice g)
    {


        s.Draw(currentWindow, pos, new Rectangle(0, 0, windowWidth, windowHeight), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);

    }

    public void DrawNewWindow(SpriteBatch s, GraphicsDevice g)
    {

            g.SetRenderTarget(windowTexture);
            g.Clear(Color.Transparent);

            s.Begin();

            #region Draw Background

            for (int w = 3; w < (windowWidth); w += 32)
            {
                for (int h = 32; h < (windowHeight); h += 32)
                {
                    s.Draw(WindowSkin, new Vector2(w, h), new Rectangle(32, 32, 32, 32), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
                }
            }

            #endregion

            s.Draw(importedTexture, new Vector2(3, 32), new Rectangle(0, 0, importedTexture.Width, importedTexture.Height), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);


            #region Draw resizables

            for (int i = 32; i < (windowWidth - 64); i += 32)
            {
                s.Draw(WindowSkin, new Vector2(i, 0), new Rectangle(16, 0, 32, 32), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
            }
            for (int i = 32; i < (windowWidth - 32); i += 32)
            {
                s.Draw(WindowSkin, new Vector2(i, windowHeight - 32), new Rectangle(32, 64, 32, 32), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
            }
            for (int i = 64; i < (windowHeight - 32); i += 32)
            {
                s.Draw(WindowSkin, new Vector2(0, i), new Rectangle(0, 48, 32, 32), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
            }
            for (int i = 64; i < (windowHeight - 32); i += 32)
            {
                s.Draw(WindowSkin, new Vector2(windowWidth - 32, i), new Rectangle(64, 48, 32, 32), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
            }

            #endregion

            #region Draw Corners

            s.Draw(WindowSkin, new Vector2(0, 0), topLeftRect, Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
            s.Draw(WindowSkin, new Vector2(0, 32), new Rectangle(0, 32, 32, 32), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);

            s.Draw(WindowSkin, new Vector2(windowWidth - 64, 0), topRightRect, Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
            s.Draw(WindowSkin, new Vector2(windowWidth - 32, 32), new Rectangle(64, 32, 32, 32), Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);

            s.Draw(WindowSkin, new Vector2(windowWidth - 32, 0), buttonRect, Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
            s.Draw(WindowSkin, new Vector2(0, windowHeight - 32), botLeftRect, Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);
            s.Draw(WindowSkin, new Vector2(windowWidth - 32, windowHeight - 32), botRightRect, Color.White, 0, Vector2.Zero, 1.0f, SpriteEffects.None, 0);

            #endregion

            s.End();

            currentWindow = windowTexture;

    }
}
}

我的 Draw() 方法;

        protected override void Draw(GameTime gameTime)
    {

            window1.DrawNewWindow(spriteBatch, GraphicsDevice);
            window1.drawNew = false;


        GraphicsDevice.SetRenderTarget(null);
        GraphicsDevice.Clear(Color.CornflowerBlue);

        spriteBatch.Begin(SpriteSortMode.Deferred,
                    BlendState.AlphaBlend,
                    SamplerState.PointClamp,
                    null,
                    null,
                    null);

        window1.Draw(spriteBatch, GraphicsDevice);

        spriteBatch.End();

        base.Draw(gameTime);
    }

这一切都很好,并针对我的小窗皮纹理等进行了配置。唯一的问题是它会有点滞后,然后在运行它大约一分钟后完全崩溃。它会抛出一个Out Of Memory Exception,但我不知道也找不到与 spritebatch 相关的任何其他主题或帖子。有人对我如何使这项工作不占用太多内存有任何建议吗?我认为这是一种简单、经济有效的绘制窗口的方法。我只是不确定如何减少我的绘图调用,或者恢复任何内存。

【问题讨论】:

    标签: c# xna out-of-memory xna-4.0 spritebatch


    【解决方案1】:

    windowTexture = new RenderTarget2D(g, windowWidth+2, windowHeight+2);

    可能是罪魁祸首。尽量不要在每次更新时都实例化新的东西。它每秒发生大约 60 次,并可能导致严重的开销。而是在 Initialize 方法中初始化渲染目标。

    【讨论】:

    • 但是我将如何补偿更改的渲染目标大小?我以这种方式对其进行编码,因此可以轻松调整大小。此外,它在两个轴上都是“+2”,因为当它移动得更快时,它会在两边切断一点,然后更新可以跟上。添加一点它解决了这个问题。等等,这意味着我可以只更新它的宽度/高度,而不是重新初始化......让我检查一下。编辑:不,它是只读的......我认为这就是我首先重新初始化的原因...... Xd
    • 我也尝试只绘制新窗口大小,如果它自上次更新以来改变了大小,但试图告诉它不要重绘(所以它不必遍历所有这些draws) 由于某种原因不起作用,它只是在第一次绘制后消失。就像渲染目标在绘制后自行删除一样。
    • 有几个渲染目标,如果你需要它们(真的,你应该只需要一个),然后将纹理移动到一个纹理上,这样你就可以绘制它了。为了处理屏幕尺寸的变化,取决于图像是否可以缩放是否重要,然后只需在巨大的纹理上绘制(在渲染目标上)所有内容,并根据屏幕尺寸缩小以进行最终绘制。
    • 是的,我想我修好了。感谢您的麻烦,+1。 :] 或者,至少我愿意,如果它能让我...
    • 呃……我找不到接受它的方法。你能告诉我它的位置吗?编辑:Pfft,没关系。复选标记。完成了,谢谢。
    【解决方案2】:

    RenderTarget2D 实现了 IDisposable:一旦完成,您应该始终在其上调用 Dispose(),因为它可能持有非托管资源(如 Direct3D 表面)。这是您看到的内存泄漏的根本原因。

    当然,如前所述,在每个 Draw() 上实例化一个新的 RenderTarget2D 并不是一个好主意,因为它的调用成本很高。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多