【问题标题】:Images not displayed using sprites in SFML未使用 SFML 中的精灵显示的图像
【发布时间】:2018-03-05 05:39:06
【问题描述】:

我在 Linux Mint 18.1 上使用 C++17 学习了 SFML 2.3.2 来学习使用 GUI。作为 Hello World 之后的第二个项目,我正在尝试重现 Snake,该游戏旧手机已预装。到目前为止,大部分东西都可以正常工作,除了一些我以后必须处理的小例外,有些是由于游戏尚未完全完成造成的。

只是为了确保我正确理解了这个问题,因为我以前从未使用过低级语言的 GUI 和图像。首先将图像加载到纹理中,然后将纹理添加到精灵,然后将该精灵绘制到窗口上?

程序可以完美编译,正确初始化所有内容,并且运行时没有出现无法解释的重大问题。除了图像不显示。精灵在那里并以其默认的单色背景颜色显示,但不显示任何图像。

我做错了什么,我该如何解决?谢谢!

// HEADERS
#include <iostream>
#include <SFML/Graphics.hpp>
#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/Rect.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/System/String.hpp>
#include <SFML/Window/Keyboard.hpp>

// CREATE NEW FONT
sf::Font create_font()
{
    sf::Font f;
    bool id = f.loadFromFile("/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-B.ttf");

    if (id == false)
    {
        std::cerr << "Font:\tCould not be loaded." << std::endl;
    }
    else
    {
        std::cerr << "Font:\tLoaded successfully." << std::endl;
    }

    return f;

}

// CREATE NEW SPRITE USING TEXTURE, GIVEN ARE PATH WITH COORDINATES AND DIMENSIONS
sf::Sprite load_img(std::string path, long x, long y, long w, long h)
{
    sf::Texture t;
    bool id = t.loadFromFile(path);

    if (id == false)
    {
        std::cerr << "Texture:\t" << path << "\tFailed to load." << std::endl;
    }
    else
    {
        std::cerr << "Texture:\t" << path << "\tLoaded successfully." << std::endl;
    }

    sf::Sprite s(t);
    s.setTextureRect(sf::IntRect((int)x, (int)y, (int)w, (int)h));
    s.setPosition(x, y);
    return s;
}


// MAIN FUNCTION
int main()
{
    // DECLARING/DEFINING VARIABLES
    unsigned long window_width = 512;
    unsigned long window_height = 512;
    unsigned long score = 0;
    unsigned long head_old_position_x, head_old_position_y;
    std::string title = "Snek";
    std::string wdir = "/home/kate/Documents/coding/snek/";

    // WINDOW
    sf::RenderWindow window(sf::VideoMode(window_width, window_height), title);
    window.setFramerateLimit(60);

    // SPRITES
    sf::Sprite background = load_img(wdir + "img/background.png", 0, 0, 512, 512);
    sf::Sprite head = load_img(wdir + "img/head.png", 47, 39, 8, 8);
    sf::Sprite body = load_img(wdir + "img/body.png", 39, 39, 8, 8);
    sf::Sprite poison = load_img(wdir + "img/poison.png", 119, 119, 8, 8);
    sf::Sprite trap = load_img(wdir + "img/trap.png", 159, 159, 8, 8);
    sf::Sprite candy = load_img(wdir + "img/candy.png", 199, 199, 8, 8);

    // FONT
    sf::Font font = create_font();

    // TEXT
    sf::Text score_display(title, font, 20);
    sc// HEADERS
#include <iostream>
#include <SFML/Graphics.hpp>
#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/Rect.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/System/String.hpp>
#include <SFML/Window/Keyboard.hpp>

// CREATE NEW FONT
sf::Font create_font()
{
    sf::Font f;
    bool id = f.loadFromFile("/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-B.ttf");

    if (id == false)
    {
        std::cerr << "Font:\tCould not be loaded." << std::endl;
    }
    else
    {
        std::cerr << "Font:\tLoaded successfully." << std::endl;
    }

    return f;

}

// CREATE NEW SPRITE USING TEXTURE, GIVEN ARE PATH WITH COORDINATES AND DIMENSIONS
sf::Sprite load_img(std::string path, long x, long y, long w, long h)
{
    sf::Texture t;
    bool id = t.loadFromFile(path);

    if (id == false)
    {
        std::cerr << "Texture:\t" << path << "\tFailed to load." << std::endl;
    }
    else
    {
        std::cerr << "Texture:\t" << path << "\tLoaded successfully." << std::endl;
    }

    sf::Sprite s(t);
    s.setTextureRect(sf::IntRect((int)x, (int)y, (int)w, (int)h));
    s.setPosition(x, y);
    return s;
}


// MAIN FUNCTION
int main()
{
    // DECLARING/DEFINING VARIABLES
    unsigned long window_width = 512;
    unsigned long window_height = 512;
    unsigned long score = 0;
    unsigned long head_old_position_x, head_old_position_y;
    std::string title = "Snek";
    std::string wdir = "/home/kate/Documents/coding/snek/";

    // WINDOW
    sf::RenderWindow window(sf::VideoMode(window_width, window_height), title);
    window.setFramerateLimit(60);

    // SPRITES
    sf::Sprite background = load_img(wdir + "/img/background.png", 0, 0, 512, 512);
    sf::Sprite head = load_img(wdir + "/img/head.png", 47, 39, 8, 8);
    sf::Sprite body = load_img(wdir + "/img/body.png", 39, 39, 8, 8);
    sf::Sprite poison = load_img(wdir + "/img/poison.png", 119, 119, 8, 8);
    sf::Sprite trap = load_img(wdir + "/img/trap.png", 159, 159, 8, 8);
    sf::Sprite candy = load_img(wdir + "/img/candy.png", 199, 199, 8, 8);

    // FONT
    sf::Font font = create_font();

    // TEXT
    sf::Text score_display(title, font, 20);
    score_display.setString(std::to_string(score));
    score_display.setPosition(5, 5);

    // LOOP
    while (window.isOpen())
    {
        sf::Event event;
        while ( window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            { window.close(); }

            head_old_position_x = head.getPosition().x;
            head_old_position_y = head.getPosition().y;

            // MOVEMENT BASED ON KEYBOARD INPUT
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
            {
                head.setPosition(head.getPosition().x - 8, head.getPosition().y);
                body.setPosition(head_old_position_x, head_old_position_y);
            }

            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
            {
                head.setPosition(head.getPosition().x, head.getPosition().y - 8);
                body.setPosition(head_old_position_x, head_old_position_y);
            }

            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
            {
                head.setPosition(head.getPosition().x + 8, head.getPosition().y);
                body.setPosition(head_old_position_x, head_old_position_y);
            }

            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
            {
                head.setPosition(head.getPosition().x, head.getPosition().y + 8);
                body.setPosition(head_old_position_x, head_old_position_y);
            }


            if (body.getPosition().x == candy.getPosition().x && body.getPosition().y == candy.getPosition().y)
            {
                score ++;
                score_display.setString(std::to_string(score));
            }


            // REFRESH WINDOW
            window.clear();
            window.draw(background);
            window.draw(head);
            window.draw(body);
            window.draw(poison);
            window.draw(trap);
            window.draw(candy);
            window.draw(score_display);
            window.display();
        }
    }

    return 0;
}
ore_display.setString(std::to_string(score));
    score_display.setPosition(5, 5);

    // LOOP
    while (window.isOpen())
    {
        sf::Event event;
        while ( window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            { window.close(); }

            head_old_position_x = head.getPosition().x;
            head_old_position_y = head.getPosition().y;

            // MOVEMENT BASED ON KEYBOARD INPUT
            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
            {
                head.setPosition(head.getPosition().x - 8, head.getPosition().y);
                body.setPosition(head_old_position_x, head_old_position_y);
            }

            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
            {
                head.setPosition(head.getPosition().x, head.getPosition().y - 8);
                body.setPosition(head_old_position_x, head_old_position_y);
            }

            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
            {
                head.setPosition(head.getPosition().x + 8, head.getPosition().y);
                body.setPosition(head_old_position_x, head_old_position_y);
            }

            if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
            {
                head.setPosition(head.getPosition().x, head.getPosition().y + 8);
                body.setPosition(head_old_position_x, head_old_position_y);
            }


            if (body.getPosition().x == candy.getPosition().x && body.getPosition().y == candy.getPosition().y)
            {
                score ++;
                score_display.setString(std::to_string(score));
            }


            // REFRESH WINDOW
            window.clear();
            window.draw(background);
            window.draw(head);
            window.draw(body);
            window.draw(poison);
            window.draw(trap);
            window.draw(candy);
            window.draw(score_display);
            window.display();
        }
    }

    return 0;
}

【问题讨论】:

  • 控制台有消息吗?
  • 图片不显示的常见原因是纹理超出范围,或者无法加载。
  • @ArnavBorborah 不,任何 SFML 函数都没有。我自己的错误检查确认一切应该按预期工作。

标签: c++ image user-interface sfml c++17


【解决方案1】:

您的纹理超出范围,请参阅When is an object "out of scope"? 了解更多详细信息。您在 load_img 函数中声明了纹理,但在您退出 load_img 并返回精灵后,sf::Texture t; 被删除。

所以这是一个更新的函数,您可以在其中将纹理存储在 load_img 函数之外并通过引用传递它。仅显示相关部分。首先将纹理传递给 load_img 函数。删除sf::Texture t;

sf::Sprite load_img(std::string path, long x, long y, long w, long h, sf::Texture& t)
{
    bool id = t.loadFromFile(path);
    [...]
}

声明一个纹理并将其传递给 load_img 函数。

sf::Texture headtexture;
sf::Sprite head = load_img(wdir + "img/head.png", 47, 39, 8, 8, headtexture);

如果您对所有精灵执行此操作,它可以正常工作并正确显示图像/精灵。

编辑 2017 年 9 月 25 日

基于 cmets,这是一个没有函数的最小工作示例:

// HEADERS
#include <iostream>
#include <SFML/Graphics.hpp>
#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/Rect.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/System/String.hpp>
#include <SFML/Window/Keyboard.hpp>

// MAIN FUNCTION
int main()
{
    // DECLARING/DEFINING VARIABLES
    unsigned long window_width = 512;
    unsigned long window_height = 512;
    std::string title = "Snek";
    std::string wdir = "/home/kate/Documents/coding/snek/";

    // WINDOW
    sf::RenderWindow window(sf::VideoMode(window_width, window_height), title);
    window.setFramerateLimit(60);

    // SPRITES
    sf::Texture headtexture;
    sf::Sprite head;

    headtexture.loadFromFile(wdir + "img/head.png");
    head.setTexture(headtexture);
    head.setTextureRect(sf::IntRect(47, 39, 8, 8));
    head.setPosition(30, 30);

    // LOOP
    while (window.isOpen())
    {
        sf::Event event;
        while ( window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            { window.close(); }

            // REFRESH WINDOW
            window.clear();
            window.draw(head);
            window.display();
        }
    }

    return 0;
}

【讨论】:

  • 我昨天就已经怀疑了,并将所有内容移至 int main() 以确保 100% 确定。精灵以其默认的单色背景颜色显示,但图像不存在。基本上,我看到的只是窗口的黑色背景。
  • 是的,但目前你在函数内部定义纹理,当你退出它时它会超出范围,导致未定义的行为。
  • 我已对其进行了更改,以便在 int main() 中专门使用纹理和精灵。它永远不会去其他任何地方。还是不行。
  • 你通过引用 sf::Texture&amp; t 将纹理传递给 load_img,如我的回答所示?
  • 这不是问题。纹理不可能超出范围,因为它是在函数内部设置的。
【解决方案2】:

您已经失去了对纹理的引用。在您的情况下,纹理是 load_img() 函数中的局部变量。

当任何精灵使用它时,你应该保持你的纹理加载并可用。

我建议您阅读解释此问题的 SFML 教程的 this 部分。

【讨论】:

  • 我在 cmets 中读到您将所有内容移至 main。你能用那个代码更新吗?也许这样我们可以找出任何错误
  • 这是问题的一部分,但主要问题在其他地方。请参阅我标记为解决方案的答案。这是这里的主要问题。
【解决方案3】:

好的,我想我明白了。

可能没有显示任何内容,因为您在事件循环中拥有所有绘图内容

尝试将这些内容放在while(window.isOpen()) 循环范围内。

【讨论】:

  • 是的。而已!谢谢!终于 :D 上周疯狂地浏览我的代码,但找不到。
猜你喜欢
  • 1970-01-01
  • 2019-02-20
  • 2020-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-31
  • 2013-02-25
  • 2019-03-10
相关资源
最近更新 更多