SDL游戏开发教程03(消息循环和键盘事件响应)

阅读更多

    对于窗口程序来说,消息循环和事件响应是非常重要的,这节将介绍如何利用SDL提供的API函数实现消息循环和键盘ESC键响应。
将上节中的这部分代码注释掉:

//if( SDL_Flip( screen ) == -1 )
//{
//	return 1;
//}
//SDL_Delay( 2000 );

 

    上面的代码主要是将内存中的内容显示到屏幕上,然后等待两秒,让用户有机会看到图片。

 

    下面要将这部分带代码替换成一个消息循环,让程序可以响应用户消息,代码如下:

 

bool bQuit = false;		//程序是否退出的标志
SDL_Event event;
while(!bQuit)			//如果bQuit不为true的话,循环一直进行
{
	//从消息循环中尝试取出一个消息,如果有的话返回ture,否则返回false
	//SDL_PollEvent不会等待,而是立刻返回
	while( SDL_PollEvent( &event ) )
	{
		switch(event.type)		//处理取到的消息,判断消息类型
		{
		case SDL_KEYDOWN:		//如果是键盘按下事件
			if(event.key.keysym.sym == SDLK_ESCAPE)	//如果按的是ESC键
			{
				bQuit = true;						//退出循环
			}
			break;
		case SDL_QUIT:			//如果是窗口关闭事件,例如点击窗口的关闭按钮
			bQuit = true;							//退出循环
			break;
		default:
			break;
		}
	}

	//将内存中的内容显示到屏幕上,该函数每调用一次就会更新一次窗口的内容,即游戏中的一帧
	//由于在这个循环中我们没有修改内存中的内容,所以屏幕窗口中显示的内容不会发生变化
	if( SDL_Flip( screen ) == -1 )
	{
		break;
	}
}

    学过windwos API编程的人一定对上面的这段代码非常熟悉,因为它和windows的消息循环机制很相似,对于windows的消息循环来说我们一般这样写:

MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
	TranslateMessage(&msg);
	DispatchMessage(&msg);
}

     在这里windows和SDL消息循环的区别在于GetMessage在消息队列中没有消息的情况下会等待,直到有消息为止;而SDL_PollEvent是不管有没有消息都马上返回。

    其实在windows api中也有与SDL的SDL_PollEvent对应的函数,那就是PeekMessage。同样在SDL中也有与GetMessage对于的SDL_WaitEvent函数。

 

    在这里,我们为什么用SDL_PollEvent而不用SDL_WaitEvent?是因为SDL_WaitEvent在没有用户消息的时候会造成程序等待,从而影响到游戏的帧数,这样在有动画的游戏中,就会出现用户不操作的时候界面停止,当用户再次操作时,界面发生跳跃的情况。试想玩俄罗斯方块的时候,你操作一下它就动一下,你不操作他就不动;或者刚刚方块还在上面,你等了一下没操作键盘,等你再操作键盘的时候,方块已经到下面了,这个是因为方块的下落一般是在定时器中处理的,是后台处理,没有用户消息的时候,后台的定时器还在运行,但界面没有和后台同步,从而造成画面跳跃前进的状况。

 

    对于消息处理来说,SDL还提供了一些函数,由于我们暂时对消息处理没有进一步更深的需求,所以在这里不详细介绍,等用到的时候再说。如果你想了解一下的话,可以阅读SDL的文档。

 

    下面分析SDL_Event的结构:

typedef union SDL_Event 
{
	Uint8 type;					//消息类型
	SDL_ActiveEvent active;		//窗口焦点、输入焦点及鼠标焦点的失去和得到消息
	SDL_KeyboardEvent key;		//键盘消息,键盘按下和释放
	SDL_MouseMotionEvent motion;//鼠标移动消息
	SDL_MouseButtonEvent button;//鼠标按键消息
	SDL_JoyAxisEvent jaxis;		//手柄消息
	SDL_JoyBallEvent jball; 	//手柄消息
	SDL_JoyHatEvent jhat; 		//手柄消息
	SDL_JoyButtonEvent jbutton; //手柄消息
	SDL_ResizeEvent resize;		//窗口大小变化事件
	SDL_ExposeEvent expose;		//窗口重绘消息
	SDL_QuitEvent quit;			//退出消息
	SDL_UserEvent user;			//用户自定义事件
	SDL_SysWMEvent syswm;		//平台相关的系统消息
} SDL_Event;

     SDL_Event是一个联合体,type字段决定了其中的哪个结构体数据有效。
    本节中只用到了键盘消息,所以这里主要介绍键盘消息,如果后面用到了其他消息,将做详细解释。SDL_KeyboardEvent定义:

typedef struct
{
  Uint8 type;			//消息类型,SDL_KEYDOWN/UP


  Uint8 state;			//键盘状态,表示按下还是释放,在这里和type字段代表的意义相同
  SDL_keysym keysym;	//具体的按键信息
} SDL_KeyboardEvent;

     这里是键盘消息结构体的定义,type表示类型,由于SDL_Event是联合体,所以SDL_KeyboardEvent中的type等于SDL_Event中的type字段。下面看SDL_keysym:

typedef struct
{
  Uint8 scancode;	//按键对应的硬件扫描码
  SDLKey sym;		//按键对应的SDL枚举定义,SDL定义的键盘键以SDLK_开头(如SDLK_DELETE表示删除键)
  SDLMod mod;		//哪个辅助键被按下,辅助键指ALT,SHIFT之类的键
  Uint16 unicode;	//输入对应的unicode编码(需要调用SDL_EnableUNICODE开启unicode,SDL默认不开启)
} SDL_keysym;

    其中scancode 暂时用不着,判断哪个键被按下一般都是用sym ,SDLKey和SDLMod都是SDL定义的枚举,在头文件SDL_keysym.h中。具体的可参考SDL文档或者源代码。

 

     到这里为止,我们可以在窗口中显示一张图片,并且可以移动和关闭窗口了,在这过程中用到的函数的具体相关细节,需要大家自己去尝试,去了解,这里只是介绍了一些常用的功能。下一节中将介绍如何用C++将这些代码封装起来。

你可能感兴趣的:(游戏,Windows,编程,数据结构,UP)