在 SFML 2 中使用精灵向量时如何停止出现白色方块?
How to stop having a white square when using a sprite vector with SFML 2?
我正在尝试制作精灵矢量,但前几个元素总是显示一个白色方块。
这些变量包含在 TileRPG class 中,然后在 main.cpp 中使用
tile.cpp
void TileRPG::draw(int id, float x, float y, sf::RenderWindow& window) {
m_sprite[id].setPosition(sf::Vector2f(x, y));
window.draw(m_sprite[id]);
}
TileRPG::TileRPG() {
std::ifstream file { "data/tileRPGList.rf" };
std::string line{ "" }, access { "" };
sf::Texture texture;
sf::Sprite sprite;
unsigned int i = 0;
while (std::getline(file, line)) {
m_texture.push_back(texture);
m_sprite.push_back(sprite);
access = "data/" + line;
m_texture[i].loadFromFile(access);
m_sprite[i].setTexture(m_texture[i]);
i++;
}
}
tile.hpp
class Tile {
protected:
std::vector<sf::Texture> m_texture;
std::vector<sf::Sprite> m_sprite;
};
class TileRPG : public Tile {
public:
TileRPG();
void draw(int id, float x, float y, sf::RenderWindow& window);
};
Sprite::setTexture
不会复制纹理,而是存储指向它的指针。一旦纹理向量在后续 push_back
s 之一中重新分配其存储空间,此指针就会失效。
问题
来自sf::Sprite::setTexture()
documentation:
the sprite doesn't store its own copy of the texture, but rather keeps a pointer to the one that you passed to this function.
因此,sf::Sprite
对象不会存储 sf::Texture
对象的副本。顺便说一句,这与The Flyweight Pattern, as it can be inferred from sf::Sprite
's documentation:
有关
The separation of sf::Sprite
and sf::Texture
allows more flexibility and better performances: indeed a sf::Texture
is a heavy resource, and any operation on it is slow (often too slow for real-time applications). On the other side, a sf::Sprite
is a lightweight object which can use the pixel data of a sf::Texture
and draw it with its own transformation/color/blending attributes.
代码中的 m_texture
数据成员是 sf::Texture
个对象的向量,即 std::vector<sf::Texture>
。如果它没有足够的容量来存储要插入的 sf::Texture
对象,则对其调用 push_back()
将重新分配向量的内部缓冲区。因此,存储在 std::vector<sf::Texture>
中的 sf::Texture
个对象在调用 push_back()
后可能最终位于内存中的不同位置。由于 sf::Sprite
对象只保留指向 sf::Texture
对象的指针,如果 sf::Texture
对象已重新分配到内存中的其他位置,这些指针最终将指向内存中的错误位置。
可能的解决方案
您可以简单地调用 std::vector::reserve()
来预先为向量的内部缓冲区预留足够的内存。这种方法的缺点是理想情况下,您需要提前知道向量要存储的 sf::Texture
个对象的数量,以避免浪费内存。
另一种方法是仅在您已正确填充 std::vector<sf::Texture>
容器后 调用 sf::Sprite::setTexture()
。这样,由于您不打算进一步将 sf::Texture
个对象插入到向量中,因此它不会重新分配其内部缓冲区。
最后,关于容器的另一种方法是将 m_texture
定义为 std::vector<std::unique_ptr<sf::Texture>>
。这样,如果向量的内部缓冲区发生重新分配,只有 std::unique_ptr<sf::Texture>
对象的地址会受到影响,不会 pointee 个对象,(即不是 sf::Texture
个对象的地址)。您也可以使用 boost::stable_vector
来达到同样的目的。在这种情况下,您只需将 m_texture
定义为 boost::stable_vector<sf::Texture>
。
我正在尝试制作精灵矢量,但前几个元素总是显示一个白色方块。 这些变量包含在 TileRPG class 中,然后在 main.cpp 中使用 tile.cpp
void TileRPG::draw(int id, float x, float y, sf::RenderWindow& window) {
m_sprite[id].setPosition(sf::Vector2f(x, y));
window.draw(m_sprite[id]);
}
TileRPG::TileRPG() {
std::ifstream file { "data/tileRPGList.rf" };
std::string line{ "" }, access { "" };
sf::Texture texture;
sf::Sprite sprite;
unsigned int i = 0;
while (std::getline(file, line)) {
m_texture.push_back(texture);
m_sprite.push_back(sprite);
access = "data/" + line;
m_texture[i].loadFromFile(access);
m_sprite[i].setTexture(m_texture[i]);
i++;
}
}
tile.hpp
class Tile {
protected:
std::vector<sf::Texture> m_texture;
std::vector<sf::Sprite> m_sprite;
};
class TileRPG : public Tile {
public:
TileRPG();
void draw(int id, float x, float y, sf::RenderWindow& window);
};
Sprite::setTexture
不会复制纹理,而是存储指向它的指针。一旦纹理向量在后续 push_back
s 之一中重新分配其存储空间,此指针就会失效。
问题
来自sf::Sprite::setTexture()
documentation:
the sprite doesn't store its own copy of the texture, but rather keeps a pointer to the one that you passed to this function.
因此,sf::Sprite
对象不会存储 sf::Texture
对象的副本。顺便说一句,这与The Flyweight Pattern, as it can be inferred from sf::Sprite
's documentation:
The separation of
sf::Sprite
andsf::Texture
allows more flexibility and better performances: indeed asf::Texture
is a heavy resource, and any operation on it is slow (often too slow for real-time applications). On the other side, asf::Sprite
is a lightweight object which can use the pixel data of asf::Texture
and draw it with its own transformation/color/blending attributes.
代码中的 m_texture
数据成员是 sf::Texture
个对象的向量,即 std::vector<sf::Texture>
。如果它没有足够的容量来存储要插入的 sf::Texture
对象,则对其调用 push_back()
将重新分配向量的内部缓冲区。因此,存储在 std::vector<sf::Texture>
中的 sf::Texture
个对象在调用 push_back()
后可能最终位于内存中的不同位置。由于 sf::Sprite
对象只保留指向 sf::Texture
对象的指针,如果 sf::Texture
对象已重新分配到内存中的其他位置,这些指针最终将指向内存中的错误位置。
可能的解决方案
您可以简单地调用 std::vector::reserve()
来预先为向量的内部缓冲区预留足够的内存。这种方法的缺点是理想情况下,您需要提前知道向量要存储的 sf::Texture
个对象的数量,以避免浪费内存。
另一种方法是仅在您已正确填充 std::vector<sf::Texture>
容器后 调用 sf::Sprite::setTexture()
。这样,由于您不打算进一步将 sf::Texture
个对象插入到向量中,因此它不会重新分配其内部缓冲区。
最后,关于容器的另一种方法是将 m_texture
定义为 std::vector<std::unique_ptr<sf::Texture>>
。这样,如果向量的内部缓冲区发生重新分配,只有 std::unique_ptr<sf::Texture>
对象的地址会受到影响,不会 pointee 个对象,(即不是 sf::Texture
个对象的地址)。您也可以使用 boost::stable_vector
来达到同样的目的。在这种情况下,您只需将 m_texture
定义为 boost::stable_vector<sf::Texture>
。