DXライブラリとC言語でゲームプログラミングその7。前回作ったゲームパッドで操作する機能の改善。XInputで3Dゲームを作る前提です。
前回はこちら↓
キーボードとゲームパッドの入力の統合
前回ゲームパッドで操作できるようにしたがキーボードとは独立してでの判定。このままでも操作することはできるが、先人の実装コードを見るとキーボードとゲームパッドの入力を統合するのが普通。キーコンフィグを実装するなら特に。
実装するにあたりまずはゲーム内での操作(左右上下に移動、ジャンプ、攻撃、ダッシュetc)をまとめた構造体を定義し、各操作ごとに番号を振っていく。そしてその番号を使ってキーボードとゲームパッドの入力を統合していく。
実装
さっそくコードをペタリ。
Input.h
//Input.hに以下の変数・関数を追加
//ゲームの操作をまとめた構造体(中身は一例)
typedef struct {
int up;
int down;
int left;
int right;
int confirm; //決定ボタン
int attack;
int jump; //今回はキャンセルボタンも兼ねる
int dash;
int menu;
}config_t;
extern config_t config;
void Input_Initialize();
void Input_Merge(int* p, int k);まず Input.h にゲーム内の操作一覧をまとめた構造体 config_t を記載して extern config_t configを宣言。externをつけないと多重定義エラーが出るので注意。
Input.cpp
//以下の変数・関数を追加
config_t config;
//入力関連の初期化
void Input_Initialize() {
config.up = 0;
config.down = 1;
config.left = 2;
config.right = 3;
config.confirm = 13;
config.attack = 14;
config.jump = 12;
config.dash = 9;
config.menu = 4;
}
//2つの引数の比較。大きい方を1つ目の引数に代入
void Input_Merge(int *p, int k) {
//片方が離された瞬間(-1)でもう片方が入力なし(0)の場合
if (*p == -1 && k == 0) {
return;
}
else if (*p == 0 && k == -1) {
*p = k;
return;
}
//それ以外
*p = *p > k ? *p : k;
}
//ゲームパッドの入力状態を更新する
void Input_UpdateGanepad() {
//中略
//以下を追加
//キーボードとゲームパッドの入力を統合
Input_Merge(&Input_Gamepad[config.up], Input_Keyboard[KEY_INPUT_UP]);
Input_Merge(&Input_Gamepad[config.down], Input_Keyboard[KEY_INPUT_DOWN]);
Input_Merge(&Input_Gamepad[config.left], Input_Keyboard[KEY_INPUT_LEFT]);
Input_Merge(&Input_Gamepad[config.right], Input_Keyboard[KEY_INPUT_RIGHT]);
Input_Merge(&Input_Gamepad[config.confirm], Input_Keyboard[KEY_INPUT_RETURN]);
Input_Merge(&Input_Gamepad[config.attack], Input_Keyboard[KEY_INPUT_A]);
Input_Merge(&Input_Gamepad[config.jump], Input_Keyboard[KEY_INPUT_S]);
Input_Merge(&Input_Gamepad[config.dash], Input_Keyboard[KEY_INPUT_LSHIFT]);
Input_Merge(&Input_Gamepad[config.menu], Input_Keyboard[KEY_INPUT_SPACE]);
}
Input.cpp には先ほどのconfig_t configを再度宣言し、初期化する関数を追加。次にキーボードとゲームパッドの入力内容を比較する関数を用意。ゲームパッドの入力を得る関数の最後に入力を統合する関数を追加。結果はゲームパッドの入力を格納する方の配列に入れる。
あとはMenu.cppなどのキー入力確認の部分を以下のように変更する。
Menu.cpp
//更新
void Menu_Update() {
if (Input_GetGamepadDown(config.down) || Input_GetGamepadDown(XINPUT_THUNMBL_DOWN)) { //下が押されていたら
NowSelect = (NowSelect + 1) % eMenu_Num;//選択状態を一つ下げる
}
if (Input_GetGamepadDown(config.up) || Input_GetGamepadDown(XINPUT_THUNMBL_UP)) { //上が押されていたら
NowSelect = (NowSelect + (eMenu_Num - 1)) % eMenu_Num;//選択状態を一つ上げる
}
if (Input_GetGamepadDown(config.confirm)) { //攻撃(決定)ボタンが押されたら
switch (NowSelect) {//現在選択中の状態によって処理を分岐
case eMenu_Game://ゲーム選択中なら
SceneMgr_ChangeScene(eScene_Game);//シーンをゲーム画面に変更
break;
case eMenu_Config://設定選択中なら
SceneMgr_ChangeScene(eScene_Config);//シーンを設定画面に変更
break;
default:
break;
}
}
}Config.cppおよびGame.cppの方も同様にキー入力確認の部分を書き変えていく。
補足
今回でキーボードとゲームパッドの入力を統合したわけだが、上の実装例を見て「ゲームパッドの十字キーと左スティックの入力も1つにまとめないのか」と思った人がいると思う。
これは実際の3Dゲーム上で操作する場合、十字キーと左スティックには違う操作を割り当てる必要がある(例:十字キーはホットキー移動・切り替え、左スティックはプレイヤーの移動)ことがあるので今回は統一していない。
弾幕STGゲームなど2D操作でかつ操作数も少ない場合はもちろん統合してもよし。

コメント