《第一章》SFML 入门

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34536551/article/details/84141509

创建窗口


创建窗口的只需要一行代码:

#include <SFML/Graphics.hpp>

int main()
{
    sf::Window window(sf::VideoMode(200, 200), "HUANGCHENGTAO!");  //创建窗口代码
    sf::sleep(sf::seconds(3)); //添加此代码 这样我们就可以创建窗口之后,运行代码可以看到窗口,否则不可以
  
    return 0;
}

● main函数唯一做的是通过调用sf :: Window构造函数初始化窗口变量,之后程序退出。 还有一种方法可以使用默认构造函数打开一个窗口,然后调用Window :: create()。 这个函数的参数与构造函数完全相同,我们刚刚讲过。 如果在已经打开的窗口上调 Window :: create(),它将关闭窗口并使用新的参数集重新初始化它 。

● 请注意 Window 和VideoMode 都在sf命名空间中。 SFML中的每个类都在该命名空间下,该命名空间将SFML中的所有类与其他库中的类分开。

● 我们可以在创建窗口时,窗口的大小、标题、样式和图形设置时指定各种配置。您可能已经注意到我们将两个参数传递 给 Window构造函数 - 一个VideoMode实例和一个字符串(标题)。 构造函数实际上最多可以使用四个参数,最后两个是可选的 -  Style和ContextSettings。


VideoMode
 


●  VideoMode类包含显示一个窗口的信息,例如宽度、高度和每个像素的比特数。最后一个参数是表示单个像素颜色的位数。它的默认值为32,如果我们想要创建一个全屏窗口,所提供的值必须由机器的显示器和显卡支持。如果我们为全屏窗口选择无效的参数,窗口创建将会失败的。可以使用 VideoMode::isValid()  方法检 查VideoMode   类的有效性,结果返回一个布尔值。

●  如果我们需要根据PC端桌面版的大小(或像素深度)创建窗口,VideoMode::getDesktopMode()是一个静态方法。另一方面,如果我们要在全屏模式下创建一个窗口,我们可能需要使用  VideoMode::getFullScreenModes() 检查可用的分辨率。这将返回显示模式的std::vector,我们可以自己选择其中一种模式,或者让用户决定哪种模式最适合他们。

然而,仅仅指定全屏视频模式还不足以创建全屏窗口。我们也需要设定一个窗口的样式。


Style
 


●  Style参数是一个位掩码。掩码是标志的组合,其中每个标志代表掩码的一个特定位。在本例中flags存储在 sf::Style 名称空间中的enum中。我们可以使用flags 的组合来创建所需的标志掩码。以下是SFML提供的风格:

Enum value 描述
sf::Style ::None 这个窗户没有任何装饰,也不能与任何其他风格相结合
sf::Style ::Titlebar 添加一个标题栏
sf::Style ::Resize 这增加了一个最大化按钮。还允许手动调整窗口的大小
sf::Style ::Close 添加一个关闭按钮
sf::Style ::Fullscreen 这将以全屏模式打开窗口。注意,这不能与任何其他样式组合,需要有效的显示模式。
sf::Style ::Default 这将标题栏、大小调整和关闭组合在一起。这是默认样式。

可以通过使用位运算符来组合不同的样式。如果我们想要一个带有标题栏和关闭按钮的窗口,我们可以这样写:

sf::Uint32 style = sf::Style::Titlebar | sf::Style::Close;

这里要做的唯一一件事就是将该样式作为Window构造函数的第三个参数传递。


ContextSettings
 


● 最后一个参数是ContextSettings的一个实例。 此结构是一组设置的集合,描述了所需的渲染上下文。 SFML使用OpenGL进行渲染,因此这些设置与它直接相关。 可用的上下文设置如下:

depthBits ——这指的是深度缓冲区位数。

stencilBits —— 这指的是模板缓冲区的位数。

antialiasingLevel: —— This refers to the requested number of multisampling levels

majorVersion and minorVersion: —— 这些是指所要求的OpenGL版本

这些设置中的每一个都将在第5章(操作2D摄像机)中得到更详细的解释,您将学习如何使用OpenGL直接渲染物体。


Disabling the mouse cursor (禁用鼠标光标)
 


●  Window类有一个方法,可以在窗口上设置光标的可见性 —— Window :: setMouseCursorVisible()。 对于不使用光标的游戏,或者当我们想要将光标的图像更改为与默认情况不同的内容时,这是非常有用的。


The game loop 


下面是一个典型的游戏循环:

#include <SFML/Graphics.hpp>

int main()
{
  
    sf::RenderWindow window(sf::VideoMode(200, 200), "HUANGCHENGTAO!");  //创建窗口代码
    sf::sleep(sf::seconds(3)); //这样我们就可以创建窗口之后,运行代码可以看到窗口,否则不可以
    while (window.isOpen()) //游戏循环
    {
        /*
        处理输入——处理来自输入设备和窗口的事件。
        更新框架——更新场景中的对象
        渲染框架 —— 将场景中的对象渲染到窗口上
         */
    }
  
    return 0;
}

典型的游戏循环有三个主要阶段:

        处理输入——处理来自输入设备和窗口的事件。
        更新框架——更新场景中的对象
        渲染框架 —— 将场景中的对象渲染到窗口上

SFML中的输入处理可以通过捕获事件(由窗口分配)或直接查询输入设备的当前状态来完成。这两种方法有不同的用途。例如,我们可能想关闭按钮按下事件上的窗口,或者只要按下某个键,我们的主角就会向右移动。

● 在捕获和使用事件后,我们到达更新框架阶段。在这个阶段,我们想要推进我们的游戏逻辑,更新我们的世界状态

●在我们完成对象更新后,循环的最后阶段就会出现。 在这里,我们清除从上次绘制的所有内容,并再次渲染屏幕上的每个对象。


Event handling (处理事件)
 


可以通过  bool Window :: pollEvent(sf :: Event&event) 从窗口查询事件。 如果有一个事件等待处理,该函数将返回true,并且事件变量将被事件数据填充。 如果不是,则该函数返回false。 同样重要的是要注意,一次可能有多个事件;因此我们必须确保捕获每个可能的事件。 以下是典型的事件循环:

  while (window.isOpen()) //游戏循环
    {
        sf::Event event;
        while (window.pollEvent(event))
        {

        }
    }

请务必注意C ++中的Event类包含一个union。 这意味着其中只有一个有效成员。 访问任何其他成员将导致未定义的行为。 我们可以通过查看事件类型来获取有效成员。

事件类型在逻辑上可以分为四个部分,具体取决于它们与什么有关:

  • Window
  • Keyboard
  • Mouse
  • Joystick

Window related events


Enum value Member associated Description
Event::Closed None 当操作系统检测到用户想要关闭窗口时触发此事件——关闭按钮、组合键等等。
Event::Resized Event::size holds the new size
of the window
当操作系统检测到窗口已手动调整大小或已使用Window :: setSize()时,将触发此事件。

Event::LostFocus


Event::GainedFocus

None This event is triggered when the window loses or gains focus. Windows which are out of focus don't receive keyboard events.

Keyboard related events


Enum value Member associated Description

Event::KeyPressed


Event::KeyReleased

Event :: key保存 按下/松开 的键 当按下或松开焦点窗口上的单个按钮时,将触发此事件。
Event::TextEntered Event :: text保存 UTF-32 unicode 的字符值 每次输入字符时都会触发此事件。这将从用户输入中生成可打印的字符,对于文本字段非常有用。

 


Mouse related events
 


Enum value Member associated Description

Event::MouseMoved

Event::mouseMove holds the new mouse position 当鼠标在窗口内更改其位置时会触发此事件。

Event::MouseButtonPressed


Event::MouseButtonReleased

Event::mouseButton   holds the pressed / released button and the mouse position 在窗口内按下鼠标按钮时会触发此事件。 目前支持五个按钮 - 左,右,中,其它按钮1和其它按钮2。
Event::MouseWheelMoved Event::mouseWheel  保存了鼠标的滚轮移动了多少时间以及鼠标位置 当滚动轮在窗口内移动时触发此事件

joystick related events
 


Enum value Member associated Description

Event::JoystickConnected


Event::JoystickDisconnected

Event :: joystickConnect 保存刚才连接 / 断开的操纵杆的ID 当操纵杆连接或断开时触发此事件。

Event::JoystickButtonPressed


Event::JoystickButtonReleased

Event :: joystickButton 保存按下的按钮次数和操纵杆ID 按下操纵杆上的按钮时会触发此操作。 SFML最多支持8个操纵杆,每个操纵杆最多32个按钮。
Event::JoystickMoved Event :: joystickMove保存移动的坐轴,新的坐标轴位置和操纵杆ID
当操纵杆的轴线移动时触发。可以通过Window::setJoystick threshold()设置移动阈值。SFML最多支持8个轴

Using events
 


通过调用Window :: pollEvent()获取事件后,我们可以通过查看Event :: type来检查它的类型。 该事件的类型为Event :: EventType,它是Event类中的枚举。 以下是典型的关闭事件的实现方式:

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

这里,Window :: close()函数将负责关闭窗口。 如果窗口变量超出范围,则调用析构函数,并且关闭窗口。

 

如果我们想处理多个事件,那么使用Switch语句是有意义的,因为它提高了可读性。让我们看看键盘键是如何按下和释放的:

#include <SFML/Graphics.hpp>
int main()
{
   
    sf::RenderWindow window(sf::VideoMode(200, 200), "HUANGCHENGTAO!");  //创建窗口代码
    sf::sleep(sf::seconds(3)); //这样我们就可以创建窗口之后,运行代码可以看到窗口,否则不可以
    sf::CircleShape shape(100.f); //创建图形对象
    shape.setFillColor(sf::Color::Red); //改shape的填充颜色
    while (window.isOpen()) //游戏循环
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::EventType::Closed:
                window.close();
                break;
            case sf::Event::EventType::KeyPressed:
                //如果按下空格键,请更改标题
                if (event.key.code == sf::Keyboard::Key::Space) //键盘按下事件
                {
                    window.setTitle("Space pressed");
                }
                break;

            case sf::Event::EventType::KeyReleased:  //键盘松开事件
                //如果空格键又被松开,则改变标题
                if (event.key.code == sf::Keyboard::Key::Space)
                {
                    window.setTitle("Space released");
                }//如果松开了Escape键,则关闭窗口
                else if (event.key.code == sf::Keyboard::Key::Escape)
                {
                    window.close();
                }
                break;
            default:
                break;
            }
        }
        window.clear();
        window.draw(shape);
        window.display();
    }
  
    return 0;
}

上面的代码演示了如何捕获事件,以便在每次按下和松开空格键时更改窗口的标题。除此之外,当Escape键被松开时,窗口就会关闭。

Event :: key包含一个名为code的成员,code是Keyboard :: Key类型的枚举。

但是,Event :: EventType :: TextEntered 更好。 可以以相对简单的方式检测和处理单键被按下 和 松开。

但是,当涉及到特定的字符时,事情开始变得有点复杂。例如,如果我们想检测时!符号已经输入,我们必须查看是否同时按下了两个单独的键。

在这种情况下,SFML通过提供简单易用的TextEntered事件为我们节省了大量工作。 仅当按下表示字符的键组合时才会触发该事件; 意味着单个键(例如,只有Shift)可能不会触发事件。 当然,如果单独按下K,事件将被正常触发,并将包含该字符。


查看这个示例,其中使用 TextEntered 事件将使用的字符串是由字符组装而成的,当按下Enter(或Reach)按钮时,文本设置为标题:

 sf::String buffer;
    while (window.isOpen()) //游戏循环
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::EventType::Closed:
                window.close();
                break;
            case sf::Event::EventType::TextEntered:
               //将字符直接添加到字符串中
                buffer += event.text.unicode;
                break;

            case sf::Event::EventType::KeyReleased: 
               //将标题更改为当前缓冲区并清除缓冲区
                if (event.key.code == sf::Keyboard::Key::Return)
                {
                    window.setTitle(buffer);
                    buffer.clear();
                }
                break;
            default:
                break;
            }
        }
       
    }
    return 0;

注意,我们使用的字符串缓冲区的类型是sf:string,而不是std:string。创建sf:string类是为了自动处理字符串类型和编码之间的转换。


 

猜你喜欢

转载自blog.csdn.net/qq_34536551/article/details/84141509