【问题标题】:SFML draw call to subclass draws as white squareSFML 对子类的绘制调用绘制为白色方块
【发布时间】:2020-03-26 15:29:31
【问题描述】:

我正在开发一个游戏项目,发现自己陷入了以下问题:

我有一个名为Game : public sf::Drawable 的类,我用来(除其他外)在我的游戏中绘制所有内容。 Game 包含一个名为Player : public Entity 的类,它又是Entity : public sf::Drawable 的子类。


这些类略有简化,但受影响的功能是一样的:

实体

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 类并绘制它。这不起作用,我用上面的代码说明了这一点

我意识到这个问题可以(可能)通过将sf::Spritesf::Texture 移动到Player 类来解决,但是由于我想最终从实体基类派生CoinEnemy,我更愿意按原样解决问题。*

感谢您的帮助 /传说

【问题讨论】:

    标签: c++ inheritance sfml


    【解决方案1】:

    sf::Sprite 的对象存储指向纹理的指针。

    当你有player = Player() 为基类时,将被称为复制赋值运算符 - 默认情况下由编译器生成。它一一复制所有成员变量。

    在执行复制分配后:

    entity1 = entity2;
    

    我们有:

    entity1.eSprite = entity2.eSprite; // shallow copy
    entity1.eTex = entity2.eTex;
    

    还有关键点——entity1.eSprite 指向的纹理是什么?它是entity2.eTex!不幸的是,entity2 在你的情况下是临时的,所以你有指向精灵内部纹理的悬空指针...... SFML 中的常见错误,它在SFML 的官方参考中有所描述。

    您成功加载了纹理,正确构建了精灵, 并且... 你现在在屏幕上看到的只是一个白色方块。什么 发生了什么?

    这是一个常见的错误。当您设置精灵的纹理时,所有 内部做的是存储一个指向纹理实例的指针。所以, 如果纹理被破坏或移动到内存中的其他位置,则精灵 以无效的纹理指针结束。

    解决方案,添加复制赋值运算符,正确设置精灵的纹理,如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;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多