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++將這些代碼封裝起來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章