XNA キー押下検知
前回の
XNA ことはじめ
http://d.hatena.ne.jp/levin_gsp/20071212/1197440515
に続いて、XNA/C# で勝手に一人で盛り上がっていく。
今回は XNA におけるキーボード入力の検知を題材として取り上げる。
ソースコードレベルで手元にあるのは Spacewar Project と Empty Project (共にWin版)のみ。
ここから自力で解析しつつ、考察しつつ、色々試してみたい。
まず、Spacewar を少しプレイしてみると、“およ?”という印象の一つにキー操作がある。
XBOX360 を想定したキー配列になっているのだが、その設定がどこにあるのか。
探してみると、まずこんなのが見つかった。
Debug ビルドした後であれば、Debug フォルダ(Releaseも同様)の下に settings.xml がある。
<?xml version="1.0"?> <Settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <MediaPath>content\</MediaPath> <WindowTitle>Spacewar</WindowTitle> 〜中略〜 <Player1Start>LeftControl</Player1Start> <Player1Back>LeftShift</Player1Back> <Player1A>V</Player1A> <Player1B>G</Player1B> <Player1X>F</Player1X> <Player1Y>T</Player1Y> <Player1ThumbstickLeftXmin>A</Player1ThumbstickLeftXmin> <Player1ThumbstickLeftXmax>D</Player1ThumbstickLeftXmax> <Player1ThumbstickLeftYmin>S</Player1ThumbstickLeftYmin> <Player1ThumbstickLeftYmax>W</Player1ThumbstickLeftYmax> <Player1Left>A</Player1Left> <Player1Right>D</Player1Right> <Player1Down>S</Player1Down> <Player1Up>W</Player1Up> <Player1LeftTrigger>Q</Player1LeftTrigger> <Player1RightTrigger>E</Player1RightTrigger> <Player2Start>RightControl</Player2Start> <Player2Back>RightShift</Player2Back> <Player2A>Home</Player2A> <Player2B>End</Player2B> <Player2X>PageUp</Player2X> <Player2Y>PageDown</Player2Y> <Player2ThumbstickLeftXmin>Left</Player2ThumbstickLeftXmin> <Player2ThumbstickLeftXmax>Right</Player2ThumbstickLeftXmax> <Player2ThumbstickLeftYmin>Down</Player2ThumbstickLeftYmin> <Player2ThumbstickLeftYmax>Up</Player2ThumbstickLeftYmax> <Player2Left>Left</Player2Left> <Player2Right>Right</Player2Right> <Player2Down>Down</Player2Down> <Player2Up>Up</Player2Up> <Player2LeftTrigger>Insert</Player2LeftTrigger> <Player2RightTrigger>Delete</Player2RightTrigger> </Settings>
パッと見からして、キー配列以外にも数多くの(というより動作に必要なほとんどの)設定が記載された XML ファイルだとわかる。
settings.xml の名の通り、という感じ。
しかし、これはソースではなく、ビルドによって出力された“実行時に入力するための設定ファイル”だ。
(同パスに出来ている exe を実行する前に、上記の内容を変更しておけばそれに準じた設定となる(と思う
じゃあこれらの設定はどこで行っているのか。
とりあえず、キーの配列(XBOX360コントローラ用のボタン割り当て)はどこで決めているのか。
探してみた。
Program.cs や SpacewarGame.cs より一階層深いパス「common」フォルダの下にある4つのソースがどうもそれっぽい。
GamePadHelper.cs
GamePads.cs
Keymap.cs
XInputHelper.cs
ここでキー配列を含むキーパッド関連のクラスを定義してるみたい。
さて、本題。
XNA におけるキー押下通知、非常に気になる機構。
XNA Game Studio 2.0 で追加されたキーパッド関連のメソッドがある。
IsButtonDown
IsButtonUp
である。
これによるコードレベルでの変化を、XNA Game Studio Express 1.x までと比較してみる。
1.x
// AボタンとBボタンの同時押しを検出! if (padState.Buttons.A == ButtonState.Pressed && padState.Buttons.B == ButtonState.Pressed ) ...
2.0
// AボタンとBボタンの同時押しを検出! if (padState.IsButtonDown(Buttons.A&Buttons.B) ) ...
うん、スッキリ書ける。
2つのキー同時押しでこれだから、それ以上になれば更に。
同時押しに限らず、どちらか(いずれか)でも '&' が '|' の判定になるだけで、処理の簡素化の程度は同様。
これはイイ。
この判定方法って、1.x にせよ 2.0 にせよ「押されているかどうか」を見ている。
「押されたことを検知した」わけではない。
つまり、キー押下(KeyPress)イベントを受け取るような WinForms 的な発想とは異なるわけだ。
これはどうしてだろう。
個人的解釈を書いてみる。
XNA はゲームを開発するための Framework だ。
そのための機構が色々とデフォルトで組み込まれている。
その一つは Update メソッドの実装ではないかと思う。
空プロジェクトでも頻繁に呼ばれる Update メソッド。
実行して、どっか(Updateメソッドが妥当か)で BreakPoint 張って止めてみる。
this.base.TargetElapsedTime が Update のコール周期。
{00:00:00.0166667}
となっていた。
Default では、0.0166667 秒周期、つまり「秒間60回」頻度でコールされている。
設定変更はプロパティの値を変えることで出来るが、そういうことを言っているのではなくて。
「秒間60回」呼ばれるように初期設定されていることこそが、「ゲームを開発するための Framework 」ならではの設定だと感じる。
Windows アプリケーションや、Web アプリケーションと違って、ゲームの場合、画面に対して何かしら目に見える変化がある。
そうでなければ成り立たないからだ。(ゲームが
XNA は、KeyPress を検出するような機構を提供していない。
それは、Update メソッドで「キーが押されているかどうか」を判定することで、「キーが押されたことを検出する」のと同様の検知能力を提供できる、という意図の現れではないかと思う。
ふーむ。
XNA ならではの入力検知処理を垣間見た気がした。