SFML - Сборщик мусора C # удаляет объект, который используется - PullRequest
0 голосов
/ 22 сентября 2018

Я использую SFML для C #.Я хочу создать спрайт BackgroundImage, а затем начать рисовать его с помощью агента, представленного в виде круга, поверх него следующим образом:

    static void Main(string[] args)
    {
        Window = new RenderWindow(new VideoMode((uint)map.Size.X * 30, (uint)map.Size.Y * 30), map.Name + " - MAZE", Styles.Default);

        while (Window.IsOpen)
        {
            Update();
        }
    }
    static public RenderWindow Window { get; private set; }
    static Map map = new Map(string.Format(@"C:\Users\{0}\Desktop\Maze.png", Environment.UserName));

    static public void Update()
    {
        Window.Clear(Color.Blue);

        DrawBackground();
        DrawAgent();

        Window.Display();
    }

    static void DrawAgent()
    {
        using (CircleShape tempCircle = new CircleShape
        {
            FillColor = Color.Cyan,
            Radius = 15,
            Position = new Vector2f(30, 30),
            Origin = new Vector2f(30, 30),
            Scale = new Vector2f(.5f, .5f)
        })
        {
            Window.Draw(tempCircle);
        }

    }

    static private Sprite BackgroundImage { get; set; }
    static void DrawBackground()
    {
        if (BackgroundImage == null)
            BackgroundImage = GetBackground();

        Window.Draw(BackgroundImage);

    }

    static Sprite GetBackground()
    {
        RenderTexture render = new RenderTexture((uint)map.Size.X * 30, (uint)map.Size.Y * 30);
        foreach (var point in map.Grid.Points)
        {
            RectangleShape pointShape = new RectangleShape(new Vector2f(30, 30));
            switch (point.PointType)
            {
                case PointType.Walkable:
                    pointShape.FillColor = Color.White;
                    break;
                case PointType.NotWalkable:
                    pointShape.FillColor = Color.Black;
                    break;
                case PointType.Start:
                    pointShape.FillColor = Color.Red;
                    break;
                case PointType.Exit:
                    pointShape.FillColor = Color.Blue;
                    break;
            }
            pointShape.Position = new Vector2f(point.Position.X * 30, point.Position.Y * 30);
            render.Draw(pointShape);

        }
        Sprite result = new Sprite(render.Texture);
        result.Origin = new Vector2f(0, result.GetLocalBounds().Height);
        result.Scale = new Vector2f(1, -1);
        return result;
    }

Все работает, как задумано, когда я его запускаю, но через несколькосекунд, примерно в то время, когда объем памяти процесса достигает 70 МБ, BackgroundImage превращается в полностью белый спрайт.Если я изменю тип BackgroundImage и GetBackground () на RenderTexture, верну объект «render», а затем изменю функцию DrawBackground () следующим образом

 void RenderBackground()
        {
            if (BackgroundImage == null)
                BackgroundImage = GetBackground();

            using (Sprite result = new Sprite(BackgroundImage.Texture))
            {
                result.Origin = new Vector2f(0, result.GetLocalBounds().Height);
                result.Scale = new Vector2f(1, -1);
                Window.Draw(result);
            }
        }

, тогда фоновый спрайт не станет белым, но сохранит весьRenderTexture вместо Sprite и постоянное создание новых объектов Sprite каждый раз, когда мы вызываем функцию RenderBackground (), кажется плохой идеей.Есть ли какой-нибудь способ для функции GetBackground () вернуть Sprite, который не станет белым после разрушения локальной переменной «render» функции?

Ответы [ 2 ]

0 голосов
/ 22 сентября 2018

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

Sprite result = new Sprite(render.Texture);

я написал

Sprite result = new Sprite(new Texture(render.Texture));

Теперь сборщик мусора не располагает текстурой Sprite

0 голосов
/ 22 сентября 2018

Вы не совсем не согласны со своими предположениями.Упрощенно, SFML знает два типа ресурсов:

  • Легкие ресурсы - это небольшие объекты, которые быстро создаются и уничтожаются.Это не так уж и плохо - просто бросить их и восстановить их позже.Типичными примерами могут быть Sprite, Sound, Text и, в основном, большинство классов SFML.

  • Тяжелые ресурсы часто представляют собой большие объекты или объекты, требующие файлаДоступ к созданию или использованию.Типичными примерами могут быть Image, Texture, SoundBuffer и Font.Вы не должны воссоздавать их, а вместо этого сохранять их живыми, пока они вам нужны.Если они утилизируются слишком рано, источники света, использующие их, так или иначе потерпят неудачу.

Текстура спрайта, которая становится белой, как вы обнаружили, является типичным признакомназначенная текстура освобождается / удаляется.

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

Я не использовал SFML с C #, и я довольно долго не касался C #, но для простой реализации у вас просто будет Dictionary<string, Texture>.Когда вы хотите загрузить файл текстуры, например texture.png, вы посмотрите, есть ли словарная запись с этим именем ключа.Если есть, просто верните его.Если нет, создайте новую запись и загрузите текстуру, а затем верните ее.

Я не практикуюсь, поэтому, пожалуйста, рассмотрите этот псевдокод!

private Dictionary<string, Texture> mTextureCache; // initialized in constructor

public Texture getTexture(file) {
    Texture tex;
    if (mTextureCache.TryGetValue(file, out tex))
        return tex;
    tex = new Texture(file);
    mTextureCache.add(file, tex);
    return tex;
}

// Somewhere else in your code:
Sprite character = new Sprite(getTexture("myCharacter.png"));

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

...