问题描述
我有一个项目,其中我的纹理没有正确显示在窗口内。它将始终显示空白的白色精灵而不是纹理。我无法找出我做错了什么。这是我的代码:
带有矢量保持纹理的类头
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
,因为我们不打算修改它,尽管这是可选的 - 我不妨指出这是一个好习惯。
以下是返回 const
的 const reference
函数示例:
// header
const sf::Texture& getTextureByID(int id) const;
// source
const sf::Texture& textures::getTextureByID(int id) const {
return texturesVector[id];
}
这有望解决您的问题。
无关注释:
您的纹理类总共存储四个纹理、两个泥土纹理和两个草纹理。
这可能是您想要的,也可能不是。
一种解决方案是没有成员变量 dirt_Texture
和 grass_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>>
)