リズムゲームの判定について

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

リズムゲームの判定について

#1

投稿記事 by souta » 3ヶ月前

学校の制作課題で、音ゲーのようなものをサイトなどを参考に作っています。
ノーツをキー入力で消すところまではできました。
でも、判定の部分でタイミングよく押せたらGOOD、判定ラインを越えたらMISSと表示させるやり方がわかりません。環境はWindowsで、Visual Studio 2019とDXライブラリで作っています。まだC言語も完璧に理解していない初心者です。わかりにくい質問の仕方ですいません。よかったらアドバイス、返信待ってます。
コードはこんな感じです。

コード:

#include "DxLib.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
#define LANE_SIZE 1 //レーンの数
#define BAR_SIZE 40 //1レーンあたりの最大bar数

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

    char buf[256]; //キー押下状態格納用配列
    int key[LANE_SIZE] = {
        KEY_INPUT_A
    };

    bool bar_f[LANE_SIZE][BAR_SIZE]; //barの存在フラグ
    float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標
    for (int j = 0; j < BAR_SIZE; j++) {
        for (int i = 0; i < LANE_SIZE; i++) {
            bar_f[i][j] = false; //全てにfalseを代入
        }
    }
    LONGLONG start_time; //開始した時刻
    LONGLONG now_time; //現在のフレームの時刻
    int currentTime; //開始してからの経過時間
    int counter = 0;
    const int bpm = 120;

    SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
    ChangeWindowMode(TRUE); //ウィンドウモードで起動
    SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
    SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
    if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
    SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定

    //while(裏画面を表画面に反映, メッセージ処理, 画面クリア)
    while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
        if (buf[KEY_INPUT_ESCAPE] == 1) {
            break; // 終了
        }
        //時間関係
        if (counter == 0) {
            start_time = GetNowHiPerformanceCount();
        }
        now_time = GetNowHiPerformanceCount();
        currentTime = (int)((now_time - start_time) / 1000); // ms
        //bar生成
        if (currentTime >= 550000 / bpm * counter) {
            for (int i = 0; i < LANE_SIZE; i++) {
                bar_f[i][counter % BAR_SIZE] = true;
                bar_y[i][counter % BAR_SIZE] = -100.f;
            }
            counter++;
        }
        //bar座標更新
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    bar_y[i][j] += 4.f;
                    if (bar_y[i][j] > WIN_H + 10) {
                        bar_f[i][j] = false; //画面外に出たらfalse
                    }
                }
            }
        }
        // 判定
        GetHitKeyStateAll(buf);
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
                        if (buf[key[i]] == 1) {
                            bar_f[i][j] = false;
                        }
                    }
                }
            }
        }
        //判定ライン描画
        LoadGraphScreen(1,1, "a0.png", TRUE);
        DrawLine(0, WIN_H / 5 * 4, WIN_W, WIN_H / 5 * 4, GetColor(255, 255, 255));
        DrawCircleAA(400.f, 480.f, 45.f, 60.f, GetColor(255, 255, 255), FALSE);
        //bar描画
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    DrawCircleAA(400.f + i * 1.f, bar_y[i][j] - 10.f,
                        30.f + 1.f + i * 1.f, bar_y[i][j] + 10.f, GetColor(0, 255, 0), TRUE);
                }
            }
        }
    }
    DxLib_End(); //DxLibの終了処理
    return 0; //正常終了
}

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

Re: リズムゲームの判定について

#2

投稿記事 by みけCAT » 3ヶ月前

1. GOOD / MISS を表示するための変数を用意する (ループ前に追加)

コード:

enum judge_value {
    NONE, GOOD, MISS;
};

const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
judge_value judge = NONE; // 表示中の判定
int judge_time = 0; // 判定を表示する残り時間 (フレーム数)
2. ノーツを消す時に、判定を表示させるように状態を更新する

コード:

        //bar座標更新
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    bar_y[i][j] += 4.f;
                    if (bar_y[i][j] > WIN_H + 10) {
                        bar_f[i][j] = false; //画面外に出たらfalse
                        // MISSを表示させる
                        judge = MISS;
                        judge_time = JUDGE_DISPLAY_TIME;
                    }
                }
            }
        }
        // 判定
        GetHitKeyStateAll(buf);
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
                        if (buf[key[i]] == 1) {
                            bar_f[i][j] = false;
                            // GOODを表示させる
                            judge = GOOD;
                            judge_time = JUDGE_DISPLAY_TIME;
                        }
                    }
                }
            }
        }
3. 状態に応じて判定を表示する (ループ内に追加)

コード:

if (judge != NONE) {
    if (judge == GOOD) {
        // GOODを描画する (テキスト・画像など)
    } else if (judge == MISS) {
        // MISSを描画する (テキスト・画像など)
    }
    judge_time--;
    if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

souta

Re: リズムゲームの判定について

#3

投稿記事 by souta » 3ヶ月前

みけCATさんありがとうございます!!
アドバイスの通り、コードを変えてみたのですがうまく表示されませんでした、、
更新したコードを張るので、どこら辺がうまくいっていないのか教えていただけると嬉しいです。何度もすいません。

コード:

 
 #include "DxLib.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
#define LANE_SIZE 1 //レーンの数
#define BAR_SIZE 40 //1レーンあたりの最大bar数

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

    char buf[256]; //キー押下状態格納用配列
    int key[LANE_SIZE] = {
        KEY_INPUT_A
    };

    bool bar_f[LANE_SIZE][BAR_SIZE]; //barの存在フラグ
    float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標
    for (int j = 0; j < BAR_SIZE; j++) {
        for (int i = 0; i < LANE_SIZE; i++) {
            bar_f[i][j] = false; //全てにfalseを代入
        }
    }
    LONGLONG start_time; //開始した時刻
    LONGLONG now_time; //現在のフレームの時刻
    int currentTime; //開始してからの経過時間
    int counter = 0;
    const int bpm = 120;

    SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
    ChangeWindowMode(TRUE); //ウィンドウモードで起動
    SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
    SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
    if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
    SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
    enum  judge_value {
        NONE, GOOD, MISS
    };

    const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
    judge_value judge = NONE; // 表示中の判定
    int judge_time = 10; // 判定を表示する残り時間 (フレーム数)

    //while(裏画面を表画面に反映, メッセージ処理, 画面クリア)
    while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
        if (buf[KEY_INPUT_ESCAPE] == 1) {
            break; // 終了
        }
        //時間関係
        if (counter == 0) {
            start_time = GetNowHiPerformanceCount();
        }
        now_time = GetNowHiPerformanceCount();
        currentTime = (int)((now_time - start_time) / 1000); // ms
        //bar生成
        if (currentTime >= 550000 / bpm * counter) {
            for (int i = 0; i < LANE_SIZE; i++) {
                bar_f[i][counter % BAR_SIZE] = true;
                bar_y[i][counter % BAR_SIZE] = -100.f;
            }
            counter++;
        }
        //bar座標更新
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    bar_y[i][j] += 4.f;
                    if (bar_y[i][j] > WIN_H + 10) {
                        bar_f[i][j] = false; //画面外に出たらfalse
                        // MISSを表示させる
                        judge = MISS;
                        judge_time = JUDGE_DISPLAY_TIME;
                    }
                }
            }
        }
        // 判定
        GetHitKeyStateAll(buf);
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
                        if (buf[key[i]] == 1) {
                            bar_f[i][j] = false;
                            // GOODを表示させる
                            judge = GOOD;
                            judge_time = JUDGE_DISPLAY_TIME;
                        }
                    }
                }
            }
        }
        if (judge != NONE) {
            if (judge == GOOD) {
                LoadGraphScreen(1, 1, "a2.png", TRUE);// GOODを描画する (テキスト・画像など)
            }
            else if (judge == MISS) {
                LoadGraphScreen(1, 1, "a2.png", TRUE);// MISSを描画する (テキスト・画像など)
            }
            judge_time--;
            if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
        }
        //判定ライン描画
        LoadGraphScreen(1,1, "a0.png", TRUE);
        DrawLine(0, WIN_H / 5 * 4, WIN_W, WIN_H / 5 * 4, GetColor(255, 255, 255));
        DrawCircleAA(400.f, 480.f, 45.f, 60.f, GetColor(255, 255, 255), FALSE);
        //bar描画
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    DrawCircleAA(400.f + i * 1.f, bar_y[i][j] - 10.f,
                        30.f + 1.f + i * 1.f, bar_y[i][j] + 10.f, GetColor(0, 255, 0), TRUE);
                }
            }
        }
    }
    DxLib_End(); //DxLibの終了処理
    return 0; //正常終了
}

Meta3

Re: リズムゲームの判定について

#4

投稿記事 by Meta3 » 3ヶ月前

GOOD MISS  a2.png? おかしいような //a0.png --- 座標など表示すると分かりやすいかも

if (judge != NONE) {
if (judge == GOOD) {
DrawFormatString(10, 10, GetColor(255, 255, 255), "GOOD");
// LoadGraphScreen(1, 1, "a2.png", TRUE);// GOODを描画する (テキスト・画像など)
}
else if (judge == MISS) {
DrawFormatString(10, 10, GetColor(255, 255, 255), "MISS");
// LoadGraphScreen(1, 1, "a2.png", TRUE);// MISSを描画する (テキスト・画像など)
}

コード:

 
 #include "DxLib.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅
#define LANE_SIZE 1 //レーンの数
#define BAR_SIZE 40 //1レーンあたりの最大bar数

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

    char buf[256]; //キー押下状態格納用配列
    int key[LANE_SIZE] = {
        KEY_INPUT_A
    };

    bool bar_f[LANE_SIZE][BAR_SIZE]; //barの存在フラグ
    float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標
    for (int j = 0; j < BAR_SIZE; j++) {
        for (int i = 0; i < LANE_SIZE; i++) {
            bar_f[i][j] = false; //全てにfalseを代入
        }
    }
    LONGLONG start_time; //開始した時刻
    LONGLONG now_time; //現在のフレームの時刻
    int currentTime; //開始してからの経過時間
    int counter = 0;
    const int bpm = 120;

    SetMainWindowText("リズムの達人"); //ウインドウのタイトルを設定
    ChangeWindowMode(TRUE); //ウィンドウモードで起動
    SetGraphMode(WIN_W, WIN_H, 32); //画面の解像度指定
    SetWindowSizeChangeEnableFlag(FALSE); //画面サイズ変更不可
    if (DxLib_Init() == -1) { return -1; } //DxLib初期化処理
    SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
    enum  judge_value {
        NONE, GOOD, MISS
    };
    const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
    judge_value judge = NONE; // 表示中の判定
    int judge_time = 10; // 判定を表示する残り時間 (フレーム数)

    //while(裏画面を表画面に反映, メッセージ処理, 画面クリア)
    while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0) {
        if (buf[KEY_INPUT_ESCAPE] == 1) {
            break; // 終了
        }
        //時間関係
        if (counter == 0) {
            start_time = GetNowHiPerformanceCount();
        }
        now_time = GetNowHiPerformanceCount();
        currentTime = (int)((now_time - start_time) / 1000); // ms
        //bar生成
        if (currentTime >= 550000 / bpm * counter) {
            for (int i = 0; i < LANE_SIZE; i++) {
                bar_f[i][counter % BAR_SIZE] = true;
                bar_y[i][counter % BAR_SIZE] = -100.f;
            }
            counter++;
        }
DrawFormatString(100, 100,  GetColor(255, 255, 255), "currentTime---%d",currentTime);


        //bar座標更新
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    bar_y[i][j] += 4.f;

DrawFormatString(100, 120,  GetColor(255, 255, 0), "bar_y[i][j]---%f",bar_y[i][j]);

                    if (bar_y[i][j] > WIN_H + 10) {
                        bar_f[i][j] = false; //画面外に出たらfalse
                        // MISSを表示させる
                        judge = MISS; 
DrawFormatString(10, 10,  GetColor(255, 255, 255), "MISS");
                        judge_time = JUDGE_DISPLAY_TIME;
                    }
                }
            }
        }
        // 判定
        GetHitKeyStateAll(buf);
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    if (WIN_H / 5 * 4 - 30 < bar_y[i][j] && bar_y[i][j] < WIN_H / 5 * 4 + 30) {
                        if (buf[key[i]] == 1) {
                            bar_f[i][j] = false;
                            // GOODを表示させる
                            judge = GOOD;
DrawFormatString(10, 10,  GetColor(255, 255, 255), "GOOD");
                            judge_time = JUDGE_DISPLAY_TIME;
                        }
                    }
                }
            }
        }
        if (judge != NONE) {
            if (judge == GOOD) {
DrawFormatString(10, 10,  GetColor(255, 255, 255), "GOOD");
//                LoadGraphScreen(1, 1, "a2.png", TRUE);// GOODを描画する (テキスト・画像など)
            }
            else if (judge == MISS) {
DrawFormatString(10, 10,  GetColor(255, 255, 255), "MISS");
//                LoadGraphScreen(1, 1, "a2.png", TRUE);// MISSを描画する (テキスト・画像など)
            }
            judge_time--;
            if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
        }
  
      //判定ライン描画
//        LoadGraphScreen(1,1, "a0.png", TRUE);
        DrawLine(0, WIN_H / 5 * 4, WIN_W, WIN_H / 5 * 4, GetColor(255, 255, 255));
        DrawCircleAA(400.f, 480.f, 45.f, 60.f, GetColor(255, 255, 255), FALSE);
        //bar描画
        for (int i = 0; i < LANE_SIZE; i++) {
            for (int j = 0; j < BAR_SIZE; j++) {
                if (bar_f[i][j]) {
                    DrawCircleAA(400.f + i * 1.f, bar_y[i][j] - 10.f,
                        30.f + 1.f + i * 1.f, bar_y[i][j] + 10.f, GetColor(0, 255, 0), TRUE);
                }
            }
        }
    }
    DxLib_End(); //DxLibの終了処理
    return 0; //正常終了
}

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

Re: リズムゲームの判定について

#5

投稿記事 by みけCAT » 3ヶ月前

判定の後、同じ位置に重ねてa0.pngを描画しているので、
a0.pngの内容によりますが、これで隠してしまっている疑いがあります。
また、GOODの描画もMISSの描画も同じ座標に同じa2.pngを描画、というのも不自然ですね。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

souta

Re: リズムゲームの判定について

#6

投稿記事 by souta » 3ヶ月前

a0.pngはゲーム画面の背景を表示させています。
仰るとおり上に表示させていて、判定の文字が隠れてしまっていたようです。
一番上に書くことでちゃんとGOODやMISSが表示されました!
みけCATさん、親切に教えていただきありがとうございます!!

返信

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