26:キーボード入力を受け付ける
キャラクターを移動させることまではできるようになりましたので、次はプレイヤー自らがキャラクターを動かせるようにしましょう。キーボード入力の受け付けはDirectInputで行います。DirectInputの宣言をする
入力関連のデータを格納するCGameObjectの派生クラス「CInput」のヘッダファイルに以下の定義を追加します。これでDirectXが提供する最新バージョンのDirectInputが利用できるようになります。DirectInputを利用できるようにするには、GUIDと呼ばれる定義も必要になります。これらの定義は「dxguid.lib」に格納されているので、コンパイル時にこのライブラリをリンクするようにしておきます。
#pragma once
#include "GameObject.h"
//利用するDirectInputバージョンの宣言
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
//DirectInputに関連するライブラリのリンクを宣言
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")
コンストラクタ・デストラクタの追加
ゲーム全体でDirectInputを初期化するのはまず一度きりなので、初期化と解放処理はコンストラクタ・デストラクタで行うことにします。DirectInputを管理するオブジェクトはLPDIRECTINPUT8(IDirectInput8)、入力機器(ここではキーボード)の管理を行うオブジェクトはLPDIRECTINPUTDEVICE8(IDirectInputDevice8)となっています。
#pragma once
#include "GameObject.h"
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "dxguid.lib")
class CInput : public CGameObject
{
private:
LPDIRECTINPUT8 pInput;
LPDIRECTINPUTDEVICE8 pKeyDevice;
};
#include "Input.h"
CInput::CInput()
{
pInput = NULL;
pKeyDevice = NULL;
}
CInput::~CInput()
{
RELEASE(pKeyDevice);
RELEASE(pInput);
}
キーボードデバイスを取得
次にDirectInputの作成および入力機器情報の作成を行います。DirectInput自体の作成はDirectInput8Createで、入力機器情報の作成はIDirectInput8::CreateDevice()にて行います。CreateDeviceの第1引数には対象のデバイスIDを指定する必要があります。ここでは、キーボードデバイスであるGUID_SysKeyboardを指定します。
void CInput::Init()
{
if(pInput == NULL){
// インターフェイスの取得
HRESULT hr;
hr = DirectInput8Create(
GetHInstance(), // ソフトのインスタンスハンドル
DIRECTINPUT_VERSION, // DirectInputのバージョン
IID_IDirectInput8, // 取得するインターフェイスのタイプ
(LPVOID*)&pInput, // インターフェイスの格納先
NULL // COM集成の制御オブジェクト(使わないのでNULL)
);
if(FAILED(hr)){
DXTRACE_MSG(_T("DirectInputの初期化に失敗しました"));
return;
}
hr = pInput->CreateDevice(
GUID_SysKeyboard, // 受け付ける入力デバイス
&pKeyDevice, // IDirectInputDevice8格納先
NULL // COM集成の制御オブジェクト(使わないのでNULL)
);
if(FAILED(hr)){
DXTRACE_MSG(_T("DirectInputDeviceの初期化に失敗しました"));
return;
}
}
}
つづいて協調モードの指定を行います。これは、データを取得する状況を指定するもので、3つの状態を組み合わせることができます。指定はIDirectInputDevice8::SetCooperativeLevel()で行います。
①取得するタイミング | |
---|---|
DISCL_BACKGROUND | ウィンドウがアクティブになっていなくても常に取得 |
DISCL_FOREGROUND | ウィンドウがアクティブになっているときのみ取得 |
②取得データの提供先 | |
DISCL_EXCLUSIVE | DirectInputを呼び出したアプリのみに限定 |
DISCL_NONEXCLUSIVE | すべてのアプリケーションに提供 |
③Windowsキーのロック | |
DISCL_NOWINKEY | ウィンドウズキーをロックして無効にする |
/* 省略 */
class CInput : public CGameObject
{
private:
LPDIRECTINPUT8 pInput;
LPDIRECTINPUTDEVICE8 pKeyDevice;
BYTE keydata[256];
protected:
void Init();
};
void CInput::Init()
{
if(pInput == NULL){
/* 省略 */
// データフォーマットの設定
pKeyDevice->SetDataFormat(&c_dfDIKeyboard);
// 協調モードの設定
pKeyDevice->SetCooperativeLevel(GetHWnd(),
DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
// キーバッファの初期化
ZeroMemory(keydata, 256);
}
}
入力された情報を取得
キーボードからどのキーが押されたかは、IDirectInputDevice8::Acquire()によって入力の受け付けを開始した後で、IDirectInputDevice8::GetDeviceState()によってリアルタイム取得できます。データは256バイトの配列に丸ごと格納されるので、その中から特定のキーが押されているかどうかを取得する関数を別に用意しておくと便利でしょう。
/* 省略 */
class CInput : public CGameObject
{
private:
LPDIRECTINPUT8 pInput;
LPDIRECTINPUTDEVICE8 pKeyDevice;
BYTE keydata[256];
public:
BOOL IsKeyDown(int key);
protected:
void Init();
void Exex();
};
void CInput::Exec()
{
if(pKeyDevice){
// 入力の受け付け開始
pKeyDevice->Acquire();
// データを取得(256は取得するデータのサイズ)
pKeyDevice->GetDeviceState(256, keydata);
}
}
BOOL CInput::IsKeyDown(int key)
{
if(pKeyDevice == NULL) return FALSE;
// 最上位1ビットに「押されているか」どうかのデータが格納されていることに注意
// 最下位1ビットには「トグル(オン・オフの状態)」が格納されている
return (keydata[key] & 0x80) ? TRUE : FALSE;
}