【问题标题】:SFML - Sprite is blank after loading from textureSFML - 从纹理加载后 Sprite 为空白
【发布时间】:2021-02-01 03:20:24
【问题描述】:

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

下面的sn-ps中我的代码有问题吗?它们应该很容易阅读:)。

我的代码:

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

菜单.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);
};

菜单.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);
}

【问题讨论】:

    标签: c++ graphics textures sprite sfml


    【解决方案1】:

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

    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 对象 background - Menu 数据成员 - 比其关联的 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 对象。

    【讨论】:

    • 完美,非常感谢!我让 Texture bg 成为 Menu.h 的成员,这样它就不会被破坏了!很好的答案!
    猜你喜欢
    • 2020-07-21
    • 1970-01-01
    • 2015-03-13
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 2016-08-19
    • 1970-01-01
    相关资源
    最近更新 更多