多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > php教程 > Windows編程 DirectInput 鼠標和鍵盤的輸入

Windows編程 DirectInput 鼠標和鍵盤的輸入

來源:程序員人生   發布時間:2016-09-27 09:00:43 閱讀次數:2904次

版本:VS2015 語言:C++

 

書的第8章是1些數學的知識,和1個圖形庫的創建。數學知識是有必要看1看的,我這里就不做多的介紹了,圖形庫的話反正你現在的win7+系統上也運行不了,看看就好。由于雖然這本書(《Windows游戲編程大師技能》)非常的經典,但是代碼都是比較老的,很多都已過時了不能運行,所以我們要明確我們的目的,學好基礎知識,編寫1下程序練練手,熟習熟習Direct的流程和原理,至于正真的想要應用的話,憑著這些知識學習最新的dx,或直接上引擎,研究引擎中的代碼。

 

好了,說了這么多,其實這本書就是為了入門。

 

今天講的是第9章的內容,主要實現使用鍵盤和鼠標控制。

 

首先是基礎的代碼:

#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0) //判斷當前的按鍵是不是被按下 #define DDRAW_INIT_STRUCT(ddsd) { memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); } #define _RGB32BIT(a, r, g, b) ((b) + (g << 8) + (r << 16) + (a << 24)) HWND main_window_handle = NULL; //當前窗口 LPDIRECTDRAW7 lpdd = NULL; //Direct7對象,下稱d7 LPDIRECTDRAWSURFACE7 lpddsprimary = NULL; //主顯示表面指針 LPDIRECTDRAWSURFACE7 lpddsback = NULL; //后備顯示表面 DDSURFACEDESC2 ddsd; //主顯示表面的描寫 int SCREEN_WIDTH = 640; //顯示寬度 int SCREEN_HEIGHT = 480; //顯示高度 int SCREEN_BPP = 32; //色深,現在的機子只能設置為32位,書上可能還是8位的 int CharPosX = 200; //當前顯示人物的x坐標 int CharPosY = 200; //當前任務顯示的y坐標 // 彈出消息 void popMessage(LPWSTR str) { MessageBox(main_window_handle, str, TEXT("提示"), MB_OK); } // 32位像素上色 void Plot_Pixel_Fast32_2(int x, int y, int red, int green, int blue, int alpha, UINT* video_buffer, int lpitch) { video_buffer[x + y * (lpitch >> 2)] = (UINT)(_RGB32BIT(alpha, red, green, blue)); //使用宏直接寫,有點區分的是lpitch需要除以4,由于lpitch算的是橫向的字節數,而我們把主界面的內存弄成UINT型,是32位、4個字節的,上1節中是我理解的不夠深入 } // 游戲初始化 int Game_Init(void* params = NULL) { // 基礎設置 if (FAILED(DirectDrawCreateEx(NULL, (void**)&lpdd, IID_IDirectDraw7, NULL))) //獲得d7對象 return 0; if (FAILED(lpdd->SetCooperativeLevel(main_window_handle, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT ))) //跟windows協作等級設置為全屏,這是最經常使用的參數 return 0; if (FAILED(lpdd->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 0, 0))) //設置顯示模式,如果設置為8位會直接出錯 return 0; // 開始創建顯示主界面 memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; //表明ddsCaps是個有效成員,并且具有后備的緩沖 ddsd.dwBackBufferCount = 2; //表明有1個緩沖 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | //表明該界面是主界面 DDSCAPS_COMPLEX | //表明具有緩沖鏈 DDSCAPS_FLIP; //表明是反正結構的1部份,上面的參數相當因而有緩沖,而這個參數表明可以切換緩沖 if (FAILED(lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL))) //根據界面描寫創建主界面 { popMessage(TEXT("主表面創建出錯")); return 0; } // 開始創建后備界面 ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; //表明該界面是后備界面 if (FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback))) //通過主界面創建出備用表面 { popMessage(TEXT("創建備用表面出錯了")); return 0; } return 1; } // 游戲結束 int Game_Shutdown(void* params = NULL) { //// 釋放初始化時創建的對象 if (NULL != lpddsprimary) { lpddsprimary->Release(); lpddsprimary = NULL; } if (NULL != lpdd) //d7對象不為空的情況下釋放 { lpdd->Release(); lpdd = NULL; } return 1; } // 游戲主循環 int Game_Main(void* params = NULL) { // 判斷是不是要退出 if (KEYDOWN(VK_ESCAPE)) PostMessage(main_window_handle, WM_CLOSE, 0, 0); // 初始化主界面描寫 DDRAW_INIT_STRUCT(ddsd); if (FAILED(lpddsback->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL))) //有備用表面時用備用表面加鎖 { popMessage(TEXT("LOCK 出錯了")); } // 白色的背景 UINT *video_buffer = (UINT*)ddsd.lpSurface; for (int x = 0; x < 640; ++x) for (int y = 0; y < 480; ++y) Plot_Pixel_Fast32_2(x, y, 255, 255, 255, 128, video_buffer, ddsd.lPitch); //畫人物 //UCHAR *video_buffer = (UCHAR*)ddsd.lpSurface; for (int x = 0+CharPosX; x < 64+CharPosX; ++x) for (int y = 0 + CharPosY; y < 64 + CharPosY; ++y) { if (x<0 || x>SCREEN_WIDTH - 1 || y<0 || y>SCREEN_HEIGHT⑴) //超越屏幕邊沿的時候不畫 continue; Plot_Pixel_Fast32_2(x, y, 0, 255, 0, 128, video_buffer, ddsd.lPitch); } if (FAILED(lpddsback->Unlock(NULL))) //解鎖 { popMessage(TEXT("UNLOCK 出錯了")); } while (FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT))); //切換界面,這邊的while不是很懂,應當每次只會調用1次 return 1; } // 消息處理函數 LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM IParam) { switch (msg) { case WM_DESTROY: PostQuitMessage(0); break; default: DefWindowProc(hwnd, msg, wParam, IParam); //自動處理其他的消息 break; } return (1); } // 主函數,程序入口 int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { // 創建窗口類 WNDCLASSEX wndclass; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; //窗口的樣式:改變寬度刷新、改變高度刷新、分配裝備描寫表、雙擊信息 wndclass.lpfnWndProc = WindowProc; //回調函數 wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //任務欄上的圖標 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //光標的讀取 wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //窗口背景 wndclass.lpszMenuName = NULL; wndclass.lpszClassName = TEXT("MyManyTimesWindow"); //窗口的名字 wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); //利用上的圖標 if (!RegisterClassEx(&wndclass)) return 0; // 創建窗口,上面的窗口類是1個模版,可以根據上面的模版創建多個窗口,但請注意第2個參數 HWND hwnd = CreateWindowEx(NULL,//WS_EX_TOPMOST, //窗口特性,注釋里設置為永久在最上方顯示 TEXT("MyManyTimesWindow"), //窗口名稱,1定要和窗口類的lpszClassName對應 TEXT("我與DDraw已很屢次了"), //標題 WS_POPUP | WS_VISIBLE, //無邊框樣式配合下面的尺寸實現全屏顯示 0, 0, //左上角坐標 SCREEN_WIDTH, SCREEN_HEIGHT, NULL, //父窗口句柄,如果是桌面則為NULL NULL, //菜單窗口句柄 hInstance, //利用程序實例 NULL //高級特性 ); if (!hwnd) //創建失敗返回 return 0; main_window_handle = hwnd; ShowWindow(hwnd, nCmdShow); //顯示窗口 UpdateWindow(hwnd); //刷新窗口 MSG msg; //消息緩存 srand(GetTickCount()); //隨機1個種子 if (0 == Game_Init()) //游戲初始化 return 0; // 進入主循環 while (true) { DWORD start_time = GetTickCount(); //獲得當前時間 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) //有消息事件,注意最后1個參數,如果設置為PM_NOREMOVE的話不會燒毀消息隊列中的消息 { if (msg.message == WM_QUIT) break; TranslateMessage(&msg); //轉譯消息 DispatchMessage(&msg); //將消息發送給WindowProc函數處理 } else //沒有消息 { //游戲主循環 Game_Main(); // 延時期碼,鎖定30幀 while ((GetTickCount() - start_time) < 33); } } Game_Shutdown(); //游戲結束 return msg.wParam; }


注意導入庫文件。嘛,都是之前的知識,復制粘貼過來就好了,效果:


顯示了1個綠色的方型,這就是我們要操控的勇士了。來吧,接下來要到達的效果就是使用wasd,控制左右移動,首先我們加上速度的全局變量(放在角色位置變量的下放):

int CharSpdX = 0; //當前顯示人物x方向的速度 int CharSpdY = 0; //當前顯示人物y方向的速度

然后導入文件input.lib和input8.lib,并包括dinput.h頭文件。

 

在文件的全局處加上宏和變量:

#define DIKEYDOWN(data, n) (data[n] & 0x80) HINSTANCE h_instance = NULL; //當前利用程序的句柄,玩家自己在main函數中設置1下 LPDIRECTINPUT8 lpdi; //輸入對象 LPDIRECTINPUTDEVICE8W lpdikey = NULL; //鍵盤裝備 UCHAR keyboard_state[256]; //鍵盤當前的狀態

初始化函數中添加獲得輸入對象和輸入裝備等的代碼,毛病處理去掉了,玩家自己添加1下:

// 開始創建輸入對象 FAILED(DirectInput8Create(h_instance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&lpdi, NULL)); FAILED(lpdi->CreateDevice(GUID_SysKeyboard, &lpdikey, NULL)); //創建鍵盤裝備FAILED(lpdikey->SetCooperativeLevel(main_window_handle, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)); //設置協作等級,鍵盤和鼠標設置為這里的可以后臺接受和非獨占,而游戲手柄則要設置為獨占 FAILED(lpdikey->SetDataFormat(&c_dfDIKeyboard))); //設置鍵盤的數據格式FAILED(lpdikey->Acquire()); //獲得鍵盤

然后在游戲Shutdown燒毀各個對象:

if (lpdikey) //釋放鍵盤相干對象 lpdikey->Unacquire(); if (lpdikey) lpdikey->Release(); if (lpdi) lpdi->Release();

最后是游戲主循環,哈哈,激動人心的時候到了:

// 獲得鍵盤狀態 if (lpdikey->GetDeviceState(sizeof(UCHAR[256]), (LPVOID)keyboard_state)) { popMessage(TEXT("獲得鍵盤狀態出錯了")); } // 處理按鍵 if (DIKEYDOWN(keyboard_state, DIK_W)) CharSpdY = ⑶; else if (DIKEYDOWN(keyboard_state, DIK_S)) CharSpdY = 3; else CharSpdY = 0; if (DIKEYDOWN(keyboard_state, DIK_D)) CharSpdX = 3; else if (DIKEYDOWN(keyboard_state, DIK_A)) CharSpdX = ⑶; else CharSpdX = 0; // 調劑人物的位置 CharPosX += CharSpdX; CharPosY += CharSpdY;

這段代碼放在刷新白色背景的上面,然后可以試試效果了。我們的勇者是否是可以上下左右移動了?嗯,太棒了!

 

下面是鼠標信息獲得的方法。

 

嗯,首先要說明1下,DirectX中的鼠標跟Windows里的鼠標其實沒有甚么關系,Windows鼠標就是你白色的指針,它就是在屏幕中的某個位置,而dx中鼠標裝備的意思是真實裝備操控時所產生的信息。不是很理解的話,我會在程序中說到這個問題。

 

上代碼(初始化和釋放就不說了,跟鍵盤的方法差不多,換成mouse相干的就OK了):

//全局變量 LPDIRECTINPUTDEVICE8W lpdimouse = NULL; //鼠標裝備 DIMOUSESTATE2 mouse_state; //鼠標的狀態 int MousePosX = 0; //dx計算出來的鼠標位置 int MousePosY = 0; // 這里是游戲主循環里的內容,請放在獲得鍵盤狀態的下面 // 處理鼠標 if (FAILED(lpdimouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mouse_state))) { popMessage(TEXT("獲得鼠標狀態出錯了")); } bool isMouseProccess = false; MousePosX += mouse_state.lX; //計算當前鼠標的位置,取得的參數是當前鼠標位置與上1幀位置的差值 MousePosY += mouse_state.lY; SetCursorPos(MousePosX, MousePosY); //設置Windows中鼠標的位置,如果不設置的話,可能會出現計算出來的位置與當前顯示位置不匹配的情況,1定要記得Windows鼠標的位置和dx中鼠標的位置是隔離的 if (DIKEYDOWN(mouse_state.rgbButtons, 0)) //當鼠標按下的時候,人物瞬移到對應位置 { isMouseProccess = true; CharPosX = MousePosX - 32; CharPosY = MousePosY - 32; }

好了,現在按下鼠標,角色就跟這鼠標移動了,效果是否是很棒啊,哈哈。

 

至于手柄,現在手上也沒有手柄,所以暫時就算了,這類其他的裝備也就是比鼠標鍵盤麻煩了點,思路還是1樣的。

 

下1節會講聲音相干的內容,而講完聲音,dx的內面貌似就是已完了,如果有好玩的話寫1點后面章節的知識,1般般的話就算了,下1節就是最后1節了。



生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 三级欧美在线 | 国产91精品久久久久久 | 亚洲国产精品ⅴa在线观看 亚洲国产精品aaa一区 | 欧美一级片网 | 亚洲免费在线观看视频 | a毛片在线播放 | 日本在线资源 | 久久精品视频一区二区三区 | 最近最新中文字幕高清免费 | 国产欧美久久久精品 | 欧美亚洲高清 | 午夜色综合 | 一级a性色生活片毛片 | 国产在线精品一区二区中文 | 一级做a爱久久久久久久 | 欧美性一区二区三区 | 亚洲在线不卡 | 天天更新天天久久久更新影院 | 亚洲欧美综合国产精品一区 | 亚洲天堂2013 | 一区二区三区免费视频 www | 九色精品在线 | 最近最新中文字幕免费的一页 | 国产亚洲一区二区在线观看 | 吃奶跟添下面特舒服 | 亚洲精品日韩一区二区日本 | 欧美做爰gif动态图一区二区 | 欧美18videosex性孕妇 | 国产成人亚洲精品久久 | 尤物网站永久在线观看 | 欧美性生交xxxxx久久久 | 欧美一区二区三区在线播放 | 欧美交| 国产精品久久久久久久毛片 | 久久福利网 | 三级黄在线播放 | 一二三四视频社区在线中文 | 亚洲一区毛片 | 国产成人十八黄网片 | 图片小说亚洲 | 精品久久久久久中文字幕专区 |