在 SFML 中不使用精灵显示图像
Images not displayed using sprites in SFML
我已经使用 C++17 在 Linux Mint 18.1 上学习了 SFML 2.3.2 来学习使用 GUI。作为 Hello World 之后的第二个项目,我正在尝试重现 Snake,该游戏已预装在旧手机中。大多数东西到现在都有效,除了一些我稍后必须处理的小例外,一些是由于游戏尚未完全完成造成的。
只是为了确保我正确理解了这件事,因为我以前从未使用过低级语言使用过 GUI 和图像。首先将图像加载到纹理中,然后将纹理添加到精灵中,然后将该精灵绘制到 window?
该程序编译无误,正确初始化所有内容,并且运行时没有出现无法解释的重大问题。除了图像不显示。精灵在那里并以默认的单色 chrome 背景颜色显示,但不显示任何图像。
我做错了什么,我该如何解决?谢谢!
// 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;
}
您的纹理超出范围,请参阅 When is an object "out of scope"? 了解更多详情。您在 load_img 函数中声明了纹理,但是 sf::Texture t;
在退出 load_img 和 return 精灵后被删除。
所以这是一个更新的函数,您可以在其中将纹理存储在 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);
如果您对所有精灵都这样做,它会正常工作并正确显示 images/sprites。
编辑 2017 年 9 月 25 日
根据评论,这是一个没有函数的最小工作示例:
// 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;
}
您丢失了对纹理的引用。在您的情况下,纹理是 load_img()
函数中的局部变量。
当任何 sprite 使用它时,您应该保持纹理加载和可用。
我建议您阅读解释此问题的 SFML 教程的 this 部分。
好的,我想我明白了。
可能没有显示任何内容,因为您在事件循环
中拥有所有绘图内容
尝试将这些内容放入 while(window.isOpen())
循环范围。
我已经使用 C++17 在 Linux Mint 18.1 上学习了 SFML 2.3.2 来学习使用 GUI。作为 Hello World 之后的第二个项目,我正在尝试重现 Snake,该游戏已预装在旧手机中。大多数东西到现在都有效,除了一些我稍后必须处理的小例外,一些是由于游戏尚未完全完成造成的。
只是为了确保我正确理解了这件事,因为我以前从未使用过低级语言使用过 GUI 和图像。首先将图像加载到纹理中,然后将纹理添加到精灵中,然后将该精灵绘制到 window?
该程序编译无误,正确初始化所有内容,并且运行时没有出现无法解释的重大问题。除了图像不显示。精灵在那里并以默认的单色 chrome 背景颜色显示,但不显示任何图像。
我做错了什么,我该如何解决?谢谢!
// 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;
}
您的纹理超出范围,请参阅 When is an object "out of scope"? 了解更多详情。您在 load_img 函数中声明了纹理,但是 sf::Texture t;
在退出 load_img 和 return 精灵后被删除。
所以这是一个更新的函数,您可以在其中将纹理存储在 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);
如果您对所有精灵都这样做,它会正常工作并正确显示 images/sprites。
编辑 2017 年 9 月 25 日
根据评论,这是一个没有函数的最小工作示例:
// 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;
}
您丢失了对纹理的引用。在您的情况下,纹理是 load_img()
函数中的局部变量。
当任何 sprite 使用它时,您应该保持纹理加载和可用。
我建议您阅读解释此问题的 SFML 教程的 this 部分。
好的,我想我明白了。
可能没有显示任何内容,因为您在事件循环
中拥有所有绘图内容尝试将这些内容放入 while(window.isOpen())
循环范围。