首页 > 解决方案 > 无法使用 RenderTexture 创建精灵

问题描述

我正在制作游戏,并且创建了一个类来存储地图。我有一个函数来创建一个单独的精灵,在它上面绘制了所有可见的地图。我使用了 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)在双循环之前使用,精灵会保持白色,但如果我使用sprite.setColor(Color::Red),它可以工作。事实是装饰精灵并没有覆盖整个纹理(纹理是 1920x1080,精灵是 320x320),所以我不明白发生了什么。

这不是装饰精灵加载,如果我使用map.draw(Decor(GRASS))精灵正确显示。

我尝试将指针用于const_vector返回的精灵,但没有成功。

标签: c++sfml

解决方案


使用 SFML 时的常见错误。

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

map是本地的。当函数结束时,map被销毁。Sprite 将纹理map作为浅拷贝,它只是指向纹理的指针,根据官方教程/文档

白色方块问题 您成功加载了纹理,正确构建了一个精灵,并且……您现在在屏幕上看到的只是一个白色方块。发生了什么?

这是一个常见的错误。当您设置精灵的纹理时,它在内部所做的只是存储指向纹理实例的指针。因此,如果纹理被破坏或移动到内存中的其他位置,则精灵最终会得到一个无效的纹理指针。

因此,副本返回的精灵存储了悬空指针。这只是未定义的行为。


相关(我的)答案,发表于 1 天前


解决方案:您必须将带有纹理的精灵包装在某种可深度复制的类中。您不能依赖浅默认生成的复制操作。


这样的类可能如下所示:

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

是安全的。


推荐阅读