Вызов SFML для подкласса dr aws в виде белого квадрата - PullRequest
0 голосов
/ 26 марта 2020

Я работаю над игровым проектом и обнаружил, что застрял в следующей проблеме:

У меня есть класс с именем 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();
    }
}

Этот код создает белый квадрат.

Я пробовал:

  • Создание Player вне Game и вызов window.draw(player); для него. Это работает.
  • Создание нового Player с помощью оператора присваивания и рисования. Это работает.
  • Создание нового Player через конструктор копирования и чертеж. Это работает.
  • Вставка Player в класс Game и рисование этого. Это не работает и является тем, что я иллюстрирую приведенным выше кодом

. Я понимаю, что эту проблему (вероятно) можно решить, переместив sf::Sprite и sf::Texture в Player класса, но так как я хочу в конечном итоге получить Coin и Enemy из базового класса Entity, я бы предпочел решить проблему как есть. *

Спасибо за любую помощь / знания

1 Ответ

0 голосов
/ 26 марта 2020

Объекты sf::Sprite хранят POINTER для текстур.

Если у вас есть player = Player() для базового класса, будет вызван оператор копирования копирования - генерируемый компилятором по умолчанию. Он копирует все переменные-члены одну за другой.

После выполнения этого назначения копирования для:

entity1 = entity2;

мы имеем:

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

и ключевой момент - какая текстура указано entity1.eSprite? Это entity2.eTex ! И, к сожалению для вас, entity2 является временным в вашем случае, поэтому у вас есть висячий указатель на текстуру внутри спрайта ... распространенная ошибка в SFML, и она описана в официальной ссылке SFML .

Вы успешно загрузили текстуру, правильно построили спрайт, и ... теперь все, что вы видите на экране, это белый квадрат. Что случилось?

Это распространенная ошибка. Когда вы устанавливаете текстуру спрайта, все, что он делает внутри, это сохраняет указатель на экземпляр текстуры. Поэтому, если текстура уничтожена или перемещена в другое место в памяти, спрайт заканчивается недопустимым указателем текстуры.

Решение, добавьте оператор присваивания копии, который правильно устанавливает текстуру для спрайта, как -копия :

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;
}
...