XNA «исключение нехватки памяти», разрабатывающее параметр воспроизведения

#c# #xna

#c# #xna

Вопрос:

При выводе этого кода возникает проблема «исключение нехватки памяти». Код делает быстрые фотографии основной платы и сохраняет их для последующей перекомпиляции в виде фильма.

Если есть другой способ сделать воспроизведение поля, это было бы очень ценно, поскольку теперь я должен сфотографировать доску, а затем перекомпилировать ее в avi-фильм. Пожалуйста, любая помощь.

  public class JSTART_Main : Microsoft.Xna.Framework.Game
{
    private GraphicsDeviceManager graphics;
    private SpriteBatch spriteBatch;
    private Texture2D background;
    private Rectangle mainFrame;
    private SpriteFont font;

    private bool finished = false;
    private BackgroundWorker bw = new BackgroundWorker();
    private Navigation navigation;

    public JSTART_Main()
    {
        graphics = new GraphicsDeviceManager(this);
        this.graphics.PreferredBackBufferWidth = 1280;
        this.graphics.PreferredBackBufferHeight = 768;
        navigation = new Navigation();
        navigation.graphics = graphics;
        navigation.window = Window;
        navigation.CreateClasses();

        //this.graphics.IsFullScreen = true;
        Content.RootDirectory = "Content";
        this.IsMouseVisible = true;

        navigation.controls.CreateControls();
        bw.WorkerSupportsCancellation = true;

        bw.DoWork  = new DoWorkEventHandler(bw_screenshots);

    }

    protected override void Initialize()
    {
        base.Initialize();
        bw.RunWorkerAsync();         
    }
    void bw_screenshots(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;


            capture();
            capture();

            if ((worker.CancellationPending == true))
            {
                e.Cancel = true;

            }
            else
            {
                bw.Dispose();

            }              
        }
    void capture()
    {

        while (finished == false)
        {              
                count  = 1;
                string counter = count.ToString();

                int w = GraphicsDevice.PresentationParameters.BackBufferWidth;
                int h = GraphicsDevice.PresentationParameters.BackBufferHeight;

                //force a frame to be drawn (otherwise back buffer is empty) 
                Draw(new GameTime());

                //pull the picture from the buffer 
                int[] backBuffer = new int[w * h];
                GraphicsDevice.GetBackBufferData(backBuffer);

                //copy into a texture 
                Texture2D texture = new Texture2D(GraphicsDevice, w, h, false, GraphicsDevice.PresentationParameters.BackBufferFormat);
                texture.SetData(backBuffer);                
                    //save to disk 
                    Stream stream = File.OpenWrite(counter   ".jpg");

                    texture.SaveAsJpeg(stream, w, h);
                    stream.Flush();
                    stream.Close();
                    texture.Dispose();

             }

    }
    protected override void LoadContent()
    {
        spriteBatch = new SpriteBatch(GraphicsDevice);
        background = Content.Load<Texture2D>("Background");
        mainFrame = new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
        font = Content.Load<SpriteFont>("font");

    }

    protected override void UnloadContent()
    {

    }
    int count = 0;

    protected override void Update(GameTime gameTime)
    {

        //if (Keyboard.GetState().IsKeyDown(Keys.Escape))
        //this.Exit();
        foreach (Unit enemy in navigation.players.enemies.Values)
        {
            enemy.EnemyAI(navigation.aiCollision);
        }
        navigation.input.UpdateKeyboard();
        navigation.networking.Receive();
        navigation.players.SpotEnemy();
        navigation.input.UpdateMouse();

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        try
        {
            base.Draw(gameTime);

            spriteBatch.Begin();
            spriteBatch.Draw(background, mainFrame, Color.White);
            spriteBatch.DrawString(font, "X: "   navigation.players.server.pos.X.ToString()   "nY: "   navigation.players.server.pos.Y.ToString(), new Vector2(22, 22), Color.White);
            spriteBatch.End();
            navigation.players.server.LoadContent(Content);
            navigation.players.server.Draw(spriteBatch, Color.Transparent);
            foreach (MainObject map in navigation.players.map)
            {
                map.LoadContent(Content);
                map.Draw(spriteBatch);
            }

            foreach (Unit enemy in navigation.players.enemies.Values)
            {
                if (navigation.controls.cbxShowEnemies.Checked || enemy.visible == true)
                {
                    enemy.LoadContent(Content);
                    enemy.Draw(spriteBatch, Color.Red);
                }
            }

            foreach (Unit unit in navigation.players.players.Values)
            {
                if (unit != null amp;amp; unit.visible)
                {
                    unit.LoadContent(Content);
                    unit.Draw(spriteBatch, Color.White);
                }
            }

        }
        catch (Exception )
        { }

    }
}
  

}

Ответ №1:

Если вы смогли нарисовать игру и игровое поле один раз, наверняка вы могли бы сделать это в другой раз. Все, что вам нужно сделать, это сохранить ходы, сделанные каждым блоком, и просто воспроизвести это.

Если вы пытаетесь сохранить это в avi-файл, рассмотрите возможность записи каждого кадра на жесткий диск вместо сохранения их в памяти.

Ответ №2:

Если вы сохраняете в оперативной памяти все кадры вашей сцены, скорее всего, ваша память довольно скоро закончится, попробуйте выполнить это вычисление:

 number_of_frame_stored * frame_height* frame_width * 32 = ....
  

Поэтому периодически сбрасывайте сохраненные кадры на диск и убедитесь, что ранее выделенная память будет освобождена (собран мусор).

Я вижу еще одну проблему в вашем коде: вы выполняете несколько LoadContent внутри метода main Draw. Доступ к диску может быть узким местом, поэтому постарайтесь загрузить все необходимое содержимое при запуске вашей игры.

Комментарии:

1. спасибо, но кадры уже записываются на диск: Поток stream = File. OpenWrite(счетчик «.jpg»); текстура. SaveAsJpeg(stream, w, h);

2. и мне просто нужен способ очистить кадры, которые хранятся в оперативной памяти. спасибо за совет по LoadContent, он уже создал узкое место. код все еще неаккуратен, но сейчас это исправим.

3. Хорошо, вы говорите, загружать весь контент при запуске игры? Некоторый контент может быть загружен только после обновления игрового поля, размещения на нем нового объекта или входа игрока в систему и отображения его на игровом поле. Какой контент тогда должен быть загружен при запуске?

4. Ну, я не вижу весь ваш код LoadContent, и я не знаю логику вашей игры. кстати, для содержимого я имею в виду текстуру, сетки и так далее. Этот материал должен загружаться при запуске программы, а не внутри вашего метода рисования.

5. Хорошо, спасибо за вашу помощь, высоко ценится, только проблема в том, что все еще не хватает памяти, нужен способ как-то очистить текстуру или «.dispose()» текстуру. Принудительный вызов GC не помогает, закрытие и перезапуск фонового потока также не дают результата.