SFML2.6 系统模块--用户数据流

介绍

SFML有几个资源类:图像、字体、声音等。在大多数程序中,这些资源将从文件中加载,借助于它们的loadFromFile函数。在另外一些情况下,资源将直接打包到可执行文件或大型数据文件中,并使用loadFromMemory从内存中加载。这些函数几乎涵盖了所有可能的用例,但不是全部。

有时,您想从不寻常的地方加载文件,例如压缩/加密存档或远程网络位置。对于这些特殊情况,SFML提供了第三个加载函数:loadFromStream。该函数使用抽象的sf::InputStream接口读取数据,该接口允许您提供自己实现的流类,该类可以与SFML一起使用。

在本教程中,您将学习如何编写和使用自己派生的输入流。

关于标准流

与许多其他语言一样,C++已经有了一个用于输入数据流的类:std::istream。实际上,它有两个:std::istream只是前端,用于自定义数据的抽象接口是std::streambuf。

不幸的是,这些类并不是非常用户友好的,如果您想要实现非平凡的东西,它们可能变得非常复杂。Boost.Iostreams库尝试为标准流提供更简单的接口,但Boost是一个庞大的依赖项,SFML不能依赖于它。

这就是为什么SFML提供了自己的流接口,希望它更简单和更快。

InputStream

sf::InputStream类声明了四个虚函数:

class InputStream
{
public :

    virtual ~InputStream() {}

    virtual Int64 read(void* data, Int64 size) = 0;

    virtual Int64 seek(Int64 position) = 0;

    virtual Int64 tell() = 0;

    virtual Int64 getSize() = 0;
};

read函数必须从流中提取size字节的数据,并将它们复制到提供的数据地址。它返回读取的字节数,或者在出现错误时返回-1。

seek函数必须更改流中的当前读取位置。它 的position参数是要跳转到的绝对字节偏移量(因此它相对于数据的开头而不是当前位置)。它返回新位置,或在出现错误时返回-1。

tell函数必须返回流中的当前读取位置(以字节为单位),或者在出现错误时返回-1。

getSize函数必须返回包含在流中的数据的总大小(以字节为单位),或者在出现错误时返回-1。

要创建自己的工作流,必须根据它们的要求实现这四个函数中的每一个。

FileInputStream 和MemoryInputStream

从SFML 2.3开始,创建了两个新类来为新的内部音频管理提供流。sf::FileInputStream提供了文件的只读数据流,而sf::MemoryInputStream从内存中提供了只读流。它们都派生自sf::InputStream,因此可以使用多态。

使用InputStream

使用自定义流类很简单:实例化它,然后将其传递给要加载的对象的loadFromStream(或openFromStream)函数。

sf::FileStream stream;
stream.open("image.png");

sf::Texture texture;
texture.loadFromStream(stream);

例子

如果您需要一个演示,帮助您专注于代码的工作原理,而不是迷失于实现细节中,您可以查看sf::FileInputStream或sf::MemoryInputStream的实现。

不要忘记检查论坛和维基百科。 另一个用户可能已经编写了适合您需求的sf::InputStream类。如果您编写了一个新的类并且认为它也可能对其他人有用,请不要犹豫,分享它!

常见错误

在调用loadFromStream后,有些资源类并不完全加载。相反,只要它们在使用,它们就会继续从其数据源中读取数据。这适用于sf::Music,它会在播放时流式传输音频样本,以及sf::Font,它会根据显示的文本即时加载字形。

因此,您用于加载音乐或字体的流实例及其数据源必须在资源使用它的整个生命周期中保持活动状态。如果在仍在使用时销毁它,它将导致未定义的行为(可能会导致崩溃,数据损坏或无任何可见变化)。

另一个常见的错误是直接返回内部函数返回的任何内容,但有时它与SFML所期望的不匹配。例如,在sf::FileInputStream代码中,可能会尝试将seek函数编写如下:

sf::Int64 FileInputStream::seek(sf::Int64 position)
{
    return std::fseek(m_file, position, SEEK_SET);
}

这段代码是错误的,因为std::fseek成功时返回零,而SFML期望返回新位置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面我会给你讲解如何使用SFML来实现n-puzzle游戏的可视化。首先,我们需要了解一下SFML是什么。 SFML是一个跨平台的图形库,它提供了简单易用的API,可以帮助我们快速创建2D游戏和图形应用程序。它支持多种编程语言,包括C++、Python、Java等。 接下来,我们可以开始实现n-puzzle游戏的可视化了。首先,我们需要创建一个窗口来显示游戏界面。以下是创建窗口的代码: ```cpp #include <SFML/Graphics.hpp> int main() { sf::RenderWindow window(sf::VideoMode(800, 600), "N-Puzzle Game"); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); } window.clear(sf::Color::White); // 绘制游戏界面 window.display(); } return 0; } ``` 这段代码创建了一个800x600大小的窗口,并且在每一帧中都会清空窗口并绘制游戏界面。接下来,我们需要实现游戏界面的绘制。 n-puzzle游戏的界面由一个N*N的网格组成,每个格子中都会有一个数字。我们可以使用SFML中的矩形来表示每个格子,并且使用文本来显示数字。以下是绘制游戏界面的代码: ```cpp const int N = 3; const int tileSize = 100; sf::RectangleShape tile(sf::Vector2f(tileSize, tileSize)); tile.setFillColor(sf::Color::White); tile.setOutlineColor(sf::Color::Black); tile.setOutlineThickness(2); sf::Font font; font.loadFromFile("arial.ttf"); sf::Text text("", font, tileSize / 2); text.setFillColor(sf::Color::Black); text.setStyle(sf::Text::Bold); text.setOrigin(text.getGlobalBounds().width / 2, text.getGlobalBounds().height / 2); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { int number = i * N + j + 1; if (number == N * N) continue; tile.setPosition(j * tileSize, i * tileSize); text.setString(std::to_string(number)); text.setPosition(j * tileSize + tileSize / 2, i * tileSize + tileSize / 2); window.draw(tile); window.draw(text); } } ``` 这段代码首先定义了每个格子的大小为100x100,并且使用白色填充和黑色边框。然后,它加载了一个字体文件,并且创建了一个文本对象来显示数字。最后,它使用两个嵌套循环来绘制整个游戏界面。 这样,我们就完成了n-puzzle游戏的可视化。完整代码如下: ```cpp #include <SFML/Graphics.hpp> const int N = 3; const int tileSize = 100; int main() { sf::RenderWindow window(sf::VideoMode(N * tileSize, N * tileSize), "N-Puzzle Game"); sf::RectangleShape tile(sf::Vector2f(tileSize, tileSize)); tile.setFillColor(sf::Color::White); tile.setOutlineColor(sf::Color::Black); tile.setOutlineThickness(2); sf::Font font; font.loadFromFile("arial.ttf"); sf::Text text("", font, tileSize / 2); text.setFillColor(sf::Color::Black); text.setStyle(sf::Text::Bold); text.setOrigin(text.getGlobalBounds().width / 2, text.getGlobalBounds().height / 2); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); } window.clear(sf::Color::White); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { int number = i * N + j + 1; if (number == N * N) continue; tile.setPosition(j * tileSize, i * tileSize); text.setString(std::to_string(number)); text.setPosition(j * tileSize + tileSize / 2, i * tileSize + tileSize / 2); window.draw(tile); window.draw(text); } } window.display(); } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值