キーボードとキャラを動かくすための関数を深く理解したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Ouxiy
記事: 61
登録日時: 2週間前

キーボードとキャラを動かくすための関数を深く理解したい

#1

投稿記事 by Ouxiy » 1週間前

以下はキーボードを用いてキャラクターを動かす関数のプログラムです

コード:

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;
}  
★行い事このコードがなぜこのように書けるのかわかりやすく教えてほしいです。
このプログラムによってPCの中で何が起こっているのかを教えて頂けると嬉しいです。
なぜこのようにしなくてはキーボードを利用してキャラが動かせないのか。
key[256]やバッファなど出てきますが、フレームや押下状態をバッファに入れるなど設計図というかイメージが出来ずにいます。
なんで更新する必要があるのか、一度押した後、おしっぱではずっと動くので、更新して0に戻す、、、など、そこで出てくるフレームや押下状態に対してもイメージが出来ません。バッファに押下状態があることでおしっぱを再現しいるとか、それをKey = 0更新して再びchar tmpKey[256]してキーボードを話すと止まるなど。
逆に、おしっぱでも一歩しか進まないようにするにはバッファやフレームや押下状態をどのように考えながら上のようにコードを書けばいいのかわかりません。

ただ欲を言えば、使う画像のデータをPC内で扱っていると仮定して、その画像のフレーム数や押下状態の収納するバッファの様子や図を紙に書いて考えて、上のようなコードが作れた!みたいなのが理想です。そのように説明して頂けると考えやすいです。



そしてもう一つ、できれば、別表現で以上のプログラムをもっと簡単に書き直せないでしょうか?
というのも、正直、「フレーム」や「押下状態」などの用語の理解に努めようとしたのですが、うまくいかず、もっとめんどうで地道にあえてわかりやすく簡単に書いたら理解できるような気がしました。
というのもhttps://dixq.net/g/02_09.htmlより私が押したいキーボードは右、左、下、上の四つのみなのでCheckHitKey関数が使えるのではないかと考えました。もし、全部のキーボードを使わないで特定のキーボードのみを打つプログラムを作るとしたら、上のプログラムを利用しなくても作れるでしょうか?

アバター
みけCAT
記事: 6192
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: キーボードとキャラを動かくすための関数を深く理解したい

#2

投稿記事 by みけCAT » 1週間前

前半の質問については、一旦保留とします、
Ouxiy さんが書きました:
1週間前
そしてもう一つ、できれば、別表現で以上のプログラムをもっと簡単に書き直せないでしょうか?
というのも、正直、「フレーム」や「押下状態」などの用語の理解に努めようとしたのですが、うまくいかず、もっとめんどうで地道にあえてわかりやすく簡単に書いたら理解できるような気がしました。
どのような表現を簡単と感じるかは人によるはずなので、わかりません。
例えばloop unrollをしたら「別表現」で「簡単」になるでしょうか?
Ouxiy さんが書きました:
1週間前
というのもhttps://dixq.net/g/02_09.htmlより私が押したいキーボードは右、左、下、上の四つのみなのでCheckHitKey関数が使えるのではないかと考えました。もし、全部のキーボードを使わないで特定のキーボードのみを打つプログラムを作るとしたら、上のプログラムを利用しなくても作れるでしょうか?
ここでn「キーボード」が「キー」のことだとすると、作れます。
全部のキーを使うとしても、作れます。
例えば右キーが押されたタイミングかを判定するには、以下の擬似コードのようにするといいでしょう。

コード:

bool 右キーが押されていたか = false;

ループ {
    if (現在右キーが押されている) {
        if (右キーが押されていたか) {
            // 右キーが押され続けている
        } else {
            // 右キーがこのフレームで押された
        }
        右キーが押されていたか = true;
    } else {
        // 右キーが話されている
        右キーが押されていたか = false;
    }
}
他のキーについても、同様です。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6192
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: キーボードとキャラを動かくすための関数を深く理解したい

#3

投稿記事 by みけCAT » 1週間前

Ouxiy さんが書きました:
1週間前
以下はキーボードを用いてキャラクターを動かす関数のプログラムです
キーボードの状態を得る関数のプログラムはあるようですが、キャラクターを動かす関数は見当たりません。
コピペ忘れでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Ouxiy
記事: 61
登録日時: 2週間前

Re: キーボードとキャラを動かくすための関数を深く理解したい

#4

投稿記事 by Ouxiy » 1週間前

ありがとうございます。
なるほど、では
bool 右キーが押されていたか = false;

ループ {
if (現在右キーが押されている) {
if (右キーが押されていたか) {
// 右キーが押され続けている
} else {
// 右キーがこのフレームで押された
}
右キーが押されていたか = true;
} else {
// 右キーが話されている
右キーが押されていたか = false;
}
}
256のキーすべてに対して、以上のように書いてまとめたものが
int Key[256]; // キーが押されているフレーム数を格納する

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

かずま

Re: キーボードとキャラを動かくすための関数を深く理解したい

#5

投稿記事 by かずま » 1週間前

Ouxiy さんが書きました:
1週間前
以下はキーボードを用いてキャラクターを動かす関数のプログラムです
違います。

gpUpdateKey は、すべてのキーボードの押下状態を取得する関数です。
・キー i が押されていないと、Key[ i] の値は 0。
・キー i が押されていると、Key[ i] の値は押されてからのフレーム数。

gpUpdateKey は、キャラクターを動かす関数ではありません。

キャラクターを動かすのは、gpUpdateKey で取得した Key[ i] の値を見て、
キャラクターの表示位置と表示画像を変更し、DrawGraph で描画を行う
while ループ内のコードです。

なぜ、こんな当たり前のことが分からないのか不思議です。
Ouxiy さんが書きました:
1週間前
★行い事このコードがなぜこのように書けるのかわかりやすく教えてほしいです。
このプログラムによってPCの中で何が起こっているのかを教えて頂けると嬉しいです。
なぜこのようにしなくてはキーボードを利用してキャラが動かせないのか。
GetHitKeyStateAll も GetHitKey もキーの押下状態を
・キーが押されていたら 1
・キーが押されていなかったら 0
で表すだけです。

次のプログラムを実行してみてください。

コード:

#include "DxLib.h"

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

	int x = 0;

	// while(裏画面を表画面に反映, メッセージ処理, 画面クリア)
	while (ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0) {
		DrawFormatString(x, 20, GetColor(255, 255, 255), "%3d   ", x);
		if (CheckHitKey(KEY_INPUT_RIGHT) != 0) x += 10;
		if (CheckHitKey(KEY_INPUT_LEFT) != 0) x -= 10;
	}

	DxLib_End(); // DXライブラリ終了処理
	return 0;
}
右キーを押すと、キャラクターが右に 10ドット移動するように作ったつもりです。
キャラクターとして現在位置を表示することにしています。

さあ、右キーを押してみてください。10ずつ進みますか?
50 とか 60 進みませんか? なぜだかわかりますか?

WinMain の ProcessMessage の whileループは、1秒間に 60回実行されます。
人間がキーを押して離すのに 0.1秒ぐらいかかります。
その間に 6フレーム分の時間が経過します。
キーが押されているのが 6回検出されたら、キャラクタは 60 進みます。

これでは困ります。
そこで、gpUpdateKey関数を書いたのです。
この関数により、Key[KEY_INPUT_RIGHT] の値は、
0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 0, 0. 0, ... と変化します。
・最初の 0 は、キーが押される前の値。
・1 は、キーが押された直後の値。
・2~6 は、キーが押されている間の値。
・その後の 0 はキーが離された後の値。

whileループでは、Key[KEY_INPUT_RIGHT] が 1 かどうかを見るだけで、
右キーが 1回押されたことを検出できるのです。

それから、フォーラム(掲示板)ルールをよく読んでください。
複数の掲示板で質問する時は、そのことを明示しなければなりません。

Ouxiy
記事: 61
登録日時: 2週間前

Re: キーボードとキャラを動かくすための関数を深く理解したい

#6

投稿記事 by Ouxiy » 1週間前

詳しい解説感謝します 。紙に書いてイメージしてみます どうもありがとうございます。

アバター
みけCAT
記事: 6192
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: キーボードとキャラを動かくすための関数を深く理解したい

#7

投稿記事 by みけCAT » 6日前

Ouxiy さんが書きました:
1週間前
ありがとうございます。
なるほど、では
bool 右キーが押されていたか = false;

ループ {
if (現在右キーが押されている) {
if (右キーが押されていたか) {
// 右キーが押され続けている
} else {
// 右キーがこのフレームで押された
}
右キーが押されていたか = true;
} else {
// 右キーが話されている
右キーが押されていたか = false;
}
}
256のキーすべてに対して、以上のように書いてまとめたものが
int Key[256]; // キーが押されているフレーム数を格納する

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

いいえ。
前者のコードでは。「このフレームで押された」「押され続けている」「離されている」
の3種類の状態しか判定しません。 (「話されている」は誤字です。ごめんなさい)
一方、後者のコードでは、各キーが何フレーム押されているかがわかります。
この情報を利用すると、例えば「〇〇キーが60フレーム押され続けていたら△△する」のようなこともできます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)


返信

“C言語何でも質問掲示板” へ戻る