对子类绘制的 SFML 绘制调用绘制为白色方块
SFML draw call to subclass draws as white square
我正在做一个游戏项目,发现自己陷入了以下问题:
我有一个名为 Game : public sf::Drawable
的 class,我用它(除其他外)绘制游戏中的所有内容。 Game
包含一个名为 Player : public Entity
的 class,它又是 Entity : public sf::Drawable
的子 class。
这些class稍微简化了,但是受影响的功能是一样的:
实体
class Entity : public sf::Drawable
{
private:
sf::Sprite eSprite;
sf::Texture eTex;
std::string texpath;
public:
virtual Entity(std::string texpath, sf::IntRect intrect){
this->texpath = texpath;
eTex.loadFromFile(texpath, intrect);
eSprite.setTexture(eTex); }
virtual ~Entity(){}
virtual void draw(sf::RenderTarget target, sf::RenderStates states)const{
target.draw(this->eSprite);}
//Lots of other functions
}
玩家
class Player : public Entity¨
{
public:
~Player(){}
Player(std::string texpath, sf::IntRect spriteintrect)
:Entity(texpath, spriteintrect){}
void draw(sf::RenderTarget target, sf::RenderStates states){
Entity::draw(target, states); }
}
游戏
#define PLAYER_START "../filepath/image.png",
sf::IntRect{0,0,40,60,}, sf::Vector2f(320.0f, 200.0f) //Ease of access
class Game : public sf::Drawable
{
private:
Player player;
public:
Game() { player = Player(PLAYER_START); };
~Game() {};
void draw(sf::RenderTarget &target, sf::RenderStates states)const { target.draw(player); }
};
为了让问题更容易理解,我创建了以下代码示例:
int main(){
sf::RenderWindow window(sf::VideoMode(640, 480), "Game Test");
sf::Event event = sf::Event{};
Game game;
while (window.isOpen())
{
while (window.pollEvent(event))
if (event.type == sf::Event::Closed)
window.close();
window.clear();
window.draw(game);
window.display();
}
}
此代码生成一个白色方块。
我试过了:
- 在
Game
之外创建一个 Player
并在其上调用 window.draw(player);
。这行得通。
- 正在通过赋值运算符和绘图创建新的
Player
。这行得通。
- 正在通过复制构造函数和绘图创建一个新的
Player
。这行得通。
- 将
Player
插入 Game
class 并绘制它。这 不起作用 并且是我用上面的代码说明的
我意识到这个问题可以(可能)通过将 sf::Sprite
和 sf::Texture
移动到 Player
class 来解决,但是因为我想最终得出 Coin
和实体库 class 中的 Enemy
,我更愿意按原样解决问题。*
感谢您的帮助
/知识
sf::Sprite
的对象将指针存储到纹理。
当你有 player = Player()
时,基数 class 将被称为复制赋值运算符 - 默认情况下由编译器生成。它将所有成员变量一一复制。
执行复制分配后:
entity1 = entity2;
我们有:
entity1.eSprite = entity2.eSprite; // shallow copy
entity1.eTex = entity2.eTex;
和关键点 - entity1.eSprite
指向什么纹理?是entity2.eTex!对你来说不幸的是,entity2 在你的情况下是临时的,所以你在 sprite 中有指向纹理的悬空指针......SFML 中的常见错误,它在 SFML.
的官方参考中描述
You successfully loaded a texture, constructed a sprite correctly,
and... all you see on your screen now is a white square. What
happened?
This is a common mistake. When you set the texture of a sprite, all it
does internally is store a pointer to the texture instance. Therefore,
if the texture is destroyed or moves elsewhere in memory, the sprite
ends up with an invalid texture pointer.
解决方案,添加复制赋值运算符,正确设置精灵纹理,如deep-copy:
Entity& operator=(const Entity& theOther) {
if (this != &theOther) {
this->eTex = theOther.eTex;
this->eSprite.setTexture(this->eTex); // the most imporant line in this answer
}
return *this;
}
我正在做一个游戏项目,发现自己陷入了以下问题:
我有一个名为 Game : public sf::Drawable
的 class,我用它(除其他外)绘制游戏中的所有内容。 Game
包含一个名为 Player : public Entity
的 class,它又是 Entity : public sf::Drawable
的子 class。
这些class稍微简化了,但是受影响的功能是一样的:
实体
class Entity : public sf::Drawable
{
private:
sf::Sprite eSprite;
sf::Texture eTex;
std::string texpath;
public:
virtual Entity(std::string texpath, sf::IntRect intrect){
this->texpath = texpath;
eTex.loadFromFile(texpath, intrect);
eSprite.setTexture(eTex); }
virtual ~Entity(){}
virtual void draw(sf::RenderTarget target, sf::RenderStates states)const{
target.draw(this->eSprite);}
//Lots of other functions
}
玩家
class Player : public Entity¨
{
public:
~Player(){}
Player(std::string texpath, sf::IntRect spriteintrect)
:Entity(texpath, spriteintrect){}
void draw(sf::RenderTarget target, sf::RenderStates states){
Entity::draw(target, states); }
}
游戏
#define PLAYER_START "../filepath/image.png",
sf::IntRect{0,0,40,60,}, sf::Vector2f(320.0f, 200.0f) //Ease of access
class Game : public sf::Drawable
{
private:
Player player;
public:
Game() { player = Player(PLAYER_START); };
~Game() {};
void draw(sf::RenderTarget &target, sf::RenderStates states)const { target.draw(player); }
};
为了让问题更容易理解,我创建了以下代码示例:
int main(){
sf::RenderWindow window(sf::VideoMode(640, 480), "Game Test");
sf::Event event = sf::Event{};
Game game;
while (window.isOpen())
{
while (window.pollEvent(event))
if (event.type == sf::Event::Closed)
window.close();
window.clear();
window.draw(game);
window.display();
}
}
此代码生成一个白色方块。
我试过了:
- 在
Game
之外创建一个Player
并在其上调用window.draw(player);
。这行得通。 - 正在通过赋值运算符和绘图创建新的
Player
。这行得通。 - 正在通过复制构造函数和绘图创建一个新的
Player
。这行得通。 - 将
Player
插入Game
class 并绘制它。这 不起作用 并且是我用上面的代码说明的
我意识到这个问题可以(可能)通过将 sf::Sprite
和 sf::Texture
移动到 Player
class 来解决,但是因为我想最终得出 Coin
和实体库 class 中的 Enemy
,我更愿意按原样解决问题。*
感谢您的帮助 /知识
sf::Sprite
的对象将指针存储到纹理。
当你有 player = Player()
时,基数 class 将被称为复制赋值运算符 - 默认情况下由编译器生成。它将所有成员变量一一复制。
执行复制分配后:
entity1 = entity2;
我们有:
entity1.eSprite = entity2.eSprite; // shallow copy
entity1.eTex = entity2.eTex;
和关键点 - entity1.eSprite
指向什么纹理?是entity2.eTex!对你来说不幸的是,entity2 在你的情况下是临时的,所以你在 sprite 中有指向纹理的悬空指针......SFML 中的常见错误,它在 SFML.
You successfully loaded a texture, constructed a sprite correctly, and... all you see on your screen now is a white square. What happened?
This is a common mistake. When you set the texture of a sprite, all it does internally is store a pointer to the texture instance. Therefore, if the texture is destroyed or moves elsewhere in memory, the sprite ends up with an invalid texture pointer.
解决方案,添加复制赋值运算符,正确设置精灵纹理,如deep-copy:
Entity& operator=(const Entity& theOther) {
if (this != &theOther) {
this->eTex = theOther.eTex;
this->eSprite.setTexture(this->eTex); // the most imporant line in this answer
}
return *this;
}