0%

SDL事件处理

前面我为大家介绍了 SDL 的三个主题:

今天我为大家介绍一下SDL的事件处理。这里所指的事件处理就是我们通常所说的,键盘事件,鼠标事件,窗口事件等。

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

SDL中的事件处理

要想了解 SDL 的事件处理,我们必须要知道的一个原理是,SDL将所有事件都存放在一个队列中。所有对事件的操作,其实就是对队列的操作。了解了这个原理后,我们再来说SDL提供的 API 就很容易理解了。

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

SDL只提供了这样几个简单的API,下面们来介绍几个常见的事件:

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

关于事件更加详的信息可以到 SDL Wiki 上进行查询。现在我们来看一个使用的例子吧。

例子

在我们之前文章的例子中,大家已经发现一个问题,那就是窗口只显示了 3 秒钟,之后就自动消失了。

有的同学可以会通过修改代码最后面的 SDL_Delay 函数,增加它的等待时间让窗口多活一段时间。

但这样的体验实在是太糟糕了。有没有一种好的办法可以解决这个问题呢?能不能窗口一直显示,直到检测到用户按了ctrl+c 或 使用鼠标点击关闭按钮后才关闭呢?

当然是可以的。我们只需要在之前的程序的末尾增加下面这段代码即可。它会一直检测用户是否按下了退出按钮。如果检测到了,则直接退出,否则保持显示状态。

1
2
3
4
5
6
7
8
9
10
11
12
while(!quit){
SDL_Event event;
while(SDL_PollEvent(&event)){
switch(event.type){
case SDL_QUIT:
quit = 1;
break;
default:
SDL_Log(".");
}
}
}

SDL_PollEvent 与 SDL_WaitEvent

增加了上面的代码,我们的实验程序似乎也显的很正规了。但有一个问题不知你发现没有
?当我们打开任务管理器时,发现我们的程序居然占了 100% 的 CPU。My GOD!这个的结果是决对不能接受的。

是什么原因造成的呢?我们来仔细看一下我们增加的代码吧。它由两层 while 循环组成,最里面的while循环的意思是,当队列中一直能取出事件,那就让他一直做下去,直到事件队列为空。外面的while循环的意思是,当队列为空的时候,重新执行内部的while循环。

也就是说,这段代码一直在工作,从不休息。所以导致cpu占到了100%。即然找到了问题的原因,我们就好处理了,只要在外层循环的最后 delay一下,让CPU休息一下就好了。

当然,SDL还为我们提供了 SDL_WaitEvent方法,使用这个API,你的CPU就不会跑到 100%了,因为当它发现队列为空时,它会阻塞在那里,并将CPU释放掉。

即然有 SDL_WaitEvent了,为什么还要有SDL_PollEvent呢?这主要是由于使用的场景不同。对于游戏来说,它要求事件的实时处理; 而对于一些其它实时性不高的case来说,则可以使用 SDL_WaitEvent了。

小结

到此,本文的内容就介绍完了。在本文中主要介绍了SDL是如何处理事件的,SDL为我们提供了非常简单的API,这大大减少了我们的开发成本。

另外,我在文章的最后,介绍了SDL_PollEvent 与 SDL_WaitEvent两个 API的区别。这也是使用 SDL 事件处理中最容易引起困惑的地方。

希望本文能对您有所帮助,谢谢!

推荐阅读:

欢迎关注我的其它发布渠道