DirectInput(DirectX マウス入力)

今回は,DirectInputについて取り上げてみたいと思います。

DirectInputとは,DirectXで使用する事が出来るマウス入力です。

WindowsAPIでマウス情報が取得したい場合は,イベントでやる他ないと思うので WM_LBUTTONDOWNとかと格闘してください。

そして注意してほしいのは,マウス入力と言っていますが, 今回の例ではクリック情報しか取得しません。DirectInputでマウス座標も拾えますが, 今回はしていないということです。

では,さくっとプログラム書きますね。

// DirectInput用定義  
LPDIRECTINPUTDEVICE8 pDIMouse;  
LPDIRECTINPUT8 pDInput;  
DIMOUSESTATE2 dIMouseState;
     
// 初期化   
pDInput = NULL;      
pDIMouse = NULL;

// DirectInputの初期化 ここから //////////////////////////////////////////////   
DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&pDInput, NULL);

pDInput->CreateDevice(GUID_SysMouse, &pDIMouse, NULL);
pDIMouse->SetDataFormat(&c_dfDIMouse2); // マウス用のデータ・フォーマットを設定

HWND hWnd = FindWindow(L”NFWWindow”, NULL);
pDIMouse->SetCooperativeLevel(hWnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);

// デバイスの設定   
DIPROPDWORD diprop;   
diprop.diph.dwSize = sizeof(diprop);   
diprop.diph.dwHeaderSize = sizeof(diprop.diph);   
diprop.diph.dwObj = 0;   
diprop.diph.dwHow = DIPH_DEVICE;   
diprop.dwData = DIPROPAXISMODE_REL; // 相対値モードで設定(絶対値はDIPROPAXISMODE_ABS)   
pDIMouse->SetProperty(DIPROP_AXISMODE, &diprop.diph);

// 入力制御開始   
pDIMouse->Acquire(); // ここでエラーが発生しますが,無視してかまいません。
// DirectInputの初期化 ここまで //////////////////////////////////////////////////////

// DirectInputの更新 ここから //////////////////////////////////////////////////////
// 値の初期化   
dIMouseState.rgbButtons[0] = 0;
// 値の更新
if(FAILED(pDIMouse->GetDeviceState(sizeof(DIMOUSESTATE2), &dIMouseState)))
   pDIMouse->Acquire(); // 1発目や2発目にエラーが出るが無視してよい。
// DirectInputの更新 ここまで //////////////////////////////////////////////////////

あとは,値のチェックの時に,(dIMouseState.rgbButtons[0] & 0x80)がtureの時は,クリックしているということになります。

rgbButtonsとかでぐぐったら,左クリック以外の値も分かります。

ということで,DirectInputをとりあえず使う事はこれで出来ると思います。

comments

関数ポインタ の 配列 を クラス に書く場合

関数ポインタの配列だけで、十分厄介なのに

クラスに書くと、さらに厄介になるのが 関数ポインタ 本当にうっとうしい><

さっそく、サンプルプログラムを書いてみることにします♪

Sample.h
—————————————
class Sample()
{
private:
    int func01(int x, int y);
    int func02(int x, int y);
    int func03(int x, int y);

    int (Sample::*func[])(int, int);

public:
    Sample()
    {
        func[0] = &Sample::func01;
        func[1] = &Sample::func02;
        func[2] = &Sample::func03;

        (this->*func[0])(1, 1);
    }
};
—————————————
重要?なのは赤字の部分です
cppに必要なソースは書いてあるものとしています。
なので、これだけでは実行できませんので悪しからず。

関数ポインタの配列はわかるけれど、クラスに移すと
エラーが!って人用のプログラムだと思ってください。

備忘録として

comments

EmptyProject DirectX Windowのサイズ変更不可

DirectXにはSample Browserというサンプルリストがあります。
その中の EmptyProject などをフレームワークにして開発する人もいるかもしれません
(私が,そうだったりw)

その時に,画面のサイズを変更不可!変更不能!変更無効!にしたり
最大化を消したり 最小化を消したり ×ボタンを無効にしたかったりと
色々設定したいなぁと思う人もいるかも なので

軽くやり方について説明しておきます。備忘録込みですがw
まず,SampleBrowserのほぼすべてにDXUTというフォルダがあると思います。
そのフォルダの,[DXUT.cpp]をいじってあげる必要があるわけです。

めんどくさい人は,一番上階層にある[ファイル名.cpp]のDXUTCreateWindow()から定義へ移動して辿ればよいかと。

つまり,DXUTCreateWindow関数の内部で 下記のコードが見つかるはずです!

CreateWindow(L”Direct3DWindowClass”,
strWindowTitle,
WS_OVERLAPPEDWINDOW,
x, y, ( rc.right – rc.left ), ( rc.bottom – rc.top ), 0,
hMenu, hInstance, 0 );

あとは,このWS_OVERLAPPEDWINDOWを適切に書き換えてあげればよいかと思います!

ぇ?どう書き換えるかも教えろって?
WS_OVERLAPPEDWINDOWは
WS_OVERLAPPED、WS_CAPTION、WS_SYSMENU、WS_THICKFRAME、WS_MINIMIZEBOX、および WS_MAXIMIZEBOX
の足し合わせたものです。

それの,MINIMIZEBOX(最小化)とか,MAXIMAIZE(最大化)とか,THICKFRAME(サイズ変更)を抜いてあげれば,ウィンドウのサイズ変更を無効にしたりする事が出来ます。

他のスタイルが気になる場合は,
MSDN ウィンドウスタイル などでググってください。

以上

comments

エラー対処 C2572

error C2572: ‘メンバ変数名‘ : 既定パラメーターの再定義です
簡単にいうと,同じ関数が2つ以上ありますので,1つにしてね!

対処方法
?.h
・同じ関数が無いかチェックする あった場合はどちらか削除

?.cpp
・同じ関数が無いかチェックする あった場合はどちらか削除
・メンバ変数の引数に=0が入っている場合は =0を削除する

comments

警告対処 C4996

warning C4996: ‘古い関数名‘: This function or variable may be unsafe. Consider using localtime_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. 
簡単にいうと,古い関数を使用していますので,セキュリティ強化版の関数を使用してね

例)
// 引数が変わってるので注意
localtime→localtime_s

// お馴染みの警告オフ  もちろん使用しないに越した事は無い
#pragma warning(disable : 4996)

comments

mutableについて

c++ の mutable について

まず,mutableってどんな意味なんだと言いますと,
「変更可能な」
という意味だそうです。

プログラム的に一言で申しますと,
constインスタンスのメンバ変数の値を変更可能にする
と言えます。
これで理解できた人は,これ以降読む必要ないですね

そんなんで分かるかぁ!って人は読んでみてくださいw
まず,constインスタンスというのは,CLASS型クラスの
インスタンスをconstで定数化するということで,プログラムで
書くと,下記の様になります。
const CLASS c; または const CLASS * c = new CLASS();

そして,メンバ変数の値を変更可能にするということですが,
それを理解するためには,下記を理解している必要があります。

まず,constを付けると,cの値は変更不可になる。
そりゃそうですね。const int i = 5;とか書くと,iは5以外に変更できません。
それと同じように,cをconstでくくってしまうと,cの値は変更不可になります。

例えば,
class CLASS{
public:
        int value;
        CLASS(){ value = 0; }
        void init()const { value = 0; }//ERROR
};
void main()
{
        const CLASS c;
        c.value = 1;//ERROR
}
としておいた場合は,デフォルトコンストラクタで初期化した後は
もぅc.valueの値は書き換えられません。
この時,int valueにmutableを書いておいてやると
なんと,c.valueの値を書き換える事が出来るようになります。
例)
class CLASS{
public:
        mutable int value;
        CLASS(){ value = 0; }
        void init()const { value = 0; }//OK
};
void main()
{
        const CLASS c;
        c.value = 1;//OK
        c.init();//OK
}

mutableはconstを掛けた時の例外を生み出すことになるんですね。
まぁ,全変数にmutableを掛けて,宣言時にconstが掛かろうとも,
全部書き換えられるようにしておく っていう使い方があるのかも?

comments

関数ポインタの使いどころ

関数ポインタの使い方 というより,使いどころについて説明します!

 

関数ポインタの使いどころは大きく2点
1点目:速度を上げる
2点目:似ている処理を纏める

です!
では,1点目の速度を上げる事についてカキカキ
main.cpp
—————————————————————————————
 #include <iostream>
 #define MAX_SLIME 5

void GetEnemy01(std::string *Name, int *Number);  
void GetEnemy02(std::string *Name, int *Number);  
void GetEnemy03(std::string *Name, int *Number);  
void GetEnemy04(std::string *Name, int *Number);  
void GetEnemy05(std::string *Name, int *Number);

int mainFunction()  
{   
          // 乱数シード値の設定
          srand(static_cast<unsigned int>(time(NULL)));
          // 関数ポインタの宣言
          void (*GetEnemy[MAX_SLIME])(std::string *, int *);
          // 関数ポインタの配列に 関数を入れる
          GetEnemy[0] = GetEnemy01;   
          GetEnemy[1] = GetEnemy02;   
          GetEnemy[2] = GetEnemy03;   
          GetEnemy[3] = GetEnemy04;   
          GetEnemy[4] = GetEnemy05;

          // 初期化
          std::string Name = “”;   
          int Number = 0;   
          // 乱数の生成
          int EnemyNumber = rand() % 5;   
          // EnemyNumber番目に入っている関数を呼び出す
          GetEnemy[EnemyNumber](&Name, &Number);

           std::cout << “番号:” << Number << “ 名前:” << Name << std::endl;   std::cin >> Name;
          return 0;
}

 void GetEnemy01(std::string *Name, int *Number)  {   *Name = “すらいむ”;   *Number = 1;  }

 void GetEnemy02(std::string *Name, int *Number)  {   *Name = “がったいすらいむ”;   *Number = 2;  }

 void GetEnemy03(std::string *Name, int *Number)  {   *Name = “べほますらいむ”;   *Number = 3;  }

 void GetEnemy04(std::string *Name, int *Number)  {   *Name = “ほいみすらいむ”;   *Number = 4;  }

 void GetEnemy05(std::string *Name, int *Number)  {   *Name = “ばぶるすらいむ”;   *Number = 5;  }
—————————————————————————————
注目するべきはここ↓
void (*GetEnemy[MAX_SLIME])(std::string *, int *);
これが,関数ポインタの宣言にあたります。

これはいったい何をやっているのか!?
実はこれらは,関数ポインタの配列を宣言して,それぞれに関数のアドレスを入れ
あとは,配列の何番目を呼び出すと そういうことをやっています。

もし,1だったら,1を呼び出すとか それを条件判定でやると
関数が増えれば増えるほど,時間がかかります。
理由?

1を選択する時,
もし1ならば1 なら 1回の判定で済みますが
5を選択する時は,
もし1ならば → 違う  もし2ならば → 違う  もし3ならば → 違う・・・
もし5ならば 5 と5回判定する必要があるのです。配列なら,判定要らずですね。

では,続いて,似ている処理を纏める
についてですが,次のページで説明します。

comments

文字列と配列とポインタ

次に気になったのは,char型の配列又はポインタのconstを付けた時のこと

ご存知のように文字列とは”ダブルクォーテーション”で囲まれたものです。
これを,typeidで型を調べると,char constの配列となると思います。

では,本題に入りまして下記の2つは何が違うのでしょうか?
char * const str1 = “abc”;
char const str2[] = “abc”;

よく言われるのは,
 char * str3 = “abc”;
 char str4[] = “abc”;
こちらのパターン。

 str3 = “”; // OK
 str4 = “”; // エラー
 str3[0] = ‘1’; // OK
 str4[0] = ‘1’; // OK

charの配列は,初期化子で文字列を入れられるだけなので
代入はできません。
ポインタの場合は,アドレスの参照先の値を書き換えるだけなので,
代入する事が出来ます。

では,constをつけるとどうなるのか。

char * const str1 = “abc”;
char const str2[] = “abc”;

 str1 = “”; // エラー
 str2 = “”; // エラー
 str1[0] = ‘1’; // OK
 str2[0] = ‘1’; // エラー

こうなります。
ポインタに対する * const 変数
のような場合,ロックされるのは変数の値(アドレス)なので,
アドレスを書き換える事ができなくなります。
なので,str1 = “”;が出来なくなるんですね。

そして,配列の場合の const 変数
のような場合,ロックされるのは配列の値全てなので,
値を書き換える事ができなくなります。
なので, str2[0] = ‘1’;が出来なくなるんですね。

ちなみに,
 str1[0] = ‘1’; // OK
これですが,
const char * str1 = “abc”; か char const * str1 = “abc”;
と書くことで,ロックする事が出来ます。

comments

charの配列・ポインタと文字列(文字列リテラル)について

charの配列と
charのポインタの文字列の扱い方について

私の只のメモなんで,分かり難くても知らないです><!
char * str = “abc”;
この”abc”は,メモリの定数領域に確保されたものだから
例えば,
char *str1 = “abcd”;
char *str2 = “abcd”;
とした場合,機器にもよるが”abcd”のアドレスは同値となる。
この時,
str1[0] = ‘b’;のように書くことはできるが,
実行すると例外を吐き出されるので注意(やらん方がいいってことで)

続いて,
char str1[] = “abcd”;
char str2[] = “abcd”;
とした場合,スタック領域に値が一つ一つ入れられるので
この場合の”abcd”は{‘a’,’b’,’c’,’d’,”}の略でしかない
ので,中の値を書き換えることに何の問題もない。
但し,配列のため
str1 = みたいな代入はもちろん不可

 

comments

配列による文字列

配列による文字列
プログラムで書くと ↓ こんな感じ?
const char str[] = “”;

今回気になったのは,が配列の途中にあった場合,出力はどうなるのか?
文字配列中のは,どのように処理されるのか気になったのです。
“abcdef” という文字列だった場合という事ですね。
普通に考えたら,abcのみ出力して,それで終了です。
さて,合っているのでしょうか。

キャプチャ

どうやら正解の様です。str自体の大きさは,abcdefの8バイト
こちらも,特に問題はないですね。

こうなると,が入ってても最後まで出力する方法も知りたいですね。
といっても,私が知ってる限りでは,
for(int i = 0; i < sizeof(str); i++)
{
  std::cout << str[i];
}
と書くことでしょうか。
実行してみると,の部分は半角スペースで表示されました。

 

comments