【DXライブラリ】キーコンフィグを実装する

今回はキーコンフィグの実装。ゲームパッドの対応ボタンを変更できるようにします。

ゲームパッドの対応ボタンを変更したい

前回ゲームパッド(XInput)で操作できるようにしたので今回はその流れでキーコンフィグ機能を実装していく。ジャンルにもよるが大抵のPCゲームの場合キーコンフィグ機能があるはず。

今回キーコンフィグの対象はとりあえずゲームパッドのみ。キーボードの操作もコンフィグできるようにしたいけどまずはゲームパッドから。前回 Input.cpp/h に作ったゲーム内の操作をまとめた構造体 config_t の各項目に入っている数字がゲームパッドの各ボタンに対応する番号が入っている。なのでこれを変えれるようにすることでキーコンフィグを実装する。

例のよってXInput対応のゲームパッドで3Dゲームを作る前提です。

サンプルコード

キーコンフィグの実装にあたりシーン切り替え機能を実装した際に作った Config.cpp に以下のコードを追加・変更していく。

Config.cpp

//以下のコードを追加する

//選択項目表示用座標
const static int KEYCONFIG_X = 64;
const static int KEYCONFIG_Y = 96;

typedef enum {
    eConfig_Confirm,      //決定ボタン
    eConfig_Attack,       //攻撃ボタン
    eConfig_Jump,         //ジャンプ(キャンセル)ボタン
    eConfig_Dash,         //ダッシュボタン
    eConfig_Menu,         //メニューボタン
    eConfig_Exit,

    eConfig_Num,        //本項目の数
} eConfig;

static int NowSelect = eConfig_Confirm;    //現在の選択状態(初期はメニューの一番上)

//以下の関数達を次のように変更する
//初期化
void Config_Initialize() {
    NowSelect = eConfig_Confirm;
}

//更新
void Config_Update() {

    if (Input_GetGamepadDown(config.down) || Input_GetGamepadDown(XINPUT_THUMBL_DOWN)) {    //下が押されていたら
        NowSelect = (NowSelect + 1) % eConfig_Num; //選択状態を一つ下げる
    }
    if (Input_GetGamepadDown(config.up) || Input_GetGamepadDown(XINPUT_THUMBL_UP)) {    //上が押されていたら
        NowSelect = (NowSelect + (eConfig_Num - 1)) % eConfig_Num; //選択状態を一つ上げる
    }

    //キーコンフィグ
    switch (NowSelect) {
    case eConfig_Confirm:
        Input_CheckKeyConfig(KEYCONFIG_CONFIRM);
        break;
    case eConfig_Attack:
        Input_CheckKeyConfig(KEYCONFIG_ATTACK);
        break;
    case eConfig_Jump:
        Input_CheckKeyConfig(KEYCONFIG_JUMP);
        break;
    case eConfig_Dash:
        Input_CheckKeyConfig(KEYCONFIG_DASH);
        break;
    case eConfig_Menu:
        Input_CheckKeyConfig(KEYCONFIG_MENU);
        break;
    default:
        break;
    }

    if (NowSelect == eConfig_Exit) {
        if (Input_GetGamepadDown(config.confirm)) { //キャンセル(ジャンプ)ボタンが押されていたら
            SceneMgr_ChangeScene(eScene_Menu);//シーンをメニューに変更
        }
    }
}

//描画
void Config_Draw() {
    int y = KEYCONFIG_Y;

    DrawString(CONFIG_X, CONFIG_Y, "設定画面です。", GetColor(255, 255, 255));

    //キーコンフィグの内容を表示
    DrawFormatString(KEYCONFIG_X, KEYCONFIG_Y, GetColor(255, 255, 255), "決定 : %d", config.confirm);
    DrawFormatString(KEYCONFIG_X, KEYCONFIG_Y + 20, GetColor(255, 255, 255), "攻撃 : %d", config.attack);
    DrawFormatString(KEYCONFIG_X, KEYCONFIG_Y + 40, GetColor(255, 255, 255), "ジャンプ・キャンセル : %d", config.jump);
    DrawFormatString(KEYCONFIG_X, KEYCONFIG_Y + 60, GetColor(255, 255, 255), "ダッシュ : %d", config.dash);
    DrawFormatString(KEYCONFIG_X, KEYCONFIG_Y + 80, GetColor(255, 255, 255), "メニューを開く : %d", config.menu);
    DrawString(KEYCONFIG_X, KEYCONFIG_Y + 120, "キーコンフィグを終了する", GetColor(255, 255, 255));

    switch (NowSelect) {
    case eConfig_Confirm:
        y = KEYCONFIG_Y;
        break;
    case eConfig_Attack:
        y = KEYCONFIG_Y + 20;
        break;
    case eConfig_Jump:
        y = KEYCONFIG_Y + 40;
        break;
    case eConfig_Dash:
        y = KEYCONFIG_Y + 60;
        break;
    case eConfig_Menu:
        y = KEYCONFIG_Y + 80;
        break;
    case eConfig_Exit:
        y = KEYCONFIG_Y + 120;
        break;
    default:
        break;
    }

    DrawString(KEYCONFIG_X - 30, y, "■", GetColor(255, 255, 255));
}

キーコンフィグの内容がわかるようにゲーム内操作と対応するゲームパッドのボタンを表示、選択できるようにしている。

次に Input.h にキーコンフィグ用の列挙体を追加し、キーコンフィグを行う関数を宣言する。

Input.h

//以下のコードをConfig.hに追加

//キーコンフィグ用
typedef enum {
	KEYCONFIG_UP,
	KEYCONFIG_DOWN,
	KEYCONFIG_LEFT,
	KEYCONFIG_RIGHT,
	KEYCONFIG_CONFIRM,
	KEYCONFIG_ATTACK,
	KEYCONFIG_JUMP,
	KEYCONFIG_DASH,
	KEYCONFIG_MENU
} eKeyConfig;

void Input_ChangeKeyConfig(int Number, int ConfigSelect);
void Input_CheckKeyConfig(int ConfigCode);

こちらもゲーム内操作を列挙していく。

最後に Input.cpp にキーコンフィグを行う関数を書いていく。

Input.cpp

//以下のコードを追加
//キーコンフィグ本体。他の項目に同じ番号があればそれと交換する
void Input_ChangeKeyConfig(int Number, int ConfigSelect) {
    if (ConfigSelect == KEYCONFIG_CONFIRM) {
        if (config.attack == Number) {
            config.attack = config.confirm;
        }
        else if (config.jump == Number) {
            config.jump = config.confirm;
        }
        else if (config.dash == Number) {
            config.dash = config.confirm;
        }
        else if (config.menu == Number) {
            config.menu = config.confirm;
        }
        config.confirm = Number;
    }

    if (ConfigSelect == KEYCONFIG_ATTACK) {
        if (config.confirm == Number) {
            config.confirm = config.attack;
        }
        else if (config.jump == Number) {
            config.jump = config.attack;
        }
        else if (config.dash == Number) {
            config.dash = config.attack;
        }
        else if (config.menu == Number) {
            config.menu = config.attack;
        }
        config.attack = Number;
    }

    if (ConfigSelect == KEYCONFIG_JUMP) {
        if (config.confirm == Number) {
            config.confirm = config.jump;
        }
        else if (config.attack == Number) {
            config.attack = config.jump;
        }
        else if (config.dash == Number) {
            config.dash = config.jump;
        }
        else if (config.menu == Number) {
            config.menu = config.confirm;
        }
        config.jump = Number;
    }

    if (ConfigSelect == KEYCONFIG_DASH) {
        if (config.confirm == Number) {
            config.confirm = config.dash;
        }
        else if (config.attack == Number) {
            config.attack = config.dash;
        }
        else if (config.jump == Number) {
            config.jump = config.dash;
        }
        else if (config.menu == Number) {
            config.menu = config.dash;
        }
        config.dash = Number;
    }

    if (ConfigSelect == KEYCONFIG_MENU) {
        if (config.confirm == Number) {
            config.confirm = config.menu;
        }
        else if (config.attack == Number) {
            config.attack = config.menu;
        }
        else if (config.jump == Number) {
            config.jump = config.menu;
        }
        else if (config.dash == Number) {
            config.dash = config.menu;
        }
        config.menu = Number;
    }
}

//キーコンフィグをするかの確認。ゲームパッドの入力があれば各項目のキーコンフィグを行う
void Input_CheckKeyConfig(int ConfigCode) {
    int i;

    //ゲームパッドの入力を確認
    //左右スティックは除く(どのゲームも左が移動、右がカメラ操作と固定されているため)
    //十字キーも除く(メニュー画面での操作の関係)
    for (i = XINPUT_BUTTON_START; i < XINPUT_THUMBL_UP; i++) {
        //入力があればconfigの該当する値を変更
        if (Input_Gamepad[i] > 0) {
            switch (ConfigCode) {
            case KEYCONFIG_CONFIRM:
                Input_ChangeKeyConfig(i, KEYCONFIG_CONFIRM);
                break;
            case KEYCONFIG_ATTACK:
                Input_ChangeKeyConfig(i, KEYCONFIG_ATTACK);
                break;
            case KEYCONFIG_JUMP:
                Input_ChangeKeyConfig(i, KEYCONFIG_JUMP);
                break;
            case KEYCONFIG_DASH:
                Input_ChangeKeyConfig(i, KEYCONFIG_DASH);
                break;
            case KEYCONFIG_MENU:
                Input_ChangeKeyConfig(i, KEYCONFIG_MENU);
                break;
            default:
                break;
            }
        }
    }
}

Input_CheckKeyConfig() でゲームパッドの入力があるか確認し、あれば Input_ChangeKeyConfig() で現在選択中のゲーム操作に対応するボタンを変更する。今回は1つのボタンに複数の操作が割り当てられないようにしている(すでに割り当たっているボタンがあればそれと入れ替えている)。

補足として上のサンプルコードでは十字キーおよびアナログスティックの入力をゲーム内操作に割り当てないようにしている。

これはアナログスティックについてはどの3Dゲームも左スティックが移動、右スティックがカメラ操作と決まっているので「変える必要はない」ものとして判断。十字キーはメニュー操作ができなくなるので外している。

もちろんゲームによってはメニューでの移動以外に十字キーを使うことがある(ホットバーの移動など)のでその場合は各自割り当てられるようにしておく。

またキーコンフィグの設定を保存する機能は今回書いていないので注意。キーコンフィグの内容を保存したい場合は外部に出力しておく必要がある。その方法については後日。

コメント

タイトルとURLをコピーしました