ページ 1 / 1
DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月09日(水) 20:59
by KEYONN
お久しぶりです。KEYONNです。DXLIB依存ですが、ジョイパッドでの方向キーの連打によって
ダッシュする仕組みというか、連打をどうやって判定するかが知りたいです。連打というのは、
ここでは、2回カチッカチッと押す感じの事を指します。
とりあえず、キーボードでも動作させる為に、関数を作ったのですが、それは上手くいきました様子?
です。というのは、プリントデバッグみたいに、関数の戻り値を元にフラグを立てて
DrawFormatStringで"KEY OK!!"みたいに表示させる事が出来たので、恐らく上手くいっていると
思われます。
その関数を書きます。
コード:
int CheckContinuePressing(int key)
{
static int presstime[2]={0};
static int prevkey=0;
if(!prevkey && CheckHitKey(key))//キーが押された瞬間なら
{
static int i=0;//カウント変数
presstime[i]=GetTickCount();//今の時間が知りたい(ミリ秒単位で)
++i;//カウントする
if(i==2)//iが2なら
{
if(presstime[1]-presstime[0]<=0.35*1000)//2つの時間差が0.35秒より小さければ
{
i=0;//iを0にする
presstime[0]=0;//presstime[]を2つとも0にしておく
presstime[1]=0;
return 1; //1を返す
}else{
i=0;//iを0にする
presstime[0]=0;//presstime[]を2つとも0にしておく
presstime[1]=0;
return 0; //0を返す
}
}
}
prevkey=CheckHitKey(key);//今のフレームのキー入力を保存して、
//後のキー入力判定のとき使う
return 0;
}
しかし、何故か、ジョイパッドでは上手くいかないので、ここで質問させてもらいました。
ジョイパッドの判定関数はこちらです。どうすれば、うまく判定できるでしょうか?
教えてください。お願いします。
コード:
int CheckContinueJoyStick(int joytype,int joybotton)
{
int p1;//p1は、ジョイパッドのタイプによって受け取る値が違う
if(joytype==0)
p1=GetJoypadInputState(DX_INPUT_KEY_PAD1) ;//joytypeが0ならjoypad1を
else
p1=GetJoypadInputState(DX_INPUT_PAD2) ;//joytypeが0以外ならjoypad2を
static int presstime[2]={0};//押した時間を計測するための変数
static int prevkey=0;//前のパッド入力を判定させるもの
if(!prevkey && (p1 & joybotton))//押した瞬間ならば
{
static int i=0;//カウント変数
presstime[i]=GetTickCount();//押した時間をミリ秒単位で取得
++i;//押されたならカウントする
if(i==2)//i==2なら
{
if(presstime[1]-presstime[0]<=0.35*1000)//0.35秒以下なら
{
i=0;
presstime[0]=0;
presstime[1]=0;
return 1;//1を返す
}else{
i=0;
presstime[0]=0;
presstime[1]=0;
return 0;//それ以外なら0を返す
}
}
}
prevkey=p1 & joybotton;
return 0;
}
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月09日(水) 21:16
by h2so5
もっと沢山DrawFormatStringを埋め込んで問題の切り分けを行いましょう。
ジョイパッドでボタンの押下状態はちゃんと検出できているのか、
検出きていることが確認できたとして、連打した時の時間差の値はどうなっているか確かめてください。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月09日(水) 21:53
by KEYONN
//もっと沢山DrawFormatStringを埋め込んで問題の切り分けを行いましょう。
//ジョイパッドでボタンの押下状態はちゃんと検出できているのか、
//検出きていることが確認できたとして、連打した時の時間差の値はどうなっているか確かめてください。
DrawFormatStringを埋め込みにくいのは、3Dアクションゲームでフレームスキップを行うために
描画処理と更新処理を分離しているからです。現段階では、関数Draw()内に全てその中に含めて自作関数や
DXライブラリの関数などが入っています。という訳でデバッグ中です。
しばらく待ってて下さい。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月09日(水) 21:55
by みけCAT
どうしても描画と計算を分けなければいけないといった宗教上の理由がなければ、printfDxを使ってみてはいかがですか?
DrawFormatStringなどの描画とは(多分)独立して描画されるはずです。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月09日(水) 22:16
by KEYONN
//どうしても描画と計算を分けなければいけないといった宗教上の理由がなければ、
//printfDxを使ってみてはいかがですか?
//DrawFormatStringなどの描画とは(多分)独立して描画されるはずです。
ありがとうございます。おかげで、関数内部からプリントデバッグできました。
どうやら、presstime[0]に代入されないみたいです。何故かはまだ分かりませんが。。。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月09日(水) 22:38
by KEYONN
コード:
int CheckContinueJoyStick(int joytype,int joybotton)
{
int p1;//p1は、ジョイパッドのタイプによって受け取る値が違う
if(joytype==0)
p1=GetJoypadInputState(DX_INPUT_KEY_PAD1) ;//joytypeが0ならjoypad1を
else
p1=GetJoypadInputState(DX_INPUT_PAD2) ;//joytypeが0以外ならjoypad2を
static int presstime[2]={0};//押した時間を計測するための変数
static int prevkey=0;//前のパッド入力を判定させるもの
if(!prevkey && (p1 & joybotton))//押した瞬間ならば
{
static int i=0;//カウント変数
presstime[i]=GetTickCount();//押した時間をミリ秒単位で取得
printfDx("presstime[0]=%d:presstime[1]=%d",presstime[0],presstime[1]);
if(i==2)//i==2なら
{
if(presstime[1]-presstime[0]<=0.35*1000)//0.35秒以下なら
{
i=0;
presstime[0]=0;
presstime[1]=0;
return 1;//1を返す
}else{
i=0;
presstime[0]=0;
presstime[1]=0;
return 0;//それ以外なら0を返す
}
}
++i;//押されたならカウントする
}
prevkey=p1 & joybotton;
return 0;
}
これで、プリントデバッグしてみたのですが、うまく行く時といかない時があるみたいです。
うまくいかない時とは、presstime[0]に値が代入されない時のことです。
そもそも、GetTickCount()とはどういう関数か覚えていないので、
MSDNライブラリや他のサイトで見てみます。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月09日(水) 22:44
by KEYONN
MSDNライブラリで見た限り、このジョイパッドプログラムに関してはGetTickCount()を知って
成果はありませんでした。WINDOWSが起動したか、プログラムが起動したときに
タイマーが始まると思っていたのですが、WINDOWSが起動した時からのようです。
[追記]戻り値がDWORDでした。もしかすると、ここに問題点があったのかもしれないです。
戻り値に代入していたのは、intでしたから、そこに問題点があったの可能性はあります。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月09日(水) 22:53
by みけCAT
GetTickCountの精度が問題かもしれません。
DXライブラリのGetNowCount関数を使ってみてください。
【訂正】関係ありません。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月09日(水) 22:56
by みけCAT
キー入力版とジョイスティック入力版では、++i;の位置が異なっていますね。
この影響で、キーを3回押さないといけない上、アクセス違反もしくはメモリ破壊の危険があります。
【追記】デバッグしていない方の関数での++i;の位置は一致しているのですが・・・
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月10日(木) 01:02
by ISLe
1回ボタンを押し(A)て、しばらく離して、連打(B,C)した場合、連打を認識しないと思います。
Bの押下で、AとBの間隔を取って連打ではないと判断します。
その際、記録はリセットされ、Bの情報は捨てられます。
Cの押下は単体と見なされます。
常に直前の押下情報と比較して、常に直前の押下情報を記録するだけで良いのではないでしょうか。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月10日(木) 09:19
by naohiro19
本当の連射は ボタン押し→入力無し→ボタン押し→入力無し ... ですね。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月10日(木) 17:17
by KEYONN
やっと実装できました。が、実際のダッシュの実装は加速度をつければいいだけだから、自明です。
書籍のソースコードを参考にしたので、アルゴリズムだけ書いておきます。誰かの役に立てばいいです。
コード:
int CheckContinueJoyStick(int ジョイスティックのタイプ,int 方向)
{
//Direction ////0--up 1--down 2--left 3--right
int p1,p2;//p1は、ジョイパッドのタイプによって受け取る値が違う
p1=GetJoypadInputState(DX_INPUT_KEY_PAD1) ;//joytypeが0ならjoypad1
p2=GetJoypadInputState(DX_INPUT_PAD2) ;//joytypeが0以外ならjoypad2を
static int 押した時間の配列[2][4]={0};//押した時間を計測するための変数
static int 前のフレームの配列[2][4]={0};//前のフレームを判定するための変数
const int 待てるフレーム数=120;//待てるフレーム数(ここはFPSや実行速度や変動フレームを用いている場合は調整する必要あり
if(ジョイスティックのタイプ==0)
{//joypad1を取得
//printfDx("OK!!");
if(方向==0)//方向0は上方向
{
if(!前のフレームの配列[0][0] && (p1 &(PAD_INPUT_UP)))
{//押した瞬間なら
if(押した時間の配列[0][0]!=0)
{
printfDx("[UP OK1]");
return 1;
}else{
押した時間の配列[0][0]=待てるフレーム数;
}
}
前のフレームの配列[0][0]=(p1 & (PAD_INPUT_UP));
}
if(方向==1)//方向1は下方向
{
…方向別の同様にやる
}
for(int i=0;i<4;i++)
{
for(int j=0;j<2;j++)
{
if(押した時間[j][i]!=0)//押した時間が0じゃないのなら
押した時間[j][i]--;//押した時間をデクリメント
}
}
return 0;
}
みなさんのおかげで作る事が出来て良かったです。ありがとうございます。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月11日(金) 00:02
by ISLe
方向別に処理が分かれているので、例えば、上に入力していて、そこから120フレーム以内にスティックを一回転させると上にダッシュすると思いますが、想定された動作でしょうか。
上に入力していて、左右どちらかに振って戻した場合もダッシュすると思います。
誤操作を頻発しそうな気がします。
同じ組み合わせの方向キーを、一定時間内に、ニュートラルを挟んで2回押したことを検出する、という条件であればもっとシンプルに表現できると思います。
同じ組み合わせの方向キーという形で検出することで斜めダッシュも可能です。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月12日(土) 20:17
by KEYONN
#同じ組み合わせの方向キーを、一定時間内に、ニュートラルを挟んで2回押したことを検出する、
#という条件であればもっとシンプルに表現できると思います
ニュートラルというのは、何も押していない状態ですよね?
それは、つまり、DXLIBにおいて、ジョイパッドの全てのボタンが何も押されていない状態なのか、
方向キーが何も押されていない状態なのか、どちらなのでしょうか?
一定時間内に2回というのは、おそらく実装できると思いますが、上のニュートラルの意味が少し分かりづらい
ので質問させてもらいました。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月12日(土) 20:27
by KEYONN
この文字列を見て気付いた事があります。
おそらくIsleさんはテーブルを使って判定すれば効率化するという事を言いたかったのではないかと
。
int keytable[4]={PAD_INPUT_UP,PAD_INPUT_DOWN,PAD_INPUT_LEFT,PAD_INPUT_RIGHT};
これで、テーブル化できました。あとは、for文なり、while文なりで、ループで読めば良さ気ですね。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月12日(土) 21:17
by ISLe
ニュートラルというのは、ゲームパッドあるいはゲーム筐体のスティックに触れていないとき中央にある状態をイメージしています。
なので、方向キーがいずれも押されていない状態ということになります。
方向を示すビットだけをマスクして取り出し、それが一致するかどうかを判定すれば良いので、ループもテーブルも必要ありません。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月12日(土) 22:01
by KEYONN
≪余談≫
この関数には秘密があります。
実はこの関数は返される値の各ビットが各ボタンに対応していて最大で 28個のボタンの状態を調べることが出来ます。
各ビットの構成は以下のようになっています。
ビットが1になっていれば押されていることを示し、0の場合はおされて いないことを示しています。
(MSB)上位ビット (LSB)下位ビット
BBBBBBBBBBBBBBBBBBBBBBBBBBBBURLD
D・L・R・U:それぞれ方向キー下・左・右・上 B:ボタン
つまり下ボタンの状態を知りたい場合は
int DownState ;
int InputState ;
InputState = GetJoypadInputState( DX_INPUT_PAD1 ) ;
DownState = InputState & 1 ;
とDXライブラリのリファレンスにあるので、
コード:
int GetNeutralState(int p1)
{
if(p1 & 1)
{
return 0;
}else if(p1 & 2)
{
return 0;
}else if(p1 & 4)
{
return 0;
}else if(p1 & 8)
{
return 0;
}else{
return 1;
}
return 0;
}
これで、ニュートラルかどうか分かると思いますし、確認しました。
あとは、一定時間内にニュートラルをはさんで同じ方向キーが2回押したか調べればいいだけですね。
とりあえず、やってみます。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月12日(土) 22:59
by KEYONN
フローチャートはこんな感じになったのですが、多分間違ってますね。
一定時間の時間の概念が無いので。。。
もう一回作ってみます。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月12日(土) 23:04
by ISLe
KEYONN さんが書きました:これで、ニュートラルかどうか分かると思いますし、確認しました。
こういう書き方もできます。
コード:
int GetNeutralState(int p1)
{
const int MASK = PAD_INPUT_UP|PAD_INPUT_DOWN|PAD_INPUT_LEFT|PAD_INPUT_RIGHT;
return (p1 & MASK) == 0;
}
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月13日(日) 12:22
by KEYONN
コード:
int CheckJoyStickPlayer1(int Dir,int FrameTime)
{
//同じ組み合わせの方向キーを、一定時間内に、
//ニュートラルを挟んで2回押したことを検出する、
//という条件であればもっとシンプルに表現できると思います。
int p1;
int dir[4]={8,1,2,4};
p1=GetJoypadInputState(DX_INPUT_KEY_PAD1) ;//joytypeが0ならjoypad1
static int keytime[4]={0};
static int prevbotton[4]={0};
static int i=0;
static int NeutralFlag[4]={0};
if(prevbotton[Dir] && (p1 & dir[Dir]))
{
if(keytime[Dir]!=0 && NeutralFlag[Dir]==1)//キータイムが0じゃなくて、
//ニュートラルフラグが立っているなら
{
printfDx("ありえるのか?");
NeutralFlag[Dir]=0;//リセット
keytime[Dir]=0;
prevbotton[Dir]=0;
return 1;
}else{
keytime[Dir]=FrameTime;//keytimeにFrameTimeを代入
}
}
if(keytime[Dir]!=0)//keytimeが0じゃなければ
{
if(GetNeutralState(p1))//ニュートラルがあるなら
{
NeutralFlag[Dir]=1;//ニュートラルフラグに1を
}
}
prevbotton[Dir]=(p1 & dir[Dir]);//前のフレームのボタン入力を保存
if(keytime[Dir]!=0)
keytime[Dir]--;//毎フレーム0じゃなければデクリメント
return 0;
}
こんな感じなんですが、間違っている可能性大です。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月13日(日) 14:05
by KEYONN
int CheckJoyStickPlayer1(int Dir,int FrameTime);
は、どうやら、やはり間違っていたようです。
例えば、上ボタンを押していて、一旦離して、違うボタンを押すと、連続で押したと判定されてしまいます。
何が間違っているかは分かりません。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月13日(日) 22:23
by ISLe
同じ組み合わせの方向キーかどうか判定する部分がないですね。
違う組み合わせの入力があったら最初から判定し直さなければいけません。
方向別に処理する限り解決できない問題です。
だいぶ変えてしまいましたが、こんな感じになりました。
コード:
bool IsDash()
{
const int MASK = PAD_INPUT_UP|PAD_INPUT_DOWN|PAD_INPUT_LEFT|PAD_INPUT_RIGHT;
int p1, trig;
static int prev = 0; // 直前の入力
static int keep = 0; // 前回の入力
static int wait = 0;
static bool pass = false;
p1 = GetJoypadInputState(DX_INPUT_KEY_PAD1) & MASK;
trig = (prev ^ p1) & p1; // 新たな入力
prev = p1;
if (trig == 0) {
// 新たに入力がないか同じ入力が続いている
if (keep != 0) {
if (p1 == 0) {
// 前回の入力からのニュートラルでフラグを立てる
pass = true;
}
if (++wait < 60) {
// 前回の入力から60カウント以内は現状維持
return false;
}
keep = 0; // 時間切れ
}
}
else {
if (p1 == keep && pass) {
// ニュートラルを経由して前回と同じ入力があった
keep = 0;
return true;
}
keep = p1;
pass = false;
}
wait = 0;
return false;
}
これは単発ダッシュですが、ダッシュ判定時にクリアする変数を少し変更すれば連続ダッシュ仕様にできます。
少しコードを追加して押しているあいだダッシュにすることもできます。
同時入力が厳密なので、もうひと工夫しないと斜めダッシュが使いにくいです。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月15日(火) 22:18
by KEYONN
すみません、返信が遅くなってしまいました。しばらく、忙しかったのと、掲示板に書き込めなかったので
ごめんなさい。ブラウザをfirefoxに変えてから、ログインできなくなりました。パスワードの保存機能のせいかも
しれないです。今は、googlechromeで書き込んでいます。
あと、参考になりそうなソースを書き込んでくれたのは嬉しいんですが、先に作ったソース
(自分で作ったソースの方が自分にとっては分かりやすい問題)だったので、
こちらに手を付けました。
しかし、今度は弾がでなくなったり、いろいろ問題が出始めたので、何が原因か分からなかったのも
返信が遅れた理由です。今も理由がわかりません。
コード:
int CheckJoyStickPlayer1(int Dir,int FrameTime)
{
//同じ組み合わせの方向キーを、一定時間内に、
//ニュートラルを挟んで2回押したことを検出する、
//という条件であればもっとシンプルに表現できると思います。
int p1;
int dir[4]={8,1,2,4};
p1=GetJoypadInputState(DX_INPUT_KEY_PAD1) ;//joytypeが0ならjoypad1
static int keytime[4]={0};
static int prevbotton[4]={0};
static int i=0;
static int NeutralFlag[4]={0};
static int PressedBottonsKind[2];
if(prevbotton[Dir] && (p1 & dir[Dir]))
{
static int i=0;
PressedBottonsKind[i]=dir[Dir];
i++;
if(keytime[Dir]!=0 && NeutralFlag[Dir]==1 &&
PressedBottonsKind[0]==PressedBottonsKind[1])//キータイムが0じゃなくて、
//ニュートラルフラグが立っているなら
{
i=0;
PressedBottonsKind[0]=0;
PressedBottonsKind[1]=0;
//printfDx("ありえるのか?");
NeutralFlag[Dir]=0;//リセット
keytime[Dir]=0;
prevbotton[Dir]=0;
return 1;
}else{
keytime[Dir]=FrameTime;//keytimeにFrameTimeを代入
}
}
if(keytime[Dir]!=0)//keytimeが0じゃなければ
{
if(GetNeutralState(p1))//ニュートラルがあるなら
{
NeutralFlag[Dir]=1;//ニュートラルフラグに1を
}
}
prevbotton[Dir]=(p1 & dir[Dir]);//前のフレームのボタン入力を保存
if(keytime[Dir]!=0)
keytime[Dir]--;//毎フレーム0じゃなければデクリメント
return 0;
}
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月15日(火) 23:25
by ISLe
引数のDirを無くすことはできないのですか?
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月16日(水) 21:16
by KEYONN
すみません、基本的には出来ないです。
もしくは、方向別に関数を作り直すという事なら、できなくは無いです。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月17日(木) 00:55
by ISLe
わたしは、そもそも方向別であることが問題だという指摘をしました。
方向別でなければいけないということであれば無視してください。
Re: DXLIBにおけるジョイパッドでの方向キーの連続押しダッシュの仕組みについて
Posted: 2013年10月21日(月) 23:00
by KEYONN
ジョイパッドの(連続押しダッシュの)フラグを立てるのに、
持っている書籍でシューティングゲームアルゴリズムマニアックス(松浦健一郎さん)より
STAGE04:武器のコマンドショットで解決しました。
なお、ニュートラルを取るのに、#define NEUTRAL 1とありますが、実際には、判定されていない模様
かつ、上下左右ボタンしか判定していないと思われる為、
入力履歴とコマンドの初期化の為の関数
void InitCommandShot()内の
Command[0].Length=4;
Command[0].Limit=30;
Command[0].Input[0]=UP;
Command[0].Input[1]=NONE;
Command[0].Input[2]=UP;
以下同様で解決させました。
ありがとうございました。