为什么纹理不能正确显示?

问题描述

我有一个项目,其中我的纹理没有正确显示在窗口内。它将始终显示空白的白色精灵而不是纹理。我无法找出我做错了什么。这是我的代码

带有矢量保持纹理的类头

    class textures
    {
    public:
        sf::Texture dirt_Texture;
        sf::Texture grass_Texture;
        std::vector<sf::Texture> texturesvector;
        /*
             dirt = 0
            grass = 1
        */
    public:
        textures();

    sf::Texture getTextureByID(int id);



};

和它的 .cpp 文件

//constructor populate vector with textures
textures::textures()
{
    if (!dirt_Texture.loadFromFile("dirt.PNG"))
    {
        std::cout << "Error while loading texture.\n";
    }
    dirt_Texture.isSmooth();
    texturesvector.push_back(dirt_Texture);

    if (!grass_Texture.loadFromFile("grass.PNG"))
    {
        std::cout << "Error while loading texture.\n";
    }
    texturesvector.push_back(grass_Texture);
    std::cout << "Texture constructor has been called.\n";
}

sf::Texture textures::getTextureByID(int id)
{
    return texturesvector[id];
}

带有子类精灵:

class sprites : public textures
{
private:
    //textures* textureClass;
    sf::Sprite sprite;
    std::vector<int> textureIDsvector;
public:
    sprites();
    ~sprites();

    int getVectorValueAtLine(int &line);
    void setVectorValueAtLineto(int &line,int value);
    void updateTextureAtLine(int& line);
    sf::Sprite* getSprite();

};

主要函数在 .cpp 中的位置

sprites::sprites()
{
    std::vector<int> cubeIDsvector(100,0);
    textureIDsvector = cubeIDsvector;
    //textureClass = new textures();
    std::cout << "Sprite constructor has been called.\n";
}

void sprites::updateTextureAtLine(int& line)
{
    switch (textureIDsvector[line])
    {
    case 0:
        //switcher = 0;
        sprite.setTexture(getTextureByID(0));
        sprite.setColor(sf::Color(55,150,150));
        std::cout << "case 0\n";
        break;
    case 1:
        //switcher = 1;
        sprite.setTexture(getTextureByID(1));
        sprite.setColor(sf::Color(155,50,150));
        std::cout << "case 1\n";
        break;
    default:
        break;
    }
}

在主循环中,我在 sf::RenderWindow 和 window.clean(...) 从 for 循环调用 updateTextureAtLine() 函数之后在堆上创建精灵对象。

没有返回错误,在调试时看起来也很好,我是新手,但看起来纹理总是在内存中,我找不到问题出在哪里。

如下所述解决

解决方法

getTextureByID() 返回纹理的副本而不是引用。当它超出范围时,此副本将被销毁 - 因此一旦对 sprite.setTexture() 的调用完成。
这导致 Sprite 具有指向不再存在的纹理的指针。

解决方案是从 getTextureByID() 返回一个指针或引用。虽然我们正在更改该函数,但我们还应该使函数和返回值 const,因为我们不打算修改它,尽管这是可选的 - 我不妨指出这是一个好习惯。

以下是返回 constconst reference 函数示例:

// header
const sf::Texture& getTextureByID(int id) const;
// source
const sf::Texture& textures::getTextureByID(int id) const {
    return texturesVector[id];
}

这有望解决您的问题。


无关注释:

您的纹理类总共存储四个纹理、两个泥土纹理和两个草纹理。
这可能是您想要的,也可能不是。
一种解决方案是没有成员变量 dirt_Texturegrass_Texture,或者只是没有 texturesVector
另一种解决方案是让 texturesVector 存储指向纹理的指针,这些指针也可以是 const,这看起来像这样:

// header
std::vector<const sf::Texture*> texturesVector;
// source
//   constructor
texturesVector.push_back(&dirt_Texture);
...
texturesVector.push_back(&grass_Texture);
//   getTextureByID()
return *texturesVector[id]; // (or alternatively return a pointer)

最后,如果您将纹理对象存储在 texturesVector 内(如果您切换到指针,这将不成问题),请注意添加更多纹理可能会迫使向量的内部数组发生变化内存位置,从而使您的纹理无效。
如果您不打算在运行程序的中途添加更多纹理,那也没关系。我确实在运行程序的中途添加了很多纹理,因为我喜欢延迟初始化。如果您计划添加更多纹理,那么要么使用另一个不会移动其对象的容器,要么为您的纹理动态分配一个位置。我是后者的粉丝,使用字符串映射到纹理的唯一指针 (std::unordered_map<std::string,std::unique_ptr<sf::Texture>>)