つい一ヶ月程前に勉強を始めたプログラム初心者です。
現在、ゲームプログラミングについて学んでいるのですが、メニュー画面のカーソル移動処理で少し困っています。
キー入力に応じてカーソルを移動させる事は出来るのですが、一回のキー入力でカーソルが一気に動いてしまい、制御が出来ない状態になっています。
※一度下キーを押すと一気に次の処理まで行われてカーソルが荒ぶるような状態です。
キー入力後の処理にワンクッション置く事が出来れば解決するんでしょうけど、どのようにすればいいのかわかりません・・・。
自分でも調べてみたのですが、調べ方が悪いのか自分の求めている答えが出てきませんでした。
文章だけではわからないかと思いますのでプログラムを載せておきます(練習用に組んだものなのでファイル分けはしていません)。
自力で修正しつつのプログラムをそのまま貼り付けたのでカーソルが一番下にある時の処理は消えたままになっていますが、上にあるものと同じ事を書いていました。
#include "DxLib.h"
~中略~
int se_cursor; // カーソル移動時用SE
int se_enter; // 決定時SE
int Green = GetColor( 0, 255, 0 );
int White = GetColor( 255, 255, 255 );
int Cursor = 0;
int CursorX = 190; //カーソルのX座標
int CursorY = 300; //カーソルのY座標
se_cursor = LoadSoundMem("SE/se_maoudamashii_system35.wav"); // SEフォルダからSEをロード
se_enter = LoadSoundMem("SE/nc23432.wav");
enum{
TITLE,
GAME,
RESULT
}status=TITLE;
char key[256];
while(Process(key)){
switch(status){
case TITLE:
SetFontSize( 40 );
SetFontThickness( 8 );
ChangeFont( "HGS創英角ポップ体");
ChangeFontType( DX_FONTTYPE_ANTIALIASING_EDGE );
DrawFormatString( 250, 150, Green, "テスト"); // 文字を描画する
SetFontSize( 30 );
SetFontThickness( 1 );
ChangeFont( "ぷちくまふぉんと");
DrawFormatString( 220, 300, White, "はじめから");
DrawFormatString( 220, 340, White, "つづきから");
DrawFormatString( 250, 380, White, "おわる");
DrawFormatString( CursorX, CursorY, White, "→");
if(CursorY == 300){
if(key[KEY_INPUT_Z]==1){
PlaySoundMem( se_enter, DX_PLAYTYPE_BACK );
status=GAME;
}else if(key[KEY_INPUT_DOWN]==1){
PlaySoundMem( se_cursor, DX_PLAYTYPE_BACK ); //SEを再生する
CursorY=340;
}else if(key[KEY_INPUT_UP]==1){
PlaySoundMem( se_cursor, DX_PLAYTYPE_BACK ); //SEを再生する
CursorY=380;
}
}
if(CursorY == 340){
if(key[KEY_INPUT_Z]==1){
PlaySoundMem( se_enter, DX_PLAYTYPE_BACK );
status=GAME;
}else if(key[KEY_INPUT_DOWN]==1){
PlaySoundMem( se_cursor, DX_PLAYTYPE_BACK );
CursorY=380;
}else if(key[KEY_INPUT_UP]==1){
PlaySoundMem( se_cursor, DX_PLAYTYPE_BACK );
CursorY=300;
}
}
break;
case GAME:
SetFontSize( 50 ); // フォントサイズ
SetFontThickness( 8 ); // 太さ
ChangeFont( "HGS創英角ポップ体"); // フォント名
ChangeFontType( DX_FONTTYPE_ANTIALIASING_EDGE );
DrawFormatString( 0, 18, Green, "Xキーを押すとシーン移行します。"); // 文字を描画する
if(key[KEY_INPUT_X]==1){
status=RESULT;
}
break;
case RESULT:
DrawFormatString( 0, 18, Green, "Cキーを押すとシーン移行します。");
if(key[KEY_INPUT_C]==1){
status=TITLE; //テスト用なのでTITLEに戻してループさせる
}
break;
}
}
SetDrawScreen( DX_SCREEN_BACK ) ;
~以下省略~
長くなって申し訳ありませんが宜しくお願い致します。
A 回答 (4件)
- 最新から表示
- 回答順に表示
No.4
- 回答日時:
ああ、ちなみにPCのキーボードで発生するかは不明ですが、
チャタリングという現象もある機能性がありますので、適度なSleep()は必要かと思われます。
私がゲームのスクリプトで作っていた時には
「キーを押して、離した時に反応」するようにしていましたけどね。
(key[KEY_INPUT_Z]==0 && oldkey[KEY_INPUT_Z]==1)
のような条件式に。
マウスのボタンだと「押して離した時に反応」でいいのですが、キーボードだと「押された時(キーリピートの為?)」というのが、Windowsで一般的なインターフェースっつぽいですけどね。
(ダイアログのボタンなどにフォーカスがあった時の動作…とかね。)
何度も解答ありがとうございます。
なるほど、キーを離した時に反応ですか、それなら確かに今までのようにカーソルが荒ぶるという事は無くなりそうですね。
現在多忙のためにまだ試してはいませんが・・・。
一つ前の解答のプログラムも見せて頂きましたが、わかりやすく注釈まで入れて頂いて嬉しい限りです。
これからも頑張って勉強していきます、解答ありがとうございました。
No.3
- 回答日時:
>現状ではこのようなプログラムになっているのですが、Sleep以外で遅延を発生させる手段はあるのですかね?
>何度も質問申し訳ありません・・・。
char key[256];
が何のための配列なのか?
というのが不明ですが、
キーが押下されていると1が設定される。というものであれば、
「押して」「離した」というのをチェックするようにすればいいでしょう。
配列2つ用意して、ループの最後で「前回の値を保持」して、片方が離された状態、もう片方が押された状態という時にメニュー項目の移動を処理する。とかですね。
# キーリピートでどういう動作するか確認は必要かと思われますけども。
char oldkey[256];
を用意して……
while(Process(key)){
switch(status) {
case TITLE:
:
if(key[KEY_INPUT_Z]==1 && oldkey[KEY_INPUT_Z]==0) {
PlaySoundMem( se_enter, DX_PLAYTYPE_BACK );
switch(CursorY) {
case 300:status=GAME;break;
case 340:status=GAME;break; // 続きからのステータスに
case 380:status=GAME;break; // 終わるのステータスに
}
// メニュー決定なので、必要であればループから抜けるように制御する
} else if(key[KEY_INPUT_DOWN]==1 && oldkey[KEY_INPUT_DOWN]==0) {
PlaySoundMem( se_cursor, DX_PLAYTYPE_BACK );
CursorY = ((((CursorY - 300) / 40) + 1) % 3) * 40 + 300;
// CursorYから300引くと0・40・80のいずれかの値になり、それを40で割ると0から2になる。
// +1してから3の剰余算で1つ繰り上がった値になる。(0なら1、1なら2、2なら0)
// その結果に40を掛けて、最初に引いた300を加える事で
// 300→340→380→300とループするようになる
} else if(key[KEY_INPUT_UP]==1 && oldkey[KEY_INPUT_UP]==0) {
PlaySoundMem( se_cursor, DX_PLAYTYPE_BACK );
CursorY = ((((CursorY - 300) / 40) + 2) % 3) * 40 + 300;
// 上記と似たような計算。(+2してから3で剰余算する段階でどういう値の遷移するか考えてみてくださいな)
// 380→340→300→380とループする
// ちなみに、CursorYの値を直接変更するのではなく他の変数でメニュー項目の番号を0~2で持ち、
// カーソル表示の際に座標演算を行う。という方法を私なら採りますね。
}
break;
case GAME:
:
}
memcpy(oldkey, key, sizeof(key));
}
こんな感じですかね。
GetKeyboardState()がBYTE配列で256個の要素を必要とする……ようですが、
こちらはキーの押下状態は最上位ビットのようですしねぇ……。
No.2
- 回答日時:
なんかいろいろと混乱されているようですが…
ステップ実行で追いかけてみてください。
その上で、意図した動作をしているか確認してください。
プログラムコードは書かれたとおりにしか動作しませんし。
解決・・・とは少し違いますが先日頂いた解答を参考に一度プログラムを組み、間にSleep(90)の記述をする事によりカーソルが荒ぶる事は無くなりました。
現状ではこのようなプログラムになっているのですが、Sleep以外で遅延を発生させる手段はあるのですかね?
何度も質問申し訳ありません・・・。
if(key[KEY_INPUT_ESCAPE]==1){
status=END;
}
if(CursorY == 300){
if(key[KEY_INPUT_Z]==1){
PlaySoundMem( se_enter, DX_PLAYTYPE_BACK );
status=GAME;
}else if(key[KEY_INPUT_DOWN]==1){
PlaySoundMem( se_cursor, DX_PLAYTYPE_BACK ); //SEを再生する
Cursory=340;
Sleep(90);
}else if(key[KEY_INPUT_UP]==1){
PlaySoundMem( se_cursor, DX_PLAYTYPE_BACK ); //SEを再生する
CursorY=380;
Sleep(90);
}
}else if(CursorY == 340){
if(key[KEY_INPUT_Z]==1){
PlaySoundMem( se_enter, DX_PLAYTYPE_BACK );
status=GAME;
}else if(key[KEY_INPUT_DOWN]==1){
PlaySoundMem( se_cursor, DX_PLAYTYPE_BACK );
CursorY=380;
Sleep(90);
}else if(key[KEY_INPUT_UP]==1){
PlaySoundMem( se_cursor, DX_PLAYTYPE_BACK );
CursorY=300;
Sleep(90);
}
}
No.1
- 回答日時:
細かく追っていませんが…
>if(CursorY == 300){
> :
>}
の中でCursorYが340になったあと、
次の条件判定である、
>if(CursorY == 340){
を、素通りできるでしょうか?
if(CursorY == 300){
}
if(CursorY == 340){
}
と
if(CursorY == 300){
} eles if(CursorY == 340){
}
の違いは判りますか?
解答ありがとうございます、要するにキーを押して座標が変動した瞬間に次の処理を行おうとしているので、if(CursorY == 300){
}else if(CursorY == 340){
}
の処理を挟む事で一度のキー押下で次の処理を行わないようにするという解釈で良いのですかね?
少しわかりづらいかもしれません、説明下手ですみません・・・。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PHP PHPのエラーの解消法について教えて下さい。 1 2023/02/06 10:48
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- PHP PHPで画像の渡しが上手く行きません。 1 2023/02/02 09:39
- PHP php テーブルが作成できない 1 2022/11/17 23:41
- MySQL php テーブルを作れない 2 2022/11/17 18:22
- PHP php エラー 2 2022/10/23 16:43
- Excel(エクセル) PHPプログラムをエクセルに張り付けると検索ボックスがでてくる! 3 2022/05/08 07:10
- PHP PHPでユーザー情報を入力して簡易ログイン機能をつくってみたのですが 1 2023/05/29 08:51
- Visual Basic(VBA) VBAコードが作動せず、どこに問題があるのか教えて下さい。 3 2023/06/13 13:20
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
break文でループを一気に抜ける...
-
ループを途中で抜けたいのですが。
-
do-while文が禁止される理由
-
入力した文字列から母音だけを...
-
桁数を求めるプログラム。
-
if文の中にfor文なのか、for文...
-
C言語forループが完結した場合...
-
C言語のwhile()文での大括弧の...
-
Delphiで・・・
-
他言語で言うcontinue文
-
Cプログラムが終了しない
-
新たな疑問 for( ; ; ){
-
「指定されたキャストは有効で...
-
Enterキーを押されたら次の処理...
-
2曲同時再生するにはどうした...
-
Aの値からBの値を除するとは??
-
C言語での引数の省略方法
-
数字以外が入力されたらエラー...
-
数字列を3桁ごとにカンマで区切...
-
10個出力で改行したいのですが...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
break文でループを一気に抜ける...
-
ループを途中で抜けたいのですが。
-
do-while文が禁止される理由
-
入力した数値を倍々するプログラム
-
For文の終了値を関数にしても問...
-
C言語forループが完結した場合...
-
エクセルVBAで Do While (1)って?
-
入力した文字列から母音だけを...
-
if文の中にfor文なのか、for文...
-
Excel VBAで年度をまたぐ期間の...
-
C言語、whileループを抜け出す...
-
for文while文の無限ループの違...
-
プログラムで関数は使わない方...
-
Cプログラムが終了しない
-
PIC のプログラムについて ど...
-
アルゴリズムです!四つの数字...
-
UWSCにてある一定の動作を無限...
-
繰り返し文の利点について
-
ループの特定入力終了
-
PAD図の書き方
おすすめ情報
解答ありがとうございます、要するにキーを押して座標が変動した瞬間に次の処理を行おうとしているので、if(CursorY == 300){
}else if(CursorY == 340{
}
の処理を挟む事で一度のキー押下で次の処理を行わないようにするという解釈で良いのですかね?
少しわかりづらいかもしれません、説明下手ですみません・・・。
~追記~
申し訳ありません、少し解釈が間違っていたようです。
if(CursorY == 300){
}else if(CursorY == 340{
}
カーソル移動処理を個別に分けるのでは無く、この間に全ての処理を入れるという事でよろしいでしょうか?
何度も申し訳ありません・・・。