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

时间:2020-10-18 01:26:09

标签: c++ graphics textures sprite sfml

我正在使用SFML在屏幕上显示精灵。我首先使用纹理并调用loadFromFile()加载图像。这很好,不会发生任何错误。图像路径似乎正确并且已加载图像,但似乎未将数据存储在Sprite中。精灵显示无误,但显示空白图像。

以下代码段中的代码是否存在问题?它们应该很容易阅读:)。

我的代码:

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

1 个答案:

答案 0 :(得分:2)

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

sf::Sprite的文档中对此进行了说明:

请注意,sf::Sprite实例不会复制 它使用的纹理,仅保留对其的引用。因此, sf::Texture使用sf::Sprite时不得销毁它 (即,永远不要编写使用本地sf::Texture实例的函数 用于创建精灵)。

问题出在您的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);
}

可能的解决方案

sf::Texture的构造函数中,Menu对象不是 local对象,您可以使其成为{{的 data成员 1}}:

Menu

通过这种方式,class Menu { // ... Texture bg; Sprite background; // ... }; 拥有Menu(与以前一样,bg的构造函数拥有Menu)因此bg控制Menu的生命周期:bg对象生存期间,bg被保持活动状态。这次,当您调用Menu时,Menu::draw()对象确实引用了一个活跃的sf::Sprite对象。