【问题标题】:C# XNA Out of Memory Exception when using trying to Draw尝试绘制时出现 C# XNA 内存不足异常
【发布时间】:2016-01-09 00:03:48
【问题描述】:

从我在其他问题中看到的情况来看,我似乎在我的绘图代码中实例化新的东西,这将占用大量内存,但是查看我用作参考的其他代码,我不确定问题出在哪里.

namespace Crucible
{
    public class Crucible : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        //Drawing vars
        public int renderLeft;
        public int renderRight;
        public int renderUp;
        public int renderDown;
        public Tile currentTile;
        public Rectangle target;
        public Rectangle source;
        public Color tint;
        public Texture2D img;
        //
        public static int baseTileWidth = 16;
        public static int baseTileHeight = 16;
        public static int mapWidthTile = 8400;
        public static int mapHeightTile = 2400;
        public static int mapWidthPixel = 8400 * baseTileWidth;
        public static int mapHeightPixel = 2400 * baseTileHeight;
        public static int screenWidth;
        public static int screenHeight;
        public static Player mainPlayer;
        Tile[,] worldTilesFor; //Foreground Tiles
        Tile[,] worldTilesBack; //Foreground Tiles

        Texture2D coalOreSprite;
        Texture2D dirtSprite;

        public Crucible()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.PreferredBackBufferHeight = 1080;
            graphics.PreferredBackBufferWidth = 1920;
        }

        protected override void Initialize()
        {
            mainPlayer = new Player("tim", 1);
            worldTilesFor = new Tile[8400,2400];
            worldTilesBack = new Tile[8400, 2400];
            for (int i = 0; i < worldTilesFor.GetLength(0); i++)
            {
                for (int j = 0; j < worldTilesFor.GetLength(1); j++)
                {
                    worldTilesFor[i, j] = new Tile(0,i,j);
                    if (j >= 1200)
                    {
                        worldTilesFor[i, j].tileID = 1;
                    }
                }
            }
            for (int i = 0; i < worldTilesBack.GetLength(0); i++)
            {
                for (int j = 0; j < worldTilesBack.GetLength(1); j++)
                {
                    worldTilesBack[i, j] = new Tile(0, i, j);
                    if (j < 1200)
                    {
                        worldTilesFor[i, j].tileID = 1;
                    }
                }

            }
            screenWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
            screenHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
            base.IsMouseVisible = true;
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            coalOreSprite = this.Content.Load<Texture2D>("Tile_coal ore");
            dirtSprite = this.Content.Load<Texture2D>("Tile_Dirt");
        }

        protected override void UnloadContent()
        {
        }


        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            renderLeft = (int)Math.Floor(mainPlayer.position.X) - (screenWidth / 2);
            if (renderLeft < 0)
            {
                renderLeft = 0;
            }

            renderRight = (int)Math.Ceiling(mainPlayer.position.X) + (screenWidth / 2);
            if (renderRight > mapWidthPixel)
            {
                renderRight = mapWidthPixel;
            }

            renderUp = (int)Math.Floor(mainPlayer.position.Y) - (screenHeight / 2);
            if (renderUp < 0)
            {
                renderUp = 0;
            }

            renderDown = (int)Math.Floor(mainPlayer.position.Y) + (screenHeight / 2);
            if (renderDown > mapHeightPixel)
            {
                renderDown = mapHeightPixel;
            }

            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();

            for (int i = renderLeft; i < renderRight; i++)
            {
                for (int j = renderUp; j < renderDown; j++)
                {
                    currentTile = worldTilesBack[i / 16, j / 16];
                    DrawTile(currentTile);
                }
            }
            for (int i = renderLeft; i < renderRight; i++)
            {
                for (int j = renderUp; j < renderDown; j++)
                {
                    currentTile = worldTilesFor[i/16, j/16];
                    DrawTile(currentTile);
                }
            }


            spriteBatch.End();
            base.Draw(gameTime);
        }

        public void DrawTile(Tile tileIn)
        {
            switch (tileIn.tileID)
            {
                case 1:
                    img = dirtSprite;
                    break;
                default:
                    img = dirtSprite;
                    break;
            }

            if (tileIn.foreground)
            {
                tint = Color.White;
            }
            else
            {
                tint = Color.Gray; //tint background objects grey
            }
            spriteBatch.Draw(dirtSprite, new Rectangle((int)(tileIn.posX * baseTileWidth - mainPlayer.position.X + screenWidth / 2), (int)(tileIn.posY * baseTileHeight - mainPlayer.position.Y + screenHeight / 2), baseTileWidth, baseTileHeight), new Rectangle?(new Rectangle(tileIn.frameX * 16, tileIn.frameY * 16, 16, 16)), tint); //error is thrown here at the source rectangle
        }
    }
}

任何有关导致错误的原因的帮助或指导将不胜感激。

【问题讨论】:

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


    【解决方案1】:

    这是您的 worldTilesForworldTilesBack 数组。您没有展示 Tile 类的样子,但即使我们假设每个 Tile 包含 100 个字节的数据,这也是一个低猜测,即 8400 * 2400 = 20,160,000 个 Tile 实例 * 100 个字节,每个阵列大约需要 2 GB 的 ram,两者都是 4。

    我认为这就是您存储地图的方式。您将需要一个较小的地图,或者您需要某种方法来虚拟化您的地图,将其存储在磁盘上,并根据需要分块加载。

    【讨论】:

    • 我认为这会是个问题,现在每个 tile 类大约 5 个字节。感谢您的建议。
    • 请记住,即使是完全空的对象引用,在 x64 操作系统上也需要 8 个字节,而在 x86 上需要 4 个字节。使用声明该大小的数组,即使在实例化 Tile 实例之前,您也会使用大量内存。
    • 这对我来说很有趣,因为从我反编译的游戏中查看代码,它创建和处理相同的数组(以及更多)几乎没有问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-11
    • 1970-01-01
    • 1970-01-01
    • 2016-01-12
    相关资源
    最近更新 更多