zoukankan      html  css  js  c++  java
  • SDL 开发实战(四): SDL 事件处理

    在前面学习SDL的例子运行时,我们发现我们的窗口只停留了几秒,但是如果设置更长时间显然也有其他的弊端。

    那么有没有一种好的办法可以解决这个问题呢?例如:能不能让窗口一直显示,直到检测到用户用鼠标点击关闭按钮后才关闭呢?

    答:显然可以! 下面就来介绍一下SDL的事件处理机制。

    1. SDL 事件处理机制原理

    SDL事件就是键盘事件,鼠标事件,窗口事件等。SDL将所有事件都存放在一个队列中。所有对事件的操作,其实就是对队列的操作。

    而SDL对这些事件都做了封装,提供了统一的API,下面我们就来详细的看一下。

    2. SDL 操作事件队列的API

    • SDL_PollEvent: 将队列头中的事件抛出来。
    • SDL_WaitEvent: 当队列中有事件时,抛出事件。否则处于阻塞状态,释放 CPU。
    • SDL_WaitEventTimeout: 与SDL_WaitEvent的区别时,当到达超时时间后,退出阻塞状态。
    • SDL_PeekEvent: 从队列中取出事件,但该事件不从队列中删除。
    • SDL_PushEvent: 向队列中插入事件。

    3. SDL 处理事件的API

    • SDL_WindowEvent : Window窗口相关的事件。
    • SDL_KeyboardEvent : 键盘相关的事件。
    • SDL_MouseMotionEvent : 鼠标移动相关的事件。
    • SDL_QuitEvent : 退出事件。
    • SDL_UserEvent : 用户自定义事件。

    实战 

    在上面我们也说过了,如果不做SDL窗口的关闭事件的处理,我们是不能够通过点击关闭按钮,关闭SDL显示的窗口的。这样对用户是非常不友好的。

    下面我们对SDL的Hello World代码做一下优化,其实就是在程序的末尾增加SDL_Event的事件处理,本例做的事情是检测用户是否按下了退出按钮。如果检测到了,则直接退出,否则保持显示状态。

    代码实例:

    // SDL.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //
    
    #include "pch.h"
    #include <iostream>
    
    extern "C" {
    #include "SDL.h"
    }
    
    int main(int argc, char* argv[])
    {
        if (SDL_Init(SDL_INIT_VIDEO)) {
            std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
            return 1;
        }
    
        SDL_Window *win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
    
        if (win == nullptr) {
            std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
            return 1;
        }
    
        SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
        if (ren == nullptr) {
            SDL_DestroyWindow(win);
            std::cout << "SDL_CreateRender Error: " << SDL_GetError() << std::endl;
            SDL_Quit();
            return 1;
        }
    
        std::string imagePath = "1.bmp";
        SDL_Surface *bmp = SDL_LoadBMP(imagePath.c_str());
        if (bmp == nullptr) {
            SDL_DestroyRenderer(ren);
            SDL_DestroyWindow(win);
            std::cout << "SDL_LoadBMP Error: " << SDL_GetError() << std::endl;
            SDL_Quit();
            return 1;
        }
    
        SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, bmp);
    
        SDL_FreeSurface(bmp);
        if (tex == nullptr) {
            SDL_DestroyRenderer(ren);
            SDL_DestroyWindow(win);
            std::cout << "SDL_CreateTextureFromSurface Error: " << SDL_GetError() << std::endl;
            SDL_Quit();
            return 1;
        }
    
        for (int i = 0; i < 3; ++i) {
            SDL_RenderClear(ren);
            SDL_RenderCopy(ren, tex, NULL, NULL);
            SDL_RenderPresent(ren);
            SDL_Delay(1000);
        }
    
        int quit = 1;
        do {
            SDL_Event event;
            SDL_WaitEvent(&event);
            switch (event.type) {
            case SDL_QUIT:
                SDL_Log("Event type is %d", event.type);
                quit = 0;
            default:
                SDL_Log("Event type is %d", event.type);
                break;
            }
        } while (quit);
    
        SDL_DestroyTexture(tex);
        SDL_DestroyRenderer(ren);
        SDL_DestroyWindow(win);
        SDL_Quit();
    
        // Return
        return 0;
    }

    运行效果:

    我们能看到同HelloWorld一样的界面输出,此时如果我们对SDL窗口不做任何处理的话,界面是不会消失的,当我们点击窗口的关闭按钮后,界面关闭了。

    4. SDL_PollEvent 与 SDL_WaitEvent 

    细心的人会发现,使用 SDL_PollEvent 和使用 SDL_WaitEvent 两个方法都能处理SDL的事件队列。如果我们简单的将程序中的SDL_WaitEvent 替换为SDL_PollEvent ,运行时发现也没什么问题。但是当我们打开任务管理器时,发现我们的程序居然跑满了CPU。是什么原因造成的呢?我们来仔细看一下我们增加的代码吧。它由两层 while 循环组成,最里面的while循环的意思是,当队列中一直能取出事件,那就让他一直做下去,直到事件队列为空。外面的while循环的意思是,当队列为空的时候,重新执行内部的while循环。也就是说代码一直在工作,从不休息。所以导致CPU很快就跑满了。 而使用SDL_WaitEvent方法,CPU就不会出现这个问题,因为当它发现队列为空时,它会阻塞在那里,并将CPU占用释放掉。

    SDL_WaitEvent和SDL_PollEvent这两个方法使用的场景不同:

    • 对于游戏来说,它要求事件的实时处理,我们最好使用SDL_PollEvent方法
    • 对于一些其它实时性不高的case来说,则可以使用 SDL_WaitEvent了
  • 相关阅读:
    20180929 北京大学 人工智能实践:Tensorflow笔记02
    20180929 北京大学 人工智能实践:Tensorflow笔记01
    YOLOv3学习笔记
    编辑器上传漏洞
    IIS解析漏洞利用
    数据库备份及审查元素进行webshell上传
    burp suite 进行webshell上传
    BUGKU CFT初学之WEB
    CTFbugku--菜鸟初学
    理解PHP中的会话控制
  • 原文地址:https://www.cnblogs.com/renhui/p/10462137.html
Copyright © 2011-2022 走看看