ページ 11

キー入力の制御について

Posted: 2009年2月24日(火) 20:15
by はいかぜ
こんばんは。
現在、プログラミングの館を参考にしてゲームを作る基礎段階を勉強しているのものです。

一つのボタンで文字の表示、非表示を切り替えるようなプログラムを作りたいのですが上手く作れません。
ソースはこのようになっています。
#include "DxLib.h"
 
int Key[256];
 
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[/url]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key==1) GetHitKeyStateAll_InputKey++;
        else                            GetHitKeyStateAll_InputKey=0;
    }
    return 0;
}
 
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
    ChangeWindowMode(TRUE);//ウィンドウモード
    if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化

	int para,white;
	para=0;
	white=GetColor( 255 , 255 , 255 ) ;
 
    while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
          //↑メッセージ処理          ↑画面をクリア           ↑入力状態を保存       ↑ESCが押されていない
 
 
        //ココ!! 
 if(para==1)
		DrawFormatString(100,100, white , "ああああ");//文字列表示

		if(Key[ KEY_INPUT_A]	==1	&&	para==0){
			para=1;
		}

		if(Key[ KEY_INPUT_A]	==1	&&	para==1){
			para=0;
		}
 
 
        ScreenFlip();
    }
 
    DxLib_End();
    return 0;
}


このソースで動かすと何も反応がないように見えます。
また、過去ログのNo:18003に似たような症状に思えるものの解決策があったのですが…
その示されていた解決策である

1:次のページに移動するボタンと元のページに戻るボタンを別のものにする

2:ページを移動した後、しばらく全ての入力を受け付けないようにする

3:ボタンの押しっ放しを無効にする

のうち、1番は上手くできました。
しかし、やはり同じボタンで制御したいので2番か3番の方を試してみたいと思ったのですがどのように制御したらよいのかが分かりません。
または、他の方法があるのでしょうか?

どなたかアドバイスしていただけないでしょうか。
よろしくお願いします。

環境は
OS:Windows XP sp3
コンパイラ:コンパイラ名 : VC++ 2008EE
です。

Re:キー入力の制御について

Posted: 2009年2月24日(火) 20:58
by kazuoni
とりあえず題意を満たしたいなら、
if(Key[ KEY_INPUT_A]==1	&& para==0)
{

	para=1;

}

else if(Key[ KEY_INPUT_A]==1 && para==1)
{

	para=0;

}
としてください。
3はすでに解決しています。
GetHitKeyStateAll_2()は押している間ずっとインクリメントしています。
なのでKey[/url]==1としたら、押された瞬間を指しています。

>ページを移動した後、しばらく全ての入力を受け付けないようにする
これは確かに必要かも知れません。
ただ、例えば
メニュー画面

セーブ画面
と変化するときを考えます。
メニュー画面で[A]を押して次に移動とします。
押しっぱなしでもすぐに一番上のセーブデータをロードすることはありません。
さっきもいいましたが、Key[/url]はずっとインクリメントされています。
なので、Key[/url]==1としておけば大丈夫です。

もし本当にこの機能を実装するならば、
GetHitKeyStateAll_2()をメインループの条件で呼び出しますので
実行後にすべてをゼロセットするがよいかなっと思います。
(ちょっと無駄が多いかもしれないですけど・・・)

Re:キー入力の制御について

Posted: 2009年2月24日(火) 21:01
by Mato
  ソースを動かしてみずに発言しているので、間違っていたらすいません。


 このソースでは、いくらAを押しても、paraは1になりえません。
正確に言いますと、
para = 1
と代入した直後に、
para = 0
が実行されるので、ほんの一瞬だけ、1になっていますが。


 何故そうなってしまうかということについては、ソース内にコメントを埋めて説明したいと思います。
#Key[ KEY_INPUT_A]が1だとする(キーボードのAを押した直後)


#最初はparaが0なので、2つの条件を満たす
		if(Key[ KEY_INPUT_A]	==1	&&	para==0){
#paraが1になる
			para=1;

		}


#paraが1になったので、2条件を満たす
		if(Key[ KEY_INPUT_A]	==1	&&	para==1){
#paraが0になる
			para=0;

		}
という具合です。

Re:キー入力の制御について

Posted: 2009年2月24日(火) 21:12
by Mato
>もし本当にこの機能を実装するならば、
GetHitKeyStateAll_2()をメインループの条件で呼び出しますので
実行後にすべてをゼロセットするがよいかなっと思います。
(ちょっと無駄が多いかもしれないですけど・・・)


 ゼロセットとは、Key[/url]の値のことでしょうか。
これらを0にすると、またKey[KEY_INPUT_A]の値が1になりかねないのでは……。

 ですので、そういう場合では、メニュー→セーブの流れを1ループ内で納めなければKey[KEY_INPUT_A]==1という条件にしておけば、連続しないと思います。



 何か見当違いなこと言ってたらすいません。

Re:キー入力の制御について

Posted: 2009年2月24日(火) 21:28
by kazuoni
>これらを0にすると、またKey[KEY_INPUT_A]の値が1になりかねないのでは……。

自分の意図がうまく説明できていませんでした。。

例えばメニュー→縦シューティングゲームスタート
とします。そしてメニュー選択キーとショット発射キーが同じだったとします。
自機ショット発射が
if(Key[...]>=1)
で制御されているとしたら、メニュー移行押し続ければ、
いきなりショットが始まります。
これがボムキーだったら敵もいない画面でボム使ってしまいます。
(まぁ、こんな処理ないかと思いますけど・・・)
なのでちょっとの間キー無効にすればそんな心配もありません。
(ボムキーだけ無効でもいいかも知れませんが・・・。)
これを実装するには
GetHitKeyStateAll_2()
で各キーに監査の値代入後、
ゼロセットすれば、ループが戻ってくるまでKey[/url]のすべての値は0です。

こんなことを言いたかったんです^^;言葉不足で大変失礼しました。。

Re:キー入力の制御について

Posted: 2009年2月24日(火) 21:34
by Mato
 なるほど、分かりました。
変にツッコミ入れてすいません……。

Re:キー入力の制御について

Posted: 2009年2月24日(火) 22:29
by はいかぜ
回答してくださった皆様方
ありがとうございました。
こんなにも早く答えていただいて感激です。
また、質問に来ると思いますがそのときもよろしくお願いします。

kazuoniさん
ご指摘の通りにソースを書き直したら、無事に目的にたどり着けました。
else文を使うことは思いつかなかったです^^;
普段、学校で行うプログラミングにelse文を滅多に使わないのでその存在を忘れかけていました。
勉強不足が堪えます。

疑問点が解決した後で恐縮なのですが…
>実行後にすべてをゼロセットする
GetHitKeyStateAll_2()を
int GetHitKeyStateAll_2(int GetHitKeyStateAll_InputKey[/url]){
    char GetHitKeyStateAll_Key[256];
    GetHitKeyStateAll( GetHitKeyStateAll_Key );
    for(int i=0;i<256;i++){
        if(GetHitKeyStateAll_Key==1) GetHitKeyStateAll_InputKey++;
        else                            GetHitKeyStateAll_InputKey=0;
    }
	GetHitKeyStateAll_InputKey=0; //ここを追加
    return 0;
}


というようにすればよいということなのでしょうか?


Matoさん
よく分かりました。
ソースの
if(Key[ KEY_INPUT_A]	==1	&&	para==1){

			para=0;

		}

の部分を

if(Key[ KEY_INPUT_A]	==500	&&	para==1){

			para=0;

		}


としたところ…
一回目のAを押した後、しばらく押しっぱなしにすることで文字が消えました。
というわけですから、おっしゃっていたことは間違いなかったと思います。

Re:キー入力の制御について

Posted: 2009年2月24日(火) 22:47
by kazuoni
>実行後にすべてをゼロセットする
>GetHitKeyStateAll_InputKey=0

GetHitKeyStateAll_InputKeyとはなんでしょうか?
少なくとも、DxLib.hには宣言されていませんでしたが・・・?

ゼロセットはキー監査の関数には書かないほうが良い気がします。
基本的には
for(i=0;i<256;++i)
   Key=0;

を関数化して、最初に呼び出されてから数十or数百ループの間はこの関数に入る
で良いと思います。
が、果たして、これが現時点で必要なのかどうか考えてみてください。
おそらく現時点では必要ない気がしますが・・・。

Re:キー入力の制御について

Posted: 2009年2月24日(火) 23:09
by はいかぜ
>GetHitKeyStateAll_InputKeyとはなんでしょうか?
int GetHitKeyStateAll_2()の引数がint GetHitKeyStateAll_InputKey[/url]になっていたので、
最初はGetHitKeyStateAll_InputKey[/url]=0というように書いたのですが…
そしたら「]」が不適切というようなエラーが起きたので「[]」を消してみたら実行できたので、
それをそのまま書いただけでした^^;
確認もせずに質問してしまって申し訳ないです。

仰るとおり現状では、このようなことはする必要はないと思います。
ただ、後ほど必要になったときになんらかの助けになるのではないかと思い、
少し浮かんだ疑問点を質問してみたところでした。

このような質問にも、丁寧にお答えいただきありがとうございました。

Re:キー入力の制御について

Posted: 2009年2月24日(火) 23:57
by kazuoni
>GetHitKeyStateAll_InputKey=0;
これはとても危険かと^^;
Keyのアドレスが書き変わってしまいます。
ポインタ、文字列等復習をしてみてください。
memset()という関数もありますので、調べてみてください。

Re:キー入力の制御について

Posted: 2009年2月25日(水) 00:21
by はいかぜ
>ポインタ、文字列等復習をしてみてください。
>memset()という関数もありますので、調べてみてください。
了解です。
気長に学んでいくとします^^
アドバイスありがとうございました。