对子类绘制的 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();
    }
}

此代码生成一个白色方块。

我试过了:

我意识到这个问题可以(可能)通过将 sf::Spritesf::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;
}