ページ 11

gpUpdateKey()についての質問です

Posted: 2011年11月12日(土) 01:08
by tepi
初めて書き込みをさせていただきます。
よろしくお願いします!
すごく初歩的な質問かもしれませんが考えても分かりませんでした。

新・ゲームプログラミングの館の

2.9 全てのキーの入力状態を取得する

で書かれている gpUpdateKey()関数についてなのですが

コード:

#include "DxLib.h"

int Key[256]; // キーが押されているフレーム数を格納する

// キーの入力状態を更新する
int gpUpdateKey(){
        char tmpKey[256]; // 現在のキーの入力状態を格納する
        GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
        for( int i=0; i<256; i++ ){ 
                if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
                        Key[i]++;     // 加算
                } else {              // 押されていなければ
                        Key[i] = 0;   // 0にする
                }
        }
        return 0;
}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
        ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定

        int x=0;

        // while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キーの状態更新)
        while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 && gpUpdateKey()==0 ){

                DrawFormatString( x, 0, GetColor(255,255,255), "?!" ); // x,0 の位置に白で ?! を描画

                if( Key[KEY_INPUT_RIGHT] == 1 ){ // 右キーが押された瞬間なら
                        x = x + 50;                 // xを50加算
                }

        }

        DxLib_End(); // DXライブラリ終了処理
        return 0;
} 
 


GetHitKeyStateAll( tmpKey )でtmpKeyで書き込まれているのにwhile文中ではなぜKeyに変わっているのか?
ということが分かりません。

それと、
1.whileの条件の中のgpUpdateKey()==0が呼び出されて、Keyの中身がすべて0になる。
2.?!を表示する。

この後に→キーが約1/60以上の感覚で押すと、Key[KEY_INPUT_RIGHT] == 1になり?!がx+50進む。
1へ戻って、Key[KEY_INPUT_RIGHT] == 0になる。

といった流れなのでしょうか?

回答よろしくお願いします!

Re: gpUpdateKey()についての質問です

Posted: 2011年11月12日(土) 07:27
by beatle
tepi さんが書きました: GetHitKeyStateAll( tmpKey )でtmpKeyで書き込まれているのにwhile文中ではなぜKeyに変わっているのか?
ということが分かりません。
tmpKeyにキーの入力状態が書きこまれているのはその通りです。
そして、if文によってtmpKeyの要素を読み込んで、条件分岐し、if文の中身で Key++; などと、Keyに書き込んでいます。

だからWinMain関数のwhile文中ではKeyを利用しています。

スコープの関係で、WinMain関数のwhile文中からはtmpKey変数が見えないという事情もあります。

tepi さんが書きました: それと、
1.whileの条件の中のgpUpdateKey()==0が呼び出されて、Keyの中身がすべて0になる。
2.?!を表示する。

この後に→キーが約1/60以上の感覚で押すと、Key[KEY_INPUT_RIGHT] == 1になり?!がx+50進む。
1へ戻って、Key[KEY_INPUT_RIGHT] == 0になる。

といった流れなのでしょうか?


大体流れとしては合ってます。

「→キーが約1/60以上の感覚で押す」というのを
「→キーが約1/60秒以上の間押されている」と解釈することにします。
DXライブラリにはあまり詳しくないですが、ざっとプログラムを見るかぎり、60FPSに制限している感じではありません。
だから1/60秒以上というのはあまり関係なく、gpUpdateKey関数、もっと言えばGetHitKeyStateAll関数が実行された時点で
→キーを押していれば、Key[KEY_INPUT_RIGHT] == 1になります。

それから
「1.whileの条件の中のgpUpdateKey()==0が呼び出されて、Keyの中身がすべて0になる。」
というのは、どのキーも押されていない場合に限って成り立ちます。
もし何かキーが押された状態でgpUpdateKey関数を呼び出すと、「Keyの中身がすべて0になる。」なんてことにはなりません。

Re: gpUpdateKey()についての質問です

Posted: 2011年11月13日(日) 02:28
by tepi
返信ありがとうございます!

「→キーが約1/60以上の感覚で押す」というのは、
ScreenFlip()でメモリの内容をフレッシュするタイミングが
ほとんどのPCが60Hzで1/60秒感覚で入れ替わっている
というようなことが書かれていたので
もしツールなどで1/60秒中に2回以上キーが押された場合は反応しない
ということなのかなと思った次第です。

△.
Keyはなにかしらのキーを押し続けてる間増え続けて
キーをはなすと0に戻るということじゃないのでしょうか?
例えばz、x、cキーを押し続けてる間Key[z,x,c]++が
whileループした分だけ加算されていく(この時他のKeyは0)
z、x、cキーをはなすとKey[z,x,c]は12,13行目のelse文中のkey0に戻るにより
Keyはすべて0になるのではと思ったのですが違うのでしょうか?

もし△の考え方があっていたら、
29行目の if( Key[KEY_INPUT_RIGHT] == 1 )
において、これはキーが長押しされても1度しかxは50しか動きませんということで
29行目が if( Key[KEY_INPUT_RIGHT] >= 1 )
ならば、キーがなが押しされていたらwhileがループした分だけxは50ずつ進む
ということですよね?

1.
[KEY_INPUT_○○○]には○○、[KEY_INPUT_×××]には××
というような感じで数字が決まっていて
[KEY_INPUT_RIGHT]が押下されたら500という数値をかえすとして
仮に[KEY_INPUT_RIGHT]がtmpKey[200]に格納されるとすると
tmpKey[200]==CheckHitKey[KEY_INPUT_RIGHT]
となっていて、→キーが押下された時に
tmpKey[200]=500
になるので
10行目の if( tmpKey != 0 )になるということでしょうか?

またこの時に
[200]==[KEY_INPUT_RIGHT]ということになっていて
10,11行目は
if( tmpKey[KEY_INPUT_RIGHT] != 0 )
Key[KEY_INPUT_RIGHT]++;
ということなのでしょうか?

Re: gpUpdateKey()についての質問です

Posted: 2011年11月13日(日) 08:37
by beatle
tepi さんが書きました:返信ありがとうございます!

「→キーが約1/60以上の感覚で押す」というのは、
ScreenFlip()でメモリの内容をフレッシュするタイミングが
ほとんどのPCが60Hzで1/60秒感覚で入れ替わっている
というようなことが書かれていたので
もしツールなどで1/60秒中に2回以上キーが押された場合は反応しない
ということなのかなと思った次第です。
なるほどなるほど。ScreenFlip()で60FPSに制限されている可能性があるわけですね。
もしそうなら、「1/60秒中に2回以上キーが押された場合は反応しない」というのは
おそらくその通りです。ただし、2回押したうちの1回は反応する可能性があります。
tepi さんが書きました:△.
Keyはなにかしらのキーを押し続けてる間増え続けて
キーをはなすと0に戻るということじゃないのでしょうか?

まさしくその通りです。

tepi さんが書きました:例えばz、x、cキーを押し続けてる間Key[z,x,c]++が
whileループした分だけ加算されていく(この時他のKeyは0)
z、x、cキーをはなすとKey[z,x,c]は12,13行目のelse文中のkey0に戻るにより
Keyはすべて0になるのではと思ったのですが違うのでしょうか?

これもその通りです。
言ってることは分かるのですが、できれば、もうちょっと正確に記述していただけませんか?
たとえば、Key[z,x,c]という書き方はC/C++では出来ません。Key[z], Key[x], Key[c]などと書きましょう。

僕は
beatle さんが書きました:それから
「1.whileの条件の中のgpUpdateKey()==0が呼び出されて、Keyの中身がすべて0になる。」
というのは、どのキーも押されていない場合に限って成り立ちます。
もし何かキーが押された状態でgpUpdateKey関数を呼び出すと、「Keyの中身がすべて0になる。」なんてことにはなりません。

と書いたのです。「どのキーも押されていない場合に限って成り立ちます」と書きました。
つまり、z, x, cキーを離せば「どのキーも押されていない」状態になりますから、Keyの中身は全部0になります。

tepi さんが書きました:もし△の考え方があっていたら、
29行目の if( Key[KEY_INPUT_RIGHT] == 1 )
において、これはキーが長押しされても1度しかxは50しか動きませんということで
29行目が if( Key[KEY_INPUT_RIGHT] >= 1 )
ならば、キーがなが押しされていたらwhileがループした分だけxは50ずつ進む
ということですよね?

その通りです。

tepi さんが書きました:1.
[KEY_INPUT_○○○]には○○、[KEY_INPUT_×××]には××
というような感じで数字が決まっていて
[KEY_INPUT_RIGHT]が押下されたら500という数値をかえすとして
仮に[KEY_INPUT_RIGHT]がtmpKey[200]に格納されるとすると
tmpKey[200]==CheckHitKey[KEY_INPUT_RIGHT]
となっていて、→キーが押下された時に
tmpKey[200]=500
になるので
10行目の if( tmpKey != 0 )になるということでしょうか?

ここからわけが分からなくなってきました。主に
tmpKey[200]==CheckHitKey[KEY_INPUT_RIGHT]

コレですね。CheckHitKeyというのはおそらくhttp://dixq.net/g/01_05.htmlで登場するキーの入力状態を調べる関数
のことだと思いますが、関数には添え字演算子を書けません。
以下では、「CheckHitKey[KEY_INPUT_RIGHT]」は「CheckHitKey(KEY_INPUT_RIGHT)」のことだと思って、説明を書きます。
まず、CheckHitKey関数の動作を上記URLで確認してください。同様にGetHitKeyStateAll関数の動作を
http://dixq.net/g/02_09.htmlで確認してください。確認すれば、tmpKey[200]に500が代入されるという
ことはあり得ないということが分かります。(それに、tmpKeyはcharの配列なので、最大値は127です)

tepi さんが書きました:またこの時に
[200]==[KEY_INPUT_RIGHT]ということになっていて
10,11行目は
if( tmpKey[KEY_INPUT_RIGHT] != 0 )
Key[KEY_INPUT_RIGHT]++;
ということなのでしょうか?

ココも意味が分かりません。C/C++では[200]や[KEY_INPUT_RIGHT]という書き方はできません。
いろいろ推測すれば解釈できなくもないのですが、誤った解釈をしたまま疑問に答えると、誤った答えになってしまうかもしれませんので、それが怖いのです。

tepiさんの疑問の全てには答えられていないと思います。まだ疑問に思うことがあれば、是非正確な質問文でお願いします。

Re: gpUpdateKey()についての質問です

Posted: 2011年11月13日(日) 15:35
by softya(ソフト屋)
「→キーが約1/60以上の感覚で押す」というのは、
ScreenFlip()でメモリの内容をフレッシュするタイミングが
ほとんどのPCが60Hzで1/60秒感覚で入れ替わっている
というようなことが書かれていたので
もしツールなどで1/60秒中に2回以上キーが押された場合は反応しない
ということなのかなと思った次第です。
人間の反応速度やスイッチの機械工学的に1/60秒未満の速度でON/OFFを繰り返す事は非常に困難ですので現実にはさほど気にしなくて良いと思います。
気になるなら実際に計測してみてください。
1.
[KEY_INPUT_○○○]には○○、[KEY_INPUT_×××]には××
というような感じで数字が決まっていて
[KEY_INPUT_RIGHT]が押下されたら500という数値をかえすとして
仮に[KEY_INPUT_RIGHT]がtmpKey[200]に格納されるとすると
tmpKey[200]==CheckHitKey[KEY_INPUT_RIGHT]
となっていて、→キーが押下された時に
tmpKey[200]=500
になるので
10行目の if( tmpKey != 0 )になるということでしょうか?


[KEY_INPUT_RIGHT]は配列の添字参照ですので、配列の番号を指し示すだけですね。[KEY_INPUT_RIGHT]と言うものがC言語の文法上で配列名とセットで扱わないと意味を持ちません。それとCheckHitKeyはbeatleさんの指摘されている通り関数であって配列ではありません。
と言うことで根本的な問題として、「KEY_INPUT_○○○には○○、KEY_INPUT_×××には××というような感じで数字が決まっていて」と話をしないと間違っていることになります。
なので、[KEY_INPUT_RIGHT]が500と言う数値を取ることはC言語の文法上有りません。key[KEY_INPUT_RIGHT]なら500になることはあります。
たぶん、GetHitKeyStateAll()関数の内部動作を推測されての話だと思いますが、tmpKey[キー番号]に各々格納される値は0か1です。これ以外の値は格納されません。
試しにprintfして見ることをお勧めします。

またこの時に
[200]==[KEY_INPUT_RIGHT]ということになっていて
10,11行目は
if( tmpKey[KEY_INPUT_RIGHT] != 0 )
Key[KEY_INPUT_RIGHT]++;
ということなのでしょうか?


KEY_INPUT_RIGHTが200だと仮定するとしてiが200だった場合は、
if( tmpKey[KEY_INPUT_RIGHT] != 0 )
Key[KEY_INPUT_RIGHT]++;
とやっていることと同義だと思ってもらって構いません。

Re: gpUpdateKey()についての質問です

Posted: 2011年11月18日(金) 21:50
by tepi
僕は
beatle さんが書きました:それから
「1.whileの条件の中のgpUpdateKey()==0が呼び出されて、Keyの中身がすべて0になる。」
というのは、どのキーも押されていない場合に限って成り立ちます。
もし何かキーが押された状態でgpUpdateKey関数を呼び出すと、「Keyの中身がすべて0になる。」なんてことにはなりません。
と書いたのです。「どのキーも押されていない場合に限って成り立ちます」と書きました。
つまり、z, x, cキーを離せば「どのキーも押されていない」状態になりますから、Keyの中身は全部0になります。

申し訳ないです!しっかりと理解していませんでした。
tepi さんが書きました:1.
[KEY_INPUT_○○○]には○○、[KEY_INPUT_×××]には××
というような感じで数字が決まっていて
[KEY_INPUT_RIGHT]が押下されたら500という数値をかえすとして
仮に[KEY_INPUT_RIGHT]がtmpKey[200]に格納されるとすると
tmpKey[200]==CheckHitKey[KEY_INPUT_RIGHT]
となっていて、→キーが押下された時に
tmpKey[200]=500
になるので
10行目の if( tmpKey != 0 )になるということでしょうか?

ここからわけが分からなくなってきました。主に
tmpKey[200]==CheckHitKey[KEY_INPUT_RIGHT]

コレですね。CheckHitKeyというのはおそらくhttp://dixq.net/g/01_05.htmlで登場するキーの入力状態を調べる関数
のことだと思いますが、関数には添え字演算子を書けません。
以下では、「CheckHitKey[KEY_INPUT_RIGHT]」は「CheckHitKey(KEY_INPUT_RIGHT)」のことだと思って、説明を書きます。
まず、CheckHitKey関数の動作を上記URLで確認してください。同様にGetHitKeyStateAll関数の動作を
http://dixq.net/g/02_09.htmlで確認してください。確認すれば、tmpKey[200]に500が代入されるという
ことはあり得ないということが分かります。(それに、tmpKeyはcharの配列なので、最大値は127です)

このあたりは全く見当違いな事を書いていました。


tepi さんが書きました:またこの時に
[200]==[KEY_INPUT_RIGHT]ということになっていて
10,11行目は
if( tmpKey[KEY_INPUT_RIGHT] != 0 )
Key[KEY_INPUT_RIGHT]++;
ということなのでしょうか?

ココも意味が分かりません。C/C++では[200]や[KEY_INPUT_RIGHT]という書き方はできません。
いろいろ推測すれば解釈できなくもないのですが、誤った解釈をしたまま疑問に答えると、誤った答えになってしまうかもしれませんので、それが怖いのです。

tepiさんの疑問の全てには答えられていないと思います。まだ疑問に思うことがあれば、是非正確な質問文でお願いします。[/quote]

GetHitKeyStateAll関数の動作をもう一度確認してみたら解決しました!
[200]==[KEY_INPUT_RIGHT]という事ではなくて、GetHitKeyStateAll関数が呼び出された時点で
→キーの入力の受付状態が始まっているという事で解決しました。

しばらく忙しくて返信が遅くなってしまって申し訳ありませんでした。

いろいろ教えてくださりとても助かりました!
ありがとうございました!

Re: gpUpdateKey()についての質問です

Posted: 2011年11月18日(金) 21:56
by tepi
人間の反応速度やスイッチの機械工学的に1/60秒未満の速度でON/OFFを繰り返す事は非常に困難ですので現実にはさほど気にしなくて良いと思います。
気になるなら実際に計測してみてください。

そうなんですね!勉強不足でした・・・。

[KEY_INPUT_RIGHT]は配列の添字参照ですので、配列の番号を指し示すだけですね。[KEY_INPUT_RIGHT]と言うものがC言語の文法上で配列名とセットで扱わないと意味を持ちません。それとCheckHitKeyはbeatleさんの指摘されている通り関数であって配列ではありません。
と言うことで根本的な問題として、「KEY_INPUT_○○○には○○、KEY_INPUT_×××には××というような感じで数字が決まっていて」と話をしないと間違っていることになります。
なので、[KEY_INPUT_RIGHT]が500と言う数値を取ることはC言語の文法上有りません。key[KEY_INPUT_RIGHT]なら500になることはあります。
たぶん、GetHitKeyStateAll()関数の内部動作を推測されての話だと思いますが、tmpKey[キー番号]に各々格納される値は0か1です。これ以外の値は格納されません。
試しにprintfして見ることをお勧めします。

0か1かの判定しかないということが分かりました!
GetHitKeyStateAll()関数について勘違いをしていました。

KEY_INPUT_RIGHTが200だと仮定するとしてiが200だった場合は、
if( tmpKey[KEY_INPUT_RIGHT] != 0 )
Key[KEY_INPUT_RIGHT]++;
とやっていることと同義だと思ってもらって構いません。

了解です。

忙しくて返信が遅くなってしまって申し訳ありませんでした。
関数について教えてくださり助かりました。
ありがとうございました!