简体   繁体   English

SFML - 从纹理加载后精灵为空白

[英]SFML - Sprite is blank after loading from texture

I am using SFML to display a sprite on the screen.我正在使用 SFML 在屏幕上显示一个精灵。 I first use a texture and call loadFromFile() to load the image.我首先使用纹理并调用 loadFromFile() 来加载图像。 This works well with no errors occurring.这很有效,不会发生错误。 It seems that the image path is correct and it loads the image, but it doesn't seem to store the data in the sprite.似乎图像路径是正确的,它加载了图像,但它似乎没有将数据存储在精灵中。 The sprite is displayed without error, but it shows a blank white image.精灵显示没有错误,但显示空白图像。

Is there a problem with my code in the following snippets?我的以下代码段中的代码有问题吗? They should be fairly easy to read :).它们应该很容易阅读:)。

My code:我的代码:

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

An sf::Sprite object doesn't internally copy the passed sf::Texture object when you call the setTexture() member function.当您调用setTexture()成员函数时, sf::Sprite对象不会在内部复制传递的sf::Texture对象。 An sf::Sprite just refers to an sf::Texture ;一个sf::Sprite只是指一个sf::Texture the former doesn't own the latter.前者不拥有后者。 The associated sf::Texture must exist when you render the sf::Sprite .渲染sf::Sprite时,关联的sf::Texture必须存在。

It is stated in the documentation for sf::Sprite :它在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.重要的是要注意sf::Sprite实例不会复制它使用的纹理,它只保留对它的引用。 Thus, a sf::Texture must not be destroyed while it is used by a sf::Sprite (ie never write a function that uses a local sf::Texture instance for creating a sprite).因此,当sf::Texturesf::Sprite使用时,不得销毁它(即永远不要编写使用本地sf::Texture实例来创建 sprite 的函数)。

The problem is in your Menu 's constructor:问题出在您的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!!!
}

The sf::Texture object, bg , ceases to exist as soon the program control flow leaves the constructor because bg is a local variable inside the constructor.一旦程序控制流离开构造函数, sf::Texture对象bg就不再存在,因为bg是构造函数内部的局部变量。 As a result, the sf::Sprite object, background – a Menu data member – outlives its associated sf::Texture object, bg – a local object.因此, sf::Sprite对象background ——一个Menu数据成员——比其关联的sf::Texture对象, bg一个本地对象的寿命更长。

Then, in Menu::draw() you use this sf::Sprite object, background , which internally refers to an sf::Texture object that no longer exists:然后,在Menu::draw()使用这个sf::Sprite对象background ,它在内部引用一个不再存在的sf::Texture对象:

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

Possible Solution可能的解决方案

Instead of the sf::Texture object being a local object in Menu 's constructor, you could make it a data member of Menu :取而代之的是的sf::Texture对象是在本地对象Menu的构造函数,你可以把它的数据成员Menu

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

This way, Menu owns bg (in contrast to Menu 's constructor owning bg as was the case before), and therefore Menu controls bg 's lifetime: bg is kept alive while the Menu object lives.这样, Menu拥有bg (与之前的情况相比, Menu的构造函数拥有bg ),因此Menu控制bg的生命周期: bgMenu对象存在时保持活动状态。 This time, when you call Menu::draw() , the sf::Sprite object does refer to a living sf::Texture object.这一次,当您调用Menu::draw()sf::Sprite对象确实引用了一个活的sf::Texture对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM