A Simple Input Manager for XNA

來源:互聯網
上載者:User

A Simple Input Manager for XNA

僅供個人學習使用,請勿轉載,勿用於任何商業用途。

(update on 4.28 09: 這篇文章的設計是有bug的,詳細更新可以看這裡)

           Why we need input manager? 在PC平台上,KeyboardState和MouseState提供了基本的使用者輸入資訊,但是對實際編寫遊戲來說,還缺少了幾個關鍵功能。首先,這兩個類只能“拉”出資料,而不能主動“推”資料,也就是說,需要用戶端顯式查詢某個鍵的狀態,而不能當鍵狀態發生改變時通知客戶。其次,IsKeyDown和IsKeyUp返回的值並不是我們所預期的。對於普通的KeyDown事件來說,只在按鍵第一次被按下的時候觸發,比如我們在t1時刻按下按鍵,觸發keydown事件,到t2時刻,即使按鍵仍然處於按下的狀態,也不應該觸發keydown事件。而對於IsKeyDown來說,不論何時,只要按鍵處於按下狀態就一直返回true,IsKeyUp也具有同樣的行為。我習慣把XNA的IsKeyDown成為pressing,而把只在按鍵第一次狀態變化時觸發的事件成為keydown或者keyup。最後,查詢某個鍵被按下了多久,也是很常見的操作。

           基於以上討論,input manager其實只是一個簡單的類,只需要具有以下功能:
1. 同時支援推和拉模型
2. 支援以下事件:KeyDown, KeyUp, KeyPressing, MouseDown, MouseUp, MousePressing, MouseMove, MouseWheel。大部分事件接受一個void GenericEventHandle<T>(T t); 類型的委託
3. 支援查詢某個按鍵被按下的時間

 我們可以馬上寫出Input Manger的介面:

           實現起來也非常簡單,儲存當前和上一次更新時的鍵盤,滑鼠狀態。遊戲主迴圈調用Update,每次更新時次迭代所有鍵,檢查狀態是否有改變,觸發相應的事件。為了支援時間查詢,用一個Dirctionay來記錄每個按鍵被按下的時間。

          這裡有兩點需要注意的地方:首先,迭代更新按鍵狀態不要用foreach + Enum.GetValues(typeof(Keys))的方法來實現。GetValues基於反射,相對來說是比較慢的操作。可以嘗試把所有枚舉值儲存到普通數組裡,迭代數組來遍曆所有按鍵要快的多。另外,記錄每個按鍵時間的Dirctionay不要用Enum做key。使用Enum類型做key,需要進行裝箱。把Enum轉換成int再做為Dirctionay的索引值來使用,就能得到很大的效能提升。

          當然這裡還有一個潛在的問題,應該以多快的頻率來更新輸入狀態呢? 前面提到過,在遊戲主迴圈中調用update(),這意味著對於IsFixedTimeStep為true的XNA遊戲來說,將每秒更新60次;而對IsFixedTimeStep為false的遊戲來說,根據實際情況,每秒更新幾十次或者幾百次都是有可能的。問題是我們需要每秒更新那麼多次嗎?目前鍵盤打字速度的世界記錄是大約每分鐘800次,也就是每秒13次,我沒有找到滑鼠滑鼠鍵按兩下速度的世界記錄,不過自己測試了以下,每秒6~8次點擊已經是極限速度。根據奈奎斯特(Nyquist)採樣定理,只要採樣頻率大於訊號中最高頻率的2倍時,就能完整保留原始訊號中的資訊,也就是說,即使你是世界冠軍,每秒30次更新就足以捕獲你的所有輸入。從上面的類圖中可以看到,我們允許使用者分別設定鍵盤,滑鼠擊鍵的更新頻率和滑鼠移動事件的觸發頻率,因此,update中的代碼可能看起來是這樣的:

  1. public void Update(GameTime gameTime)
  2. {
  3.     float elapsedTime = (float)(gameTime.ElapsedGameTime.TotalSeconds);
  4.     keyboardUpdateCount += elapsedTime;
  5.     mouseButtonUpdateCount += elapsedTime;
  6.     mouseMoveUpdateCount += elapsedTime;
  7.     if (keyboardUpdateCount >= keyboardUpdateInterval)
  8.     {
  9.         //Update keyboard state,fire keyboard event
  10.         keyboardUpdateCount = 0;
  11.     }
  12.     if (mouseButtonUpdateCount >= mouseButtonUpdateInterval)
  13.     {
  14.         //update mouse state,fire mouse event
  15.         mouseButtonUpdateCount = 0;
  16.     }
  17.     if (mouseMoveUpdateCount >= mouseMoveUpdateInterval)
  18.     {
  19.         //update mouse position,fire mouse move event if needed
  20.         mouseMoveUpdateCount = 0;
  21.     }
  22. }

           你可以注意到Input Manager還有一個active屬性。原因是當XNA遊戲失去焦點時,KeyboardState和MouseState仍然能捕獲到使用者輸入,對大多數遊戲來數,這顯然是不必要的,所以當遊戲失去焦點時,我們將把Input Manager的active屬性設定為false,停止更新輸入。

接下來的工作
         

 

 最後要說的是,KeyboardState返回的所有鍵盤訊息,都是Keys枚舉的一個值,如果你想編寫文字框,允許使用者輸入,必須把各個枚舉值轉換為相應的字元。詳細的實現也許非常複雜,你要考慮shift按下或者Caps Lock是否開啟; 又或者你希望把每個鍵盤訊息映射為遊戲內的某個訊息,等等。那麼也許就需要在input manage之上,再建立一個InputMessageTranslator之類的東西了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.