在计算机科学领域,隐喻无处不见。所有的抽象概念,若不是被很好的用形象概念或者已经被理解的抽象概念去解释,其本身很难让人们明白是什么。事件,在这里指的就是计算机所直接感知到的玩家对于其的作用。比如你按下某个键,又松开,移动了鼠标等等。所有的这些行为都被称为事件。在计算机看来,任何事件的发生都是有先后的(如果你了解相对论,你就会知道其实世界上任意两点间并不存在“同时”的概念)。如果计算机工作效率很低,这些事件就会排着队列等待接受处理——这里又用到一个模型的隐喻——队列(queue),这是计算机算法与数据结构知识中很重要的概念,往往意味着其特征是“先进先出”。
我们就从这个事件队列(event queue)的模型去思考吧。要知道,队列是有可能为空的,这就如同银行的服务窗口前面不会总是有人排队一样——当然,我假设你不是总呆在北京,也去过一些小城市^^,那么,没有客户在窗口前需要被服务的时候,这个窗口的工作人员应该是什么状态呢?至少有两种不同的等待方式:一种是什么也不做傻等;一种是边喝点茶看看报纸算算账什么的其他事情边等待。对于计算机来说,第一种停下来等,就是wait;第二种继续做其他事情的同时等,就是poll。前者一看就明白,后者被不知道某位前辈高人翻译成“轮询”,好吧,说句实话,我笨,光看“轮询”这个词,完全无法理解是什么意思-_-!!!
SDL为我们提供了两种等待事件的方式:
int SDL_WaitEvent(SDL_Event *event);
int SDL_PollEvent(SDL_Event *event);
两个函数的返回值都是int,形参是SDL事件结构(C++里面,就把结构看成类吧。)指针SDL_Event*(请注意我把SDL_Event和*连着写,这意味着在认识上,我把SDL_Event*本身看成一种复合类类型。)我们知道,在C/C++里面,函数至少有三种基本功能。1、像命令似的起了某种作用;2、通过计算得到我们需要的返回值;3、指针(C++里面的引用)参数也可以传值。这里,我们先忽略SDL_Event结构的构造,看看这两个函数的作用。首先,他们不会引起某种作用;其次,他们的返回值是1或者0;最后,他们会通过指针参数传值,这是重点。
早期的C里面,是没有关键字true和false的。通常用1代表true,0代表false。我个人觉得,在SDL里面,1和0的概念最容易与-1和0的概念混淆。我们在学习SDL_Init的时候,说到返回值0代表成功,-1代表失败。其实细细想,还是有差别的。0和1是计算机固有的数据表示方式,而-1是计算机原始方式所无法理解的,所以会代表着异常。所以,在异常退出的时候,我选择使用return -1。
这两个函数的返回值,在等到了事件的时候,返回1,否则返回0。官方文档里面用类似while(SDL_PollEvent(&event))的方法引导轮询机制的开始,但是我觉得,对于新手来说,这样的表述不是很直观。与其间接的问窗口的服务员有客户来吗,还不如自己直接看看有没客户(event queue是不是为空)。所以,在后面的例子里面,我实际上用的是if ( &event != 0 )。
1.3:当前窗口。
如果你有兴趣研究SDL的官方文档,看到事件介绍(Introduction to Events)部分,也许会对以下问题感觉到奇怪:SDL的事件查询机制是与SDL_INIT_VIDEO同时装载的。为什么呢?
我们知道,我们开发的游戏实际上是运行在操作系统的平台上的。当前的操作系统,都是多任务的操作系统。具体说到GUI,有个很重要的概念就是你目前操作的是哪个程序,也就是更形象的概念——当前窗口。有些event可能是各个窗口,甚至包括系统本身共享的,比如鼠标移动(这不是绝对的,只是有可能);有些event只会被当前窗口接受,就如同你不会希望同时开着两个Word文件在编辑,修改一个文件的时候,另外一个也被无情的修改了。所以,SDL程序运行的时候,只有指定了哪个窗口是这个程序的窗口,并且这个窗口是当前窗口的时候,大部分event才能被正确的响应。
注意,console窗口不是SDL程序的运行窗口,它属于操作系统本身。我们要打开SDL的程序窗口,需要引入一个新函数:
SDL_Surface *SDL_SetVideoMode(int width, int height, int bitsperpixel, Uint32 flags);
我们这里仅仅是为了打开SDL的程序窗口来引入这个函数,只做个简单介绍:1、这个函数本身有作用——打开SDL程序窗口;2、前三个参数分别是这个打开窗口的宽,高和位深,最后那个flags我们这里只介绍SDL_SWSURFACE,这个位标表示把返回值的数据建立在系统内存里面。