・キーボード
・マウス
・ジョイパッド
の3つの入力処理を扱うクラスを作成します。クラス名は、それぞれ、KeyboardState、MouseState、JoypadStateとします。
これらのクラスの機能は、ボタンが「押されているかどうか」、「押された瞬間かどうか」および「離された瞬間かどうか」を判定します。
それでは、クラスの定義を見てみましょう。
#pragma once
namespace a5ua
{
class KeyboardState
{
public:
KeyboardState();
void update();
bool presses(int code) const;
bool triggers(int code) const;
bool releases(int code) const;
private:
char m_buffer[2][256];
};
class MouseState
{
/* 省略 */
};
class JoypadState
{
/* 省略 */
};
struct InputSet
{
KeyboardState key;
MouseState mouse;
JoypadState joypad;
};
}
「押されているかどうか」はpresses(code)で調べます。
「押された瞬間かどうか」はtriggers(code)で調べます。
「離された瞬間かどうか」はreleases(code)で調べます。
codeはDxLib.hに定義されている値を用います。
メンバ変数に、 とありますが、要素数256の配列で1フレーム分の入力状態を格納できます。ここでは、2フレーム分の状態を必要とするので、このようなメンバ変数を定義しています。
MouseStateクラスでは、座標を取得する関数などもありますが、長くなるのでここでは省略します。
また、これらのクラスを、InputSetという構造体にまとめておきます。
ところで、皆さん。constメンバ関数はご存じですか?
上記で言うと、12行目の などのことです。
constメンバ関数とは、オブジェクトの内部状態が変更されない関数のことです。つまり、constメンバ関数内では、メンバ変数の値が変更されないので、読み出し専用ということになります。(書き込もうとすると、コンパイルエラーになります。)
一方、10行目の は、constが付いていません。なので、update()内では、メンバ変数の変更が自由にできます。
constメンバ関数の必要性は、次のサンプルで説明します。
では、これらのクラスを使ったサンプルプログラムを見てみましょう。
#include
#include "InputSet.h"
// テスト用コード
namespace test
{
// 位置、色を表す構造体
struct point
{
int x;
int y;
int color;
};
// 位置を補正する
void correct(int &v, int min, int max)
{
if (v < min) {
v = min;
}
if (max <= v) {
v = max - 1;
}
}
// 位置を補正する
void correct(point &p)
{
correct(p.x, 0, 640);
correct(p.y, 0, 480);
}
// キーボード入力により上下左右に移動
void move(point &p, const a5ua::KeyboardState &key)
{
if (key.presses(KEY_INPUT_LEFT)) {
p.x -= 10;
}
if (key.presses(KEY_INPUT_RIGHT)) {
p.x += 10;
}
if (key.presses(KEY_INPUT_UP)) {
p.y -= 10;
}
if (key.presses(KEY_INPUT_DOWN)) {
p.y += 10;
}
}
// ジョイパッド入力により上下左右に移動
void move(point &p, const a5ua::JoypadState &joypad)
{
if (joypad.presses(DX_INPUT_PAD1, PAD_INPUT_LEFT)) {
p.x -= 10;
}
if (joypad.presses(DX_INPUT_PAD1, PAD_INPUT_RIGHT)) {
p.x += 10;
}
if (joypad.presses(DX_INPUT_PAD1, PAD_INPUT_UP)) {
p.y -= 10;
}
if (joypad.presses(DX_INPUT_PAD1, PAD_INPUT_DOWN)) {
p.y += 10;
}
}
// マウスカーソルの位置に合わせて移動
void move(point &p, const a5ua::MouseState &mouse)
{
p.x = mouse.x();
p.y = mouse.y();
}
}
int APIENTRY _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
ChangeWindowMode(TRUE); // ウィンドウモードで起動
SetMainWindowText(_T("ゲームプログラミングの骨組み:入力処理"));
if (DxLib_Init() != 0) {
return -1;
}
SetDrawScreen(DX_SCREEN_BACK);
a5ua::InputSet input;
test::point p[3] = {
{100, 100, GetColor(255, 0, 0)},
{200, 200, GetColor(0, 255, 0)},
{300, 300, GetColor(0, 0, 255)},
};
while (ProcessMessage() == 0 && ClearDrawScreen() == 0) {
// 入力状態の更新
input.key.update();
input.joypad.update();
input.mouse.update();
// ESCキーで終了
if (input.key.presses(KEY_INPUT_ESCAPE)) {
break;
}
test::move(p[0], input.key); // キーボードによる移動
test::move(p[1], input.joypad); // ジョイパッドによる移動
test::move(p[2], input.mouse); // マウスによる移動
for (int i = 0; i < 3; ++i) {
test::correct(p[i]); // 位置補正
DrawCircle(p[i].x, p[i].y, 30, p[i].color);
}
ScreenFlip();
}
DxLib_End();
return 0;
}
ですから、 などは問題なく呼び出せます。
update()はメインループの最初に1回だけ呼び出せばよいので、他の場所で呼ばれると困るわけです。
という関数呼び出しでは、input.keyの内部状態は変更されないことがわかるので、安心ですね。
このように、constメンバ関数を使うことにより、より健全なプログラミングが出来ます。
今回作成したサンプルプログラム(バイナリおよびソース)をアップロードしました。(ビルドにはDXライブラリが必要です。)
実行すると、キーボードで動かせる●、ジョイパッドで動かせる●、マウスで動かせる●が表示されます。
http://www1.axfc.net/uploader/Sc/so/169009.zip&key=mixC