DxLib サイコロのプログラムに関する質問です。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ほし

DxLib サイコロのプログラムに関する質問です。

#1

投稿記事 by ほし » 1年前

以下のプログラムは、サイコロのプログラム。
Zキーを押すとサイコロの画像がランダムに一枚ずつ切り替わり、再度Zキーを押すとランダムにサイコロの画像が一枚表示され(静止)、Cキーを押すと終了、というプログラムなのですが、Zキーを押すと、再度押した際の処理をしてしまいます。

また、再度Zキーを押すところをXキーを押すようにしたら、正常に動作します。

初歩的なところとは重々承知しております。回答、よろしくお願いします。


#include "DxLib.h"
#include "stdlib.h"

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;
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定
SetWindowSize(640, 480);
int Dice;
int Random, Random1, Random2 ;
int i1 , i2;
int Green = GetColor(0, 255, 0); // 緑の色コードを取得
int Dice1, Dice2, Dice3, Dice4, Dice5, Dice6;

Dice = 0;
Random = 0;
Random1 = 0;
Random2 = 0;
Dice1 = 0;
Dice2 = 0;
Dice3 = 0;
Dice4 = 0;
Dice5 = 0;
Dice6 = 0;
i1 = 0;
i2 = 0;

Dice1 = LoadGraph("画像/サイコロ/1.png"); // 画像をロード
Dice2 = LoadGraph("画像/サイコロ/2.png"); // 画像をロード
Dice3 = LoadGraph("画像/サイコロ/3.png"); // 画像をロード
Dice4 = LoadGraph("画像/サイコロ/4.png"); // 画像をロード
Dice5 = LoadGraph("画像/サイコロ/5.png"); // 画像をロード
Dice6 = LoadGraph("画像/サイコロ/6.png"); // 画像をロード




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


if (i1 == 0) {
if (Key[KEY_INPUT_Z] == 1) { // Zが押された瞬間なら
Random2 = 1;
i1 = 1;
}
}

if (Random2 == 1) { //サイコロ回転開始

Random = GetRand(5);
if (Random == 0) {
DrawGraph(20, 400, Dice1, TRUE);
}

else if (Random == 1) {
DrawGraph(20, 400, Dice2, TRUE);
}

else if (Random == 2) {
DrawGraph(20, 400, Dice3, TRUE);
}

else if (Random == 3) {
DrawGraph(20, 400, Dice4, TRUE);
}

else if (Random == 4) {
DrawGraph(20, 400, Dice5, TRUE);
}

else if (Random == 5) {
DrawGraph(20, 400, Dice6, TRUE);
}
Dice = GetRand(5);


if (Key[KEY_INPUT_Z] == 1) { // Zが押された瞬間なら
Random1 = 1;
Random2 = 0;
}
}


if (Random1 == 1) { // サイコロ停止
if (Dice == 0) {
DrawGraph(20, 400, Dice1, TRUE);

if (Key[KEY_INPUT_C] == 1) {
Random1 = 0;
return 0;
}
}

else if (Dice == 1) {
DrawGraph(20, 400, Dice2, TRUE);

if (Key[KEY_INPUT_C] == 1) {
Random1 = 0;
return 0;
}
}

else if (Dice == 2) {
DrawGraph(20, 400, Dice3, TRUE);

if (Key[KEY_INPUT_C] == 1) {
Random1 = 0;
return 0;
}
}

else if (Dice == 3) {
DrawGraph(20, 400, Dice4, TRUE);

if (Key[KEY_INPUT_C] == 1) {
Random1 = 0;
return 0;
}
}

else if (Dice == 4) {
DrawGraph(20, 400, Dice5, TRUE);

if (Key[KEY_INPUT_C] == 1) {
Random1 = 0;
return 0;
}
}

else if (Dice == 5) {
DrawGraph(20, 400, Dice6, TRUE);

if (Key[KEY_INPUT_C] == 1) {
Random1 = 0;
return 0;
}
}

}

if (Key[KEY_INPUT_ESCAPE] == 1) {
break;
}
}

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

ほしぼし

DxLib サイコロのプログラムに関する質問です。

#2

投稿記事 by ほしぼし » 1年前

ほし さんが書きました:
1年前
DxLibに一週間前に触れ始めた初心者です。よろしくお願いします。

以下のプログラムは、C言語で書いたサイコロのプログラムです。
Zキーを押すとサイコロの画像がランダムに一枚ずつ切り替わり、再度Zキーを押すとランダムにサイコロの画像が一枚表示され(静止)、Cキーを押すと終了、というプログラムなのですが、Zキーを押すと、再度押した際の処理をしてしまいます。(コンパイル自体は正常に終了し、テストプレイ自体も正常に終了します。)

また、再度Zキーを押すところをXキーを押すようにしたら、正常に動作します。

初歩的なところとは重々承知しております。回答、よろしくお願いします。

OS:Windows 10
コンパイル:Visual Studio 2022

コード:

#include "DxLib.h"
#include "stdlib.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); //ウィンドウモード変更と初期化と裏画面設定
    SetWindowSize(640, 480);
    int Dice;
    int Random, Random1, Random2 ;
    int i1 , i2;
    int Green = GetColor(0, 255, 0);      // 緑の色コードを取得
    int Dice1, Dice2, Dice3, Dice4, Dice5, Dice6;

    Dice = 0;
    Random = 0;
    Random1 = 0;
    Random2 = 0;
    Dice1 = 0;
    Dice2 = 0;
    Dice3 = 0;
    Dice4 = 0;
    Dice5 = 0;
    Dice6 = 0;
    i1 = 0;
    i2 = 0;

    Dice1 = LoadGraph("画像/サイコロ/1.png"); // 画像をロード
    Dice2 = LoadGraph("画像/サイコロ/2.png"); // 画像をロード
    Dice3 = LoadGraph("画像/サイコロ/3.png"); // 画像をロード
    Dice4 = LoadGraph("画像/サイコロ/4.png"); // 画像をロード
    Dice5 = LoadGraph("画像/サイコロ/5.png"); // 画像をロード
    Dice6 = LoadGraph("画像/サイコロ/6.png"); // 画像をロード




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


        if (i1 == 0) {
            if (Key[KEY_INPUT_Z] == 1) { // Zが押された瞬間なら
                Random2 = 1;
                i1 = 1;
            }
        }

        if (Random2 == 1) {     //サイコロ回転開始 

                Random = GetRand(5);
                if (Random == 0) {
                    DrawGraph(20, 400, Dice1, TRUE);
                }

                else if (Random == 1) {
                    DrawGraph(20, 400, Dice2, TRUE);
                }

                else if (Random == 2) {
                    DrawGraph(20, 400, Dice3, TRUE);
                }

                else if (Random == 3) {
                    DrawGraph(20, 400, Dice4, TRUE);
                }

                else if (Random == 4) {
                    DrawGraph(20, 400, Dice5, TRUE);
                }

                else if (Random == 5) {
                    DrawGraph(20, 400, Dice6, TRUE);
                }
                Dice = GetRand(5);


                if (Key[KEY_INPUT_Z] == 1) { // Zが押された瞬間なら
                    Random1 = 1;
                    Random2 = 0;
                }
        }

        
        if (Random1 == 1) {       // サイコロ停止
                if (Dice == 0) {
                    DrawGraph(20, 400, Dice1, TRUE);

                    if (Key[KEY_INPUT_C] == 1) {
                        Random1 = 0;
                        return 0;
                    }
                }

                else if (Dice == 1) {
                    DrawGraph(20, 400, Dice2, TRUE);

                    if (Key[KEY_INPUT_C] == 1) {
                        Random1 = 0;
                        return 0;
                    }
                }

                else if (Dice == 2) {
                    DrawGraph(20, 400, Dice3, TRUE);

                    if (Key[KEY_INPUT_C] == 1) {
                        Random1 = 0;
                        return 0;
                    }
                }

                else if (Dice == 3) {
                    DrawGraph(20, 400, Dice4, TRUE);

                    if (Key[KEY_INPUT_C] == 1) {
                        Random1 = 0;
                        return 0;
                    }
                }

                else if (Dice == 4) {
                    DrawGraph(20, 400, Dice5, TRUE); 

                    if (Key[KEY_INPUT_C] == 1) {
                        Random1 = 0;
                        return 0;
                    }
                }

                else if (Dice == 5) {
                    DrawGraph(20, 400, Dice6, TRUE);

                    if (Key[KEY_INPUT_C] == 1) {
                        Random1 = 0;
                        return 0;
                    }
                }

        }

        if (Key[KEY_INPUT_ESCAPE] == 1) {
            break;
        }
    }

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

ほしぼし

Re: DxLib サイコロのプログラムに関する質問です。

#3

投稿記事 by ほしぼし » 1年前

すみません!
フォーラム(掲示板)ルールを読んでおらず、正しい記述方法で返信しました。
失礼しました。

ほしぼし

Re: DxLib サイコロのプログラムに関する質問です。

#4

投稿記事 by ほしぼし » 1年前

再三ごめんなさい。
質問の目的は、「Zキーを再度押しても正常に動作させるにはどうしたら良いか」というものです。
本当にすみません...

アバター
usao
記事: 1887
登録日時: 11年前

Re: DxLib サイコロのプログラムに関する質問です。

#5

投稿記事 by usao » 1年前

gpUpdateKey() なる関数によって Key なる配列の内容が更新されること
VS
Key なる配列の内容を見て処理を実施すること

のタイミングの問題なんじゃない?

分かりやすく極端な例の話をすれば,最初に一回しか gpUpdateKey() を実施しないとしたら,
きっと Key の内容をチェックして処理分岐しようとしている個所の動作は所望のタイミングで動かないよね.

今,gpUpdateKey() の呼び出しは while のところにあるから,このループの繰り返し毎に呼ばれるわけだ.
言い方を変えれば「繰り返し毎に1回しか実施しない」.
それでループ内の記述が所望のタイミングで動けるのかどうかを考えてみてはどうか.

アバター
usao
記事: 1887
登録日時: 11年前

Re: DxLib サイコロのプログラムに関する質問です。

#6

投稿記事 by usao » 1年前

それはそうと,

(1) 変数名がイミフすぎて読むのがつらい.
「i1」とか「Random2」とか字面から意味を推測できない名前をあえて使う理由は何か?
他者から見たらまるで暗号だ.
もちろん言語的には自由に付けても良いのだし,ご自身が把握できているなら,(他者に見せない限りは)問題ないのだが.

(2) 画像関係に何故配列を使わないのか?(Key の側では使ってるのに)
配列使えば if で6分岐している系のコードのサイズがおおよそ1/6になるのでは?
(同じ事を繰り返し6回書いている時点でうんざりしない?)

とか.

アバター
usao
記事: 1887
登録日時: 11年前

Re: DxLib サイコロのプログラムに関する質問です。

#7

投稿記事 by usao » 1年前

> Zキーを押すとサイコロの画像がランダムに一枚ずつ切り替わり、再度Zキーを押すとランダムにサイコロの画像が一枚表示され(静止)、Cキーを押すと終了

この文章だけからでは 状態の種類(個数)が微妙に不明瞭だけど…

(状態1)最初の状態
(このとき何が表示されるのか? とかは明言されていないが)
Zキーを押すと状態2に遷移する.

(状態2)Zキーを1回押した状態
サイコロの絵がランダムに切り替わる状態.
Zキーを押すと状態3に遷移する.

(状態3)Zキーを2回押した状態
サイコロの絵のいずれか1つが表示され続ける状態.
ここでCキーを押すと終了.
(それ以外の操作は無いのかな? 例えば,再び状態2に行く道とか)

くらいの状態遷移があるものと読める.
これを素直にコードとして表現したら

コード:

//現在の状態を表す変数.
//実際には,「コレ何型なのか?」とか「マジックナンバーをダイレクトに書くな」とか色々あるだろうが.
int CurrentState = 1;

while( ...  gpUpdateKey() ... )
{
  if( CurrentState == 1 )  //状態1のときの処理
  {
    if( Zが押された ){  CurrentState = 2;  }  //状態遷移
  }
  else if( CurrentState == 2 )  //状態2のときの処理
  { ...略... }
  else if( CurrentState == 3 )  //状態3のときの処理
  { ...略... }
  else  //※この話だとこのelseの条件を満たすことはない
  { ココに来たらバグだ }
}
みたいな形が考えられる.
while ループの各繰り返しでは何れかの状態用の処理だけが実施される(:複数が実施されることはない)という形にすると gpUpdateKey() とのタイミングの兼ね合いが把握しやすいのではあるまいか.

貼られているコードは何となくそういう形にしようとしている雰囲気にも見えるが,必ずしもそうなっていないようにも見える.
else とか continue とかが無い if の列挙になっているせいで,複数の処理を一気に実施してしまうとかそういうことは無いのかを確認してみると良いかもしれぬ.

アバター
あたっしゅ
記事: 664
登録日時: 13年前
住所: 東京23区
連絡を取る:

Re: DxLib サイコロのプログラムに関する質問です。

#8

投稿記事 by あたっしゅ » 1年前

東上☆海美☆「
とりあえず、元のプログラムを出来る限り残して、『こうしたいのだろう』という形にしてみたみみ。
.png ファイルはないので、文字出力に変えたみみ。

コード:

/**
* @file sample.cpp
* @brief https://dixq.net/forum/viewtopic.php?f=3&t=21594&sid=643c13154267c94a7532d89a621c10b4 DxLib サイコロのプログラムに関する質問です。 - ミクプラ(ja)
* @details for DxLib, DOXYGEN 勉強中
*/
#include "DxLib.h"
#include "stdlib.h"


/**
* @details https://www.ay3s-room.com/entry/dxlib-key-input 新ゲームプログラミングの館 に載っているコード
*/
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;
}


/**
* @fn int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) try 
* @details main
*/
int WINAPI
WinMain(HINSTANCE, HINSTANCE, LPSTR, int) try
{
    ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定
    SetWindowSize(640, 480);

    int Dice;

#if 0
    int Random, Random1, Random2;
#else
    enum e {
        eStart, eHitZ, eAfterHitZ
    } status = eStart;
#endif

    //int i1, i2;
    int Green = GetColor(0, 255, 0);      // 緑の色コードを取得
    //int Dice1, Dice2, Dice3, Dice4, Dice5, Dice6;

    //Dice = 0;
    Dice = 6;

    //Random = 0;
    //Random1 = 0;
    //Random2 = 0;

    //Dice1 = 0;
    //Dice2 = 0;
    //Dice3 = 0;
    //Dice4 = 0;
    //Dice5 = 0;
    //Dice6 = 0;

    //i1 = 0;
    //i2 = 0;

#if 0
    Dice1 = LoadGraph("画像/サイコロ/1.png"); // 画像をロード
    Dice2 = LoadGraph("画像/サイコロ/2.png"); // 画像をロード
    Dice3 = LoadGraph("画像/サイコロ/3.png"); // 画像をロード
    Dice4 = LoadGraph("画像/サイコロ/4.png"); // 画像をロード
    Dice5 = LoadGraph("画像/サイコロ/5.png"); // 画像をロード
    Dice6 = LoadGraph("画像/サイコロ/6.png"); // 画像をロード
#else
    const char* const DiceImg[] = {
        "Dice1",
        "Dice2",
        "Dice3",
        "Dice4",
        "Dice5",
        "Dice6",
        "-----",
    };
#endif

    // while(裏画面を表画面に反映, メッセージ処理, 画面クリア)
    while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
        //if (i1 == 0) {
            if (Key[KEY_INPUT_Z] == 1) { // Zが押された瞬間なら
                //Random2 = 1;
                status = eHitZ;

                //i1 = 1;
            }
        //}

            if 
                //(Random2 == 1)
                ( status == eHitZ ) 
            {     //サイコロ回転開始 
                    //Random = GetRand(5);
                Dice = GetRand( 5 );
                status = eAfterHitZ;
            }
#if 0
                if (Random == 0) {
                    //DrawGraph(20, 400, Dice1, TRUE);
                    DrawString(20, 400, "Dice1", Green);
                }
                else if (Random == 1) {
                    //DrawGraph(20, 400, Dice2, TRUE);
                    DrawString(20, 400, "Dice2", Green);
                }
                else if (Random == 2) {
                    //DrawGraph(20, 400, Dice3, TRUE);
                    DrawString(20, 400, "Dice3", Green);
                }
                else if (Random == 3) {
                    //DrawGraph(20, 400, Dice4, TRUE);
                    DrawString(20, 400, "Dice4", Green);
                }
                else if (Random == 4) {
                    //DrawGraph(20, 400, Dice5, TRUE);
                    DrawString(20, 400, "Dice5", Green);
                }
                else if (Random == 5) {
                    //DrawGraph(20, 400, Dice6, TRUE);
                    DrawString(20, 400, "Dice6", Green);
                }
#else
            DrawString(20, 400, DiceImg[ Dice ], Green);
#endif
            //Dice = GetRand(5);
#if 0
            if (Key[KEY_INPUT_Z] == 1) { // Zが押された瞬間なら
                Random1 = 1;
                Random2 = 0;
            }
#endif
        //}


/*
        if (Random1 == 1) {       // サイコロ停止
            if (Dice == 0) {
                //DrawGraph(20, 400, Dice1, TRUE);
                DrawString(20, 400, "Dice1", Green);

                if (Key[KEY_INPUT_C] == 1) {
                    Random1 = 0;

                    //return 0;
                    break;
                }
            } else if (Dice == 1) {
                //DrawGraph(20, 400, Dice2, TRUE);
                DrawString(20, 400, "Dice2", Green);

                if (Key[KEY_INPUT_C] == 1) {
                    Random1 = 0;

                    //return 0;
                    break;
                }
            } else if (Dice == 2) {
                //DrawGraph(20, 400, Dice3, TRUE);
                DrawString(20, 400, "Dice3", Green);

                if (Key[KEY_INPUT_C] == 1) {
                    Random1 = 0;

                    //return 0;
                    break;
                }
            } else if (Dice == 3) {
                //DrawGraph(20, 400, Dice4, TRUE);
                DrawString(20, 400, "Dice4", Green);

                if (Key[KEY_INPUT_C] == 1) {
                    Random1 = 0;

                    //return 0;
                    break;
                }
            } else if (Dice == 4) {
                //DrawGraph(20, 400, Dice5, TRUE);
                DrawString(20, 400, "Dice5", Green);

                if (Key[KEY_INPUT_C] == 1) {
                    Random1 = 0;

                    //return 0;
                    break;
                }
            } else if (Dice == 5) {
                //DrawGraph(20, 400, Dice6, TRUE);
                DrawString(20, 400, "Dice6", Green);

                if (Key[KEY_INPUT_C] == 1) {
                    Random1 = 0;

                    //return 0;
                    break;
                }
            }
        }
*/
        if( status == eAfterHitZ ) {
            if (Key[KEY_INPUT_C] == 1) {
                break;
            }
        }

        if (Key[KEY_INPUT_ESCAPE] == 1) {
            break;
        }
    }

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

    return EXIT_SUCCESS;        // ソフトの終了     
}
catch (...)
{
    return EXIT_FAILURE;
}


// end.
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

ほしぼし

Re: DxLib サイコロのプログラムに関する質問です。

#9

投稿記事 by ほしぼし » 1年前

>>usao様
返信ありがとうございます!
usao様が記述している通り、状態移行とelse ifを使用してみたところ、Zキーで三段階目が反応するようになりました!本当にありがとうございます!
また、変数や配列等は質問をする身として、見やすい・わかりやすいコードになるよう心がけます!改めまして、ありがとうございました!

>>あたっしゅ様
返信ありがとうございます!
すみません、せっかくコードを書いていただいたのですが、私の想定していたプログラムとは異なっていました...
わざわざ書いていただいたのに、本当に申し訳ないです...
わかりやすいプログラムの説明ができるよう、以後心がけます!
ありがとうございました!

アバター
あたっしゅ
記事: 664
登録日時: 13年前
住所: 東京23区
連絡を取る:

Re: DxLib サイコロのプログラムに関する質問です。

#10

投稿記事 by あたっしゅ » 1年前

東上☆海美☆「
ちゃんと動くようになったプログラム、up してください。
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

アバター
usao
記事: 1887
登録日時: 11年前

Re: DxLib サイコロのプログラムに関する質問です。

#11

投稿記事 by usao » 1年前

> (2) 画像関係に何故配列を使わないのか?

そのライブラリには DrawRectGraph() なる関数があるみたいだから,コレ使うのも良いかも.
(:「6つの画像のどれを描画するか」じゃなくて「1つの画像のどの部分を描画するか」という話になる)

返信

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