SFML2.6 图形模块--绘制2D内容

介绍

正如您在之前的教程中学到的那样,SFML的窗口模块提供了一种简单的方法来打开一个OpenGL窗口并处理它的事件,但是当涉及到绘制时,它并没有帮助。您唯一剩下的选择就是使用强大但复杂和低级的OpenGL API。

幸运的是,SFML提供了一个图形模块,它将帮助您以比OpenGL更简单的方式绘制2D实体。

绘制窗口

要绘制图形模块提供的实体,您必须使用一个专用的窗口类:sf::RenderWindow。这个类是从sf::Window派生出来的,继承了它的所有函数。关于sf::Window的所有内容(创建、事件处理、控制帧速率、与OpenGL混合等)同样适用于sf::RenderWindow。

除此之外,sf::RenderWindow 添加了高级函数来帮助您轻松绘制物体。在本教程中,我们将重点介绍这些函数中的两个:clear 和 draw。它们就像它们的名字一样简单:clear 使用选定的颜色清除整个窗口,draw 绘制您传递给它的任何对象。

以下是使用渲染窗口的典型主循环:

#include <SFML/Graphics.hpp>

int main()
{
    // create the window
    sf::RenderWindow window(sf::VideoMode(800, 600), "My window");

    // run the program as long as the window is open
    while (window.isOpen())
    {
        // check all the window's events that were triggered since the last iteration of the loop
        sf::Event event;
        while (window.pollEvent(event))
        {
            // "close requested" event: we close the window
            if (event.type == sf::Event::Closed)
                window.close();
        }

        // clear the window with black color
        window.clear(sf::Color::Black);

        // draw everything here...
        // window.draw(...);

        // end the current frame
        window.display();
    }

    return 0;
}

在绘制任何东西之前调用 clear 是强制性的,否则上一帧的内容将出现在您绘制的任何物体后面。唯一的例外是当您用绘制覆盖整个窗口时,没有像素未被绘制。在这种情况下,您可以避免调用 clear(尽管它不会对性能产生显着影响)。

调用 display 也是必需的,它将自上次调用 display 以来绘制的内容显示在窗口上。实际上,物体并不是直接绘制到窗口上,而是绘制到一个隐藏的缓冲区中。当您调用 display 时,该缓冲区将被复制到窗口上–这称为双缓冲。

这个 clear/draw/display 循环是绘制物体的唯一好方法。不要尝试其他策略,比如保留上一帧的像素,"擦除"像素,或者只绘制一次,然后多次调用 display。由于双缓冲,您会得到奇怪的结果。
现代图形硬件和 API 真的是为重复的 clear/draw/display 循环而设计的,其中每次主循环迭代都会完全刷新所有内容。不要害怕每秒绘制 1000 个精灵 60 次,这远远低于计算机可以处理的数百万个三角形。

我现在可以绘制什么?

现在您已经有了一个准备绘制的主循环,让我们看看可以在其中实际上绘制什么,以及如何绘制。

SFML 提供了四种可绘制实体:其中三种是已准备好使用的(精灵,文本和形状),最后一种是构建块,可帮助您创建自己的可绘制实体(顶点数组)。

尽管它们共享一些共同的属性,但每个实体都具有自己的细微差别,因此在专用教程中进行了解释:

离屏绘制

SFML还提供了一种绘制纹理而不是直接绘制到窗口的方法。为此,使用sf::RenderTexture而不是sf::RenderWindow。它具有相同的绘制函数。继承于共同的基类sf::RenderTarget。

// create a 500x500 render-texture
sf::RenderTexture renderTexture;
if (!renderTexture.create(500, 500))
{
    // error...
}

// drawing uses the same functions
renderTexture.clear();
renderTexture.draw(sprite); // or any other drawable
renderTexture.display();

// get the target texture (where the stuff has been drawn)
const sf::Texture& texture = renderTexture.getTexture();

// draw it to the window
sf::Sprite sprite(texture);
window.draw(sprite);

getTexture函数返回一个只读纹理,这意味着您只能使用它,而不能修改它。如果您需要在使用之前修改它,则可以将其复制到您自己的sf::Texture实例中并修改该实例。

sf::RenderTexture也具有与sf::RenderWindow相同的用于处理视图和OpenGL的功能(有关更多详细信息,请参见相应的教程)。如果您使用OpenGL绘制渲染纹理,则可以使用create函数的第三个可选参数请求创建深度缓冲区。

renderTexture.create(500, 500, true); // enable depth buffer

多线程绘制

SFML支持多线程绘制,您甚至不需要做任何事情就可以让它工作。唯一需要记住的是,在另一个线程中使用窗口之前要停用它。这是因为一个窗口(更精确地说,是其OpenGL上下文)不能同时在多个线程中激活。

void renderingThread(sf::RenderWindow* window)
{
    // activate the window's context
    window->setActive(true);

    // the rendering loop
    while (window->isOpen())
    {
        // draw...

        // end the current frame
        window->display();
    }
}

int main()
{
    // create the window (remember: it's safer to create it in the main thread due to OS limitations)
    sf::RenderWindow window(sf::VideoMode(800, 600), "OpenGL");

    // deactivate its OpenGL context
    window.setActive(false);

    // launch the rendering thread
    sf::Thread thread(&renderingThread, &window);
    thread.launch();

    // the event/logic/whatever loop
    while (window.isOpen())
    {
        ...
    }

    return 0;
}

正如您所看到的,您甚至不需要在渲染线程中繁琐地激活窗口,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、付费专栏及课程。

余额充值