Невозможно создать спрайт с использованием RenderTexture - PullRequest
0 голосов
/ 07 марта 2020

Я создаю игру и создал класс для хранения карты. У меня есть функция для создания одного спрайта, на котором нарисована вся видимая карта. Я использовал RenderTexture, а затем я создаю и возвращаю спрайт, созданный с его помощью. Тем не менее, спрайт полностью белый.

Вот код для генерации карты и отрисовки спрайта

void Map::procedural_generate()
{
    cout << "Starting the map generation" << endl;
    int generation_max = m_size.x * m_size.y, 
        current_generation = 0;
    vector<Decor> decor_vector;
    m_decor_vector.clear();

    const vector<Decor> const_vector
    {
        Decor(GRASS)
    };

    for (int i = 0; i < m_size.x; i++)
    {
        decor_vector.clear();

        for (int j = 0; j < m_size.y; j++)
        {
            decor_vector.push_back(const_vector[GRASS]);
            decor_vector[j].set_position(Vector2f(i * 32, j * 32));
            current_generation++;
            cout << "Generation : " << current_generation << '/' << generation_max << '\r';
        }

        m_decor_vector.push_back(decor_vector);
        decor_vector.clear();
    }
    cout << "Map generation has ended" << endl;
}

Sprite Map::sprite()
{
    RenderTexture map;
    if (!map.create(WINDOW_WIDTH, WINDOW_HEIGTH))
        cout << "Map : Unable to create the RenderTexture" << endl;

    map.clear(Color::Green);

    for (int i = 0; i < m_size.x; i++)
        for (int j = 0; j < m_size.y; j++)
            map.draw(m_decor_vector[i][j].sprite());

    map.display();

    Sprite sprite(map.getTexture());
    return sprite; 
}

Кажется, проблема в части map.draw, как будто Я использую map.clear(Color::Red) перед двойным l oop, спрайт остается белым, но если я использую sprite.setColor(Color::Red), он работает. Дело в том, что спрайты декора не покрывают всю текстуру (текстура 1920x1080, а спрайты 320x320), поэтому я не могу понять, что происходит.

Это не загрузка спрайтов декорации, если я используйте map.draw(Decor(GRASS)) спрайт отображается правильно.

Я пытался использовать указатель для const_vector и для возвращенного спрайта, без успеха.

1 Ответ

2 голосов
/ 07 марта 2020

Популярная ошибка при использовании SFML.

Sprite Map::sprite()
{
    RenderTexture map;
    // ...
    Sprite sprite(map.getTexture());
    return sprite; 
}

map локально. Когда функция заканчивается, map уничтожается. Sprite принимает текстуру map в качестве мелкой копии, это только указатель на текстуру, в соответствии с официальным руководством / документацией :

Проблема белого квадрата Вы успешно загрузили текстуру, правильно построили спрайт, и ... теперь все, что вы видите на экране, это белый квадрат. Что случилось?

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

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


Связанный (мой) ответ, опубликованный 1 день go


Решение: вам нужно обернуть спрайты с текстурами в каком-то классе с глубокой копией. Вы не можете полагаться на мелкие дефолтные сгенерированные операции копирования.


Такой класс может выглядеть следующим образом:

class TexturedSprite {
public:
    sf::Sprite sprite;
    sf::Texture texture;

    TexturedSprite() {
        init(); // load texture
    }

    void init() {
        // load texture
        texture.loadFromFile("texture1.png");
        sprite.setTexture(texture);
        sprite.setPosition(0,0);
    }

    TexturedSprite(const TexturedSprite& theOther) {
        texture = theOther.texture; // deep copy
        sprite.setTexture(texture);
    }

    TexturedSprite& operator=(const TexturedSprite& theOther) {
        if (this == &theOther)
            return *this;
        texture = theOther.texture; // deep copy
        sprite.setTexture(texture);
        return *this;
    }
};

тогда код:

TexturedSprite fooMain;
{
    TexturedSprite foo;     // local 
    fooMain = foo;    
} // foo is destroyed, but = did deep copy of texture

безопасен .

...