用C++和SFML写游戏-事件的处理(4)

处理好来自用户的事件是一个很重要的话题。

首先我们来认识一下什么是事件

一般来说,事件是在某些情况下被触发的对象。它们依赖于操作系统,但是 SFML 为我们提供了一个很好的对象来处理事件,它是独立于操作系统的方式。sf::Event 类,这个类包含了各种事件。

建议阅读 SFML 官方文档去好好了解 SFML 事件的类型,地址是https://www.sfml-dev.org/tutorials/2.5/window-events.php。 注意 sf::Event 是一个联合体(union),使用的时候要恰当的选择我们需要的事件类型。

逻辑上,我们可以将事件分成四种类型:

  • 窗口
  • 键盘
  • 鼠标
  • 手柄

一、窗口事件

类型相关成员描述
Event::ClosedNone当操作系统检测单用户想要关闭窗口时触发
Event::ResizedEvent::size 表示新窗口的大小当操作系统检测单用户想要改变窗口大小时触发,或者调用Window::setSize()
Event::LostFocus Event::GainedFocusNone当窗口失去/得到焦点时触发,失去焦点的窗口不会收到键盘事件

二、键盘事件

类型相关成员描述
Event::KeyPressed Event::KeyReleasedEvent::key 表示的事当前按住/松开的按键在得到焦点的窗口中,当一个按钮被按下或者松开的时候触发
Event::TextEnteredEvent::text 表示的是一个字符的UTF-32 unicode任何时候一个字符输入的时候触发

三、鼠标事件

类型相关成员描述
Event::MouseMovedEvent::mouseMove 表示鼠标新位置当鼠标在窗口内移动时触发
Event::MouseButtonPressed Event::MouseButtonReleasedEvent::mouseButton 表示的是按下/松开的鼠标按钮以及它的位置当鼠标上的按钮按下/松开的时候触发。目前支持5种类型的按钮:左、中、右、额外的按钮1和按钮2
Event::MouseWheelMovedEvent::mouseWheel 表示的是滚轮以及鼠标位置当鼠标上的滚轮滚动时触发

四、手柄事件

类型相关成员描述
Event::JoystickConnected Event::JoystickDisconnectedEvent::joystickConnect 表示的是手柄连接/断开连接时的ID当手柄连接或者断开连接时触发
Event::JoystickButtonPressed Event::JoystickButtonReleasedEvent::joystickButton 表示的是手柄上按钮按下的数量以及手柄ID当手柄上的按钮按下时触发,SFML为我们提供了最多8个手柄,每个手柄32个按钮的支持
Event::JoystickMovedEvent::joystickMove 表示的是移动操纵杆的轴,操纵杆轴的位置以及手柄ID移动操纵杆的轴时会触发此操作

对于窗口事件来说,我们通常用 bool Window::pollEvent(sf::Event& event) 函数,如果有事件将要被使用的话,函数会返回 trueevent参数会对应某个具体事件。需要注意的是,同一时间下可能会有多个事件需要被处理,因此我们需要确保捕获到每一个事件。代码如下:

while (window.isOpen()) {
    sf::Event event;
    while (window.pollEvent(event)) {
        
    }
    
    // 刷新帧
    // 绘制帧
}

运行上面这份代码之后,我们可以做出移动窗口,改变窗口大小或者是最小化窗口这些操作,但是有一个问题,那就是我们无法关闭窗口。当我们点击窗口的关闭按钮时,SFML 不会去关闭窗口,这一操作需要我们去实现。

五、 事件的使用

通过 Window::pollEvent() 捕获事件之后,我们可以通过 Event::type 检查事件类型。事件类型是 Event::EventTyp,它是 Event 类中的一个枚举类型。使用方法如下

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

调用 Window::close() 可以关闭窗口。

如果我们想要使用更多的事件,我们的可以使用 switch 语法。如下:

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");
            // 当 Esc 键松开的时候关闭窗口
            else if (event.key.code == sf::Keyboard::Key::Escape)
                window.close();
            break;
        default:
            break;
    }
}

上面这份代码的意思很容易理解,通过空格键可以改变窗口的标题,松开 Esc 键时关闭窗口。注意到 Event::key 包含了 code 成员,它是 Keyboard::Key 类型中的一个枚举类型。用上面这种方法可以处理其他事件类型。

然而,Event::EventType::TextEntered的使用有点意思。按键被按下/松开的时候可以被检测到且可以使用一种相对简单的方式去处理。但是当键入一些特殊字符的时候,事情变得有点复杂起来。例如,输入 ! 号的时候在大多数键盘中是使用 shift+1的。幸好 SFML 为我们提供了一个简单的方式去处理,仅当按下表示字符的组合键时才会发生事件,这意味着按下一个键(例如 shift)时不会触发事件。

下面这个例子使用了 TextEntered 事件组合了一个字符串,然后按下 Enter 键时这个字符串会显示在窗口标题中。

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;
        }
    }
}

这里使用 sf::String 类型能够避免不同语言之间的字符编码转换。

代码已上传到 [Github](https://github.com/sshpark/LearnSFML/tree/master/blog4) 这一节简单介绍了 **SFML** 中的事件处理,下一节将会学习纹理以及精灵(sprite)的简单使用。?
使用C++SFML库来编2048小游戏是一个不错的实践项目,可以帮助你熟悉C++编程和SFML图形库的使用。SFML(Simple and Fast Multimedia Library)是一个简单易用的多媒体库,可以用来处理音频、视频、窗口等多媒体元素,非常适合用来开发小游戏。以下是使用C++SFML2048游戏的基本步骤和概念: 1. **安装SFML库**:首先需要在你的开发环境中安装SFML库。你可以从SFML的官方网站下载并按照指南进行安装。 2. **创建游戏窗口**:使用SFML创建一个窗口,这是游戏运行的基础。你可以设置窗口的大小、标题等属性。 3. **处理用户输入**:2048游戏需要响应用户的键盘输入,例如上下左右箭头键来移动方块。你需要捕捉这些键盘事件,并根据用户的操作更新游戏状态。 4. **游戏逻辑实现**:编核心游戏逻辑,包括初始化游戏板、随机生成新的数字方块、处理方块的移动和合并规则等。 5. **渲染游戏界面**:使用SFML的图形渲染功能来绘制游戏界面,包括数字方块、分数显示等。 6. **游戏循环**:游戏循环是游戏运行的核心,它负责不断地处理用户输入、更新游戏状态和渲染游戏画面。 7. **结束条件检测**:在游戏逻辑中加入检测游戏是否结束的条件,如无法移动或达到2048的数字。 以下是实现2048游戏的简化示例代码结构: ```cpp #include <SFML/Graphics.hpp> int main() { // 创建游戏窗口 sf::RenderWindow window(sf::VideoMode(400, 400), "2048 Game"); // 游戏状态初始化 // ... // 游戏主循环 while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); // 处理键盘输入 // ... } // 更新游戏逻辑 // ... // 渲染游戏界面 window.clear(); // 绘制游戏元素 // ... window.display(); } return 0; } ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值