SFML - 从纹理加载后 Sprite 为空白

SFML - Sprite is blank after loading from texture

我正在使用 SFML 在屏幕上显示精灵。我首先使用纹理并调用 loadFromFile() 来加载图像。这很有效,没有发生错误。似乎图像路径是正确的并且它加载了图像,但它似乎没有将数据存储在精灵中。精灵显示没有错误,但显示空白图像。

我的以下代码片段中的代码是否有问题?它们应该相当容易阅读:)。

我的代码:

Main.cpp

#include <SFML/Graphics.hpp>
#include "Menu.h"

using namespace sf;

int main()
{
    VideoMode vm = VideoMode::getDesktopMode();
    int width = vm.width, height = vm.height;
    RenderWindow window(VideoMode(width, height), "Score Arena v1.0", Style::Fullscreen);
    window.setPosition(Vector2i(0, 0));

    Menu menu(width, height);

    while (window.isOpen())
    {
        Event event;
        while (window.pollEvent(event))
        {
            switch (event.type) {
                case Event::Closed:
                    window.close();
                    break;

                //when a key is pressed
                case Event::KeyPressed:
                    if (Keyboard::isKeyPressed(Keyboard::Escape))
                        window.close();
                    break;
            }
        }

        window.clear();
        
        menu.draw(window);

        window.display();
    }

    return 0;
}

Menu.h

#pragma once
#include <string>
#include <SFML/Graphics.hpp>

using namespace std;
using namespace sf;

class Menu {
        int page = 0;
        string title = "Score Arena";
        string labels[4]{
                "Single Player",
                "Multi Player",
                "Options",
                "Exit"
        };
        Sprite background;

        int width, height;

public:
        Menu(int, int);
        void draw(RenderWindow &window);
};

Menu.cpp

#include "Menu.h"
#include <SFML/Graphics.hpp>
#include <iostream>

Menu::Menu(int width, int height) {
        this->width = width;
        this->height = height;

        Texture bg;
        if (!bg.loadFromFile("menuBg.jpg"))
                std::cout << "Error loading image!" << std::endl;
        background.setTexture(bg);
}

void Menu::draw(RenderWindow &window) {
        window.draw(background, RenderStates::Default);
}

当您调用 setTexture() 成员函数时,sf::Sprite 对象不会在内部复制传递的 sf::Texture 对象。一个 sf::Sprite 只是指一个 sf::Texture;前者不拥有后者。呈现 sf::Sprite.

时,关联的 sf::Texture 必须存在

sf::Sprite 的文档中说明:

It is important to note that the sf::Sprite instance doesn't copy the texture that it uses, it only keeps a reference to it. Thus, a sf::Texture must not be destroyed while it is used by a sf::Sprite (i.e. never write a function that uses a local sf::Texture instance for creating a sprite).

问题出在您的 Menu 的构造函数中:

Menu::Menu(int width, int height) {
        this->width = width;
        this->height = height;

        Texture bg; // <-- it is local variable !!!
        if (!bg.loadFromFile("menuBg.jpg"))
                std::cout << "Error loading image!" << std::endl;
        background.setTexture(bg); // <-- associating sprite to a local object!!!
        // bg goes out of existence!!!
}

sf::Texture 对象 bg 在程序控制流离开构造函数后立即停止存在,因为 bg 是构造函数内的局部变量。结果,sf::Sprite 对象 backgroundMenu 数据成员 – 比其关联的 sf::Texture 对象 bg – 本地对象。

然后,在 Menu::draw() 中使用这个 sf::Sprite 对象,background,它在内部引用一个不再存在的 sf::Texture 对象:

void Menu::draw(RenderWindow &window) {
        window.draw(background, RenderStates::Default);
}

可能的解决方案

Menu 的构造函数中,sf::Texture 对象不是 本地对象 ,您可以使它成为 数据成员 / Menu:

class Menu {
        // ...
        Texture bg;
        Sprite background;
        // ...
};

这样,Menu 拥有 bg(与之前 Menu 的构造函数拥有 bg 相反),因此 Menu 控制 bg 的生命周期:bgMenu 对象存在时保持活动状态。这一次,当您调用 Menu::draw() 时,sf::Sprite 对象确实引用了一个活跃的 sf::Texture 对象。