ゲームの画面切り替えについて

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

ゲームの画面切り替えについて

#1

投稿記事 by souta » 3年前

ゲーム制作をしているのですか、タイトル画面とゲーム画面とスコア画面の切り替えの仕方がわかりません。メニュー選択してEnterを押すと次の画面に切り替えれるようにしたいです(クリック入力でも可)
環境はWindowsで、Visual Studio 2019とDXライブラリで作っています。C言語は習っている最中で完璧には理解できていないレベルです。
<タイトル画面のコード>

コード:

#include "DxLib.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;
}

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;

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

    SetGraphMode(800, 800, 32); //画面の解像度指定


    // メニュー項目要素を2つ作る
    MenuElement_t MenuElement[2] = {
            { 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
            { 380, 400, "ゲーム終了" },
    };
    int SelectNum = 0; // 現在の選択番号

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

        // 計算フェーズ 

        if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

            SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

            for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
                if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                    MenuElement[i].x = 350; // 座標を320にする
                }
                else {                       // 今処理しているのが、選択番号以外なら
                    MenuElement[i].x = 380;// 座標を350にする
                }
            }
        }


        // 描画フェーズ

        LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE);  //背景
        LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE);  //タイトルロゴ
        for (int i = 0; i < 5; i++) { // メニュー項目を描画
            DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

            SetFontSize(32);
            SetFontThickness(4);
            ChangeFontType(DX_FONTTYPE_ANTIALIASING);
        }


    }

    DxLib_End(); // DXライブラリ終了処理
    return 0;
}
<ゲーム画面のコード>

コード:

#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) {
        LoadGraphScreen(1, 1, "a0.png", TRUE);
        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(0, 0, 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, 0, 0), "GOOD");
                            judge_time = JUDGE_DISPLAY_TIME;
                        }
                    }
                }
            }
        }
        if (judge != NONE) {
            if (judge == GOOD) {
                DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
                // GOODを描画する (テキスト・画像など)
            }
            else if (judge == MISS) {
                DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
                // MISSを描画する (テキスト・画像など)
            }
            judge_time--;
            if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
        }

        //判定ライン描画
        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; //正常終了
}
<スコア画面のコード>

コード:

#include "DxLib.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;
}

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;



int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
    SetBackgroundColor(255, 255, 255);
    ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定

    SetMainWindowText("スコア画面"); //ウインドウのタイトルを設定
    SetGraphMode(800, 600, 32); //画面の解像度指定



    // メニュー項目要素を2つ作る
    MenuElement_t MenuElement[2] = {
            { 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
            { 300, 450, "タイトルへ戻る" },
    };
    int SelectNum = 0; // 現在の選択番号

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

        // 計算フェーズ 

        if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

            SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

            for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
                if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                    MenuElement[i].x = 270; // 座標を270にする
                }
                else {                       // 今処理しているのが、選択番号以外なら
                    MenuElement[i].x = 300;// 座標を300にする
                }
            }
        }


        // 描画フェーズ

        LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE);  //背景
        LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE);  //スコアロゴ
        for (int i = 0; i < 5; i++) { // メニュー項目を描画
            DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

            SetFontSize(32);
            SetFontThickness(4);
            ChangeFontType(DX_FONTTYPE_ANTIALIASING);
        }
    }

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

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#2

投稿記事 by 参照魚 » 3年前

まずは各画面をサブルーチン化するところから始めてください。例えばタイトル画面なら、int WINAPI WinMain を int SceneTitle(void) に変更します。そして、そのサブルーチンからDxLibのシステムの初期化と後始末に関連する部分を削除します。タイトル画面なら、ChangeWindowMode, DxLib_Init,SetDrawScreen,DxLinEnd です。次に While ループを外します。これでビルドが通るところまで行ってみてください。最後のリンクでWinMainが無いというエラーがでますが、それは次の段階になります。

souta

Re: ゲームの画面切り替えについて

#3

投稿記事 by souta » 3年前

このような感じですか?

コード:

#include "DxLib.h"

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

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

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;

int SceneTitle(void) {
    SetGraphMode(800, 600, 32); //画面の解像度指定


    // メニュー項目要素を2つ作る
    MenuElement_t MenuElement[2] = {
            { 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
            { 380, 400, "ゲーム終了" },
    };
    int SelectNum = 0; // 現在の選択番号

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

        // 計算フェーズ 

        if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

            SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

            for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
                if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                    MenuElement[i].x = 350; // 座標を320にする
                }
                else {                       // 今処理しているのが、選択番号以外なら
                    MenuElement[i].x = 380;// 座標を350にする
                }
            }
        }


        // 描画フェーズ

        LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE);  //背景
        LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE);  //タイトルロゴ
        for (int i = 0; i < 5; i++) { // メニュー項目を描画
            DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

            SetFontSize(32);
            SetFontThickness(4);
            ChangeFontType(DX_FONTTYPE_ANTIALIASING);
        }


    }
    return 0;
}

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) {
        LoadGraphScreen(1, 1, "a0.png", TRUE);
        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(0, 0, 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, 0, 0), "GOOD");
                            judge_time = JUDGE_DISPLAY_TIME;
                        }
                    }
                }
            }
        }
        if (judge != NONE) {
            if (judge == GOOD) {
                DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
                // GOODを描画する (テキスト・画像など)
            }
            else if (judge == MISS) {
                DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
                // MISSを描画する (テキスト・画像など)
            }
            judge_time--;
            if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
        }

        //判定ライン描画
        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; //正常終了
}

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

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;


int SceneScore(void) {
    SetBackgroundColor(255, 255, 255);
    ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定

    SetMainWindowText("スコア画面"); //ウインドウのタイトルを設定
    SetGraphMode(800, 600, 32); //画面の解像度指定



    // メニュー項目要素を2つ作る
    MenuElement_t MenuElement[2] = {
            { 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
            { 300, 450, "タイトルへ戻る" },
    };
    int SelectNum = 0; // 現在の選択番号

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

        // 計算フェーズ 

        if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

            SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

            for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
                if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                    MenuElement[i].x = 270; // 座標を270にする
                }
                else {                       // 今処理しているのが、選択番号以外なら
                    MenuElement[i].x = 300;// 座標を300にする
                }
            }
        }


        // 描画フェーズ

        LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE);  //背景
        LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE);  //スコアロゴ
        for (int i = 0; i < 5; i++) { // メニュー項目を描画
            DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

            SetFontSize(32);
            SetFontThickness(4);
            ChangeFontType(DX_FONTTYPE_ANTIALIASING);
        }
    }
    return 0;
}

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#4

投稿記事 by 参照魚 » 3年前

SceneTitle,SceneScoreの中にあるwhile (ScreenFlip() == 0...){ コード }の部分は、whileループを外して、中のコードを剥き出しにします。あと、ゲーム画面のコードもSceneGameにします。WinMain部分はその次に考えます。

souta

Re: ゲームの画面切り替えについて

#5

投稿記事 by souta » 3年前

こうですか?

コード:

#include "DxLib.h"

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

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

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;

int SceneTitle(void) {
    SetGraphMode(800, 600, 32); //画面の解像度指定


    // メニュー項目要素を2つ作る
    MenuElement_t MenuElement[2] = {
            { 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
            { 380, 400, "ゲーム終了" },
    };
    int SelectNum = 0; // 現在の選択番号

    // while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)

        // 計算フェーズ 

        if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

            SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

            for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
                if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                    MenuElement[i].x = 350; // 座標を320にする
                }
                else {                       // 今処理しているのが、選択番号以外なら
                    MenuElement[i].x = 380;// 座標を350にする
                }
            }
        }


        // 描画フェーズ

        LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE);  //背景
        LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE);  //タイトルロゴ
        for (int i = 0; i < 5; i++) { // メニュー項目を描画
            DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

            SetFontSize(32);
            SetFontThickness(4);
            ChangeFontType(DX_FONTTYPE_ANTIALIASING);
        }


    }
    return 0;

int SceneGame{

    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) {
        LoadGraphScreen(1, 1, "a0.png", TRUE);
        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(0, 0, 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, 0, 0), "GOOD");
                            judge_time = JUDGE_DISPLAY_TIME;
                        }
                    }
                }
            }
        }
        if (judge != NONE) {
            if (judge == GOOD) {
                DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
                // GOODを描画する (テキスト・画像など)
            }
            else if (judge == MISS) {
                DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
                // MISSを描画する (テキスト・画像など)
            }
            judge_time--;
            if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
        }

        //判定ライン描画
        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; //正常終了
}

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

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;


int SceneScore(void) {
    SetBackgroundColor(255, 255, 255);
    ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定

    SetMainWindowText("スコア画面"); //ウインドウのタイトルを設定
    SetGraphMode(800, 600, 32); //画面の解像度指定



    // メニュー項目要素を2つ作る
    MenuElement_t MenuElement[2] = {
            { 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
            { 300, 450, "タイトルへ戻る" },
    };
    int SelectNum = 0; // 現在の選択番号

    // while(裏画面を表画面に反映, メッセージ処理, 画面クリア, キー更新)

        // 計算フェーズ 

        if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

            SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

            for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
                if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                    MenuElement[i].x = 270; // 座標を270にする
                }
                else {                       // 今処理しているのが、選択番号以外なら
                    MenuElement[i].x = 300;// 座標を300にする
                }
            }
        }


        // 描画フェーズ

        LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE);  //背景
        LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE);  //スコアロゴ
        for (int i = 0; i < 5; i++) { // メニュー項目を描画
            DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

            SetFontSize(32);
            SetFontThickness(4);
            ChangeFontType(DX_FONTTYPE_ANTIALIASING);
        }
    }
    return 0;

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#6

投稿記事 by 参照魚 » 3年前

SceneGameについてもSceneTitle,SceneScoreと同様にDxLibのシステムの初期化と後始末に関連する部分を削除して、whileループを外します。各画面のコードはファイルを分けた方が管理しやすいので、それぞれSceneGame.c SceneTitle.c SceneScore.cに記述してください。

souta

Re: ゲームの画面切り替えについて

#7

投稿記事 by souta » 3年前

直しました
<タイトルのコード>

コード:

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

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;

int SceneTitle(void) {
    SetGraphMode(800, 600, 32); //画面の解像度指定


    // メニュー項目要素を2つ作る
    MenuElement_t MenuElement[2] = {
            { 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
            { 380, 400, "ゲーム終了" },
    };
    int SelectNum = 0; // 現在の選択番号

        // 計算フェーズ 

    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
            if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 350; // 座標を320にする
            }
            else {                       // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 380;// 座標を350にする
            }
        }
    }

    // 描画フェーズ

    LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE);  //背景
    LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE);  //タイトルロゴ
    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }


}
return 0;
<ゲームのコード>

コード:

#include "DxLib.h"

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

int SceneGame{

    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); //画面サイズ変更不可
    SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
    enum  judge_value {
        NONE, GOOD, MISS
    };
    const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
    judge_value judge = NONE; // 表示中の判定
    int judge_time = 10; // 判定を表示する残り時間 (フレーム数)

        LoadGraphScreen(1, 1, "a0.png", TRUE);
        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;
                        DrawFormatString(10, 10, GetColor(0, 0, 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, 0, 0), "GOOD");
                            judge_time = JUDGE_DISPLAY_TIME;
                        }
                    }
                }
            }
        }
        if (judge != NONE) {
            if (judge == GOOD) {
                DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
                // GOODを描画する (テキスト・画像など)
            }
            else if (judge == MISS) {
                DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
                // MISSを描画する (テキスト・画像など)
            }
            judge_time--;
            if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
        }

        //判定ライン描画
        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);
                }
            }
        }
    }
    return 0; //正常終了
<スコアのコード>

コード:

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

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;


int SceneScore(void) {
    SetBackgroundColor(255, 255, 255);
    ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK); //ウィンドウモード変更と初期化と裏画面設定

    SetMainWindowText("スコア画面"); //ウインドウのタイトルを設定
    SetGraphMode(800, 600, 32); //画面の解像度指定



    // メニュー項目要素を2つ作る
    MenuElement_t MenuElement[2] = {
            { 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
            { 300, 450, "タイトルへ戻る" },
    };
    int SelectNum = 0; // 現在の選択番号

        // 計算フェーズ 

    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
            if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 270; // 座標を270にする
            }
            else {                       // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 300;// 座標を300にする
            }
        }
    }


    // 描画フェーズ

    LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE);  //背景
    LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE);  //スコアロゴ
    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }
}
return 0;

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#8

投稿記事 by 参照魚 » 3年前

・いずれも最後の return の位置がおかしいです
・int SceneGameの書式がおかしいです
・while ループを外したことに伴い、while から抜け出す break; は return 0; に変更する必要があります。

編集するごとにビルドが通るかこまめに確認しないとあとが大変になるので注意が必要です。

souta

Re: ゲームの画面切り替えについて

#9

投稿記事 by souta » 3年前

一応通るようになりました!
<タイトルのコード>

コード:

#include "DxLib.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;
}

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;

int SceneTitle(void) {
    SetGraphMode(800, 600, 32); //画面の解像度指定

    // メニュー項目要素を2つ作る
    MenuElement_t MenuElement[2] = {
            { 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
            { 380, 400, "ゲーム終了" },
    };
    int SelectNum = 0; // 現在の選択番号

    // 計算フェーズ 

    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
            if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 350; // 座標を320にする
            }
            else {                       // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 380;// 座標を350にする
            }
        }
    }

    // 描画フェーズ

    LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE);  //背景
    LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE);  //タイトルロゴ
    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }
}
<ゲームのコード>

コード:

#include "DxLib.h"

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

int SceneGame(void) {

    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); //画面サイズ変更不可
    SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定
    enum  judge_value {
        NONE, GOOD, MISS
    };
    const int JUDGE_DISPLAY_TIME = 30; // 判定を表示する時間 (フレーム数)
    judge_value judge = NONE; // 表示中の判定
    int judge_time = 10; // 判定を表示する残り時間 (フレーム数)

        LoadGraphScreen(1, 1, "a0.png", TRUE);
        if (buf[KEY_INPUT_ESCAPE] == 1) {
            return 0; // 終了
        }
        //時間関係
        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;
                        DrawFormatString(10, 10, GetColor(0, 0, 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, 0, 0), "GOOD");
                            judge_time = JUDGE_DISPLAY_TIME;
                        }
                    }
                }
            }
        }
        if (judge != NONE) {
            if (judge == GOOD) {
                DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
                // GOODを描画する (テキスト・画像など)
            }
            else if (judge == MISS) {
                DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
                // MISSを描画する (テキスト・画像など)
            }
            judge_time--;
            if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
        }

        //判定ライン描画
        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);
                }
            }
        }
    }
<スコアのコード>

コード:

#include "DxLib.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;
}

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;


int SceneScore(void) {
    SetBackgroundColor(255, 255, 255);
    SetMainWindowText("スコア画面"); //ウインドウのタイトルを設定
    SetGraphMode(800, 600, 32); //画面の解像度指定

    // メニュー項目要素を2つ作る
    MenuElement_t MenuElement[2] = {
            { 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
            { 300, 450, "タイトルへ戻る" },
    };
    int SelectNum = 0; // 現在の選択番号

    // 計算フェーズ 

    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
            if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 270; // 座標を270にする
            }
            else {                       // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 300;// 座標を300にする
            }
        }
    }


    // 描画フェーズ

    LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE);  //背景
    LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE);  //スコアロゴ
    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }
}

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#10

投稿記事 by 参照魚 » 3年前

各画面のSceneXXXX関数内で定義している変数を関数の外に出してstaticを付けてください。
SceneTitle と SceneScore の int Key[256]だけはexternにします。また、int gpUpdateKey()関数はでは使用されていないので削除します。

<タイトルのコード>

コード:

#include "DxLib.h"

extern int Key[256]; // キーが押されているフレーム数を格納する

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;

static MenuElement_t MenuElement[2] = {
	{ 350, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
	{ 380, 400, "ゲーム終了" },
};

static int SelectNum = 0; // 現在の選択番号

int SceneTitle(void) {
	// 計算フェーズ
    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
            if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 350; // 座標を320にする
            }
            else {                       // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 380;// 座標を350にする
            }
        }
    }

    // 描画フェーズ
    LoadGraphScreen(0, 0, "gahag-0073412840-1.png", TRUE);  //背景
    LoadGraphScreen(220, 75, "cooltext373677233987331.png", TRUE);  //タイトルロゴ
    for (int i = 0; i < 5; i++) { // メニュー項目を描画
		DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }

	return 0;
}
<ゲームのコード>

コード:

#include "DxLib.h"

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

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

static bool bar_f[LANE_SIZE][BAR_SIZE] = {}; //barの存在フラグ
static float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標

static LONGLONG start_time; //開始した時刻
static LONGLONG now_time; //現在のフレームの時刻
static int currentTime; //開始してからの経過時間
static int counter = 0;
static const int bpm = 120;

enum  judge_value {
		NONE, GOOD, MISS
};

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

int SceneGame( void ){
	LoadGraphScreen(1, 1, "a0.png", TRUE);
	if (buf[KEY_INPUT_ESCAPE] == 1) {
		return 0; // 終了
	}
	//時間関係
	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;
					DrawFormatString(10, 10, GetColor(0, 0, 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, 0, 0), "GOOD");
						judge_time = JUDGE_DISPLAY_TIME;
					}
				}
			}
		}
	}
	if (judge != NONE) {
		if (judge == GOOD) {
			DrawFormatString(10, 10, GetColor(255, 0, 0), "GOOD");
			// GOODを描画する (テキスト・画像など)
		}
		else if (judge == MISS) {
			DrawFormatString(10, 10, GetColor(0, 0, 255), "MISS");
			// MISSを描画する (テキスト・画像など)
		}
		judge_time--;
		if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
	}

	//判定ライン描画
	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);
			}
		}
	}
	return 0; //正常終了
}
<スコアのコード>

コード:

#include "DxLib.h"

extern int Key[256]; // キーが押されているフレーム数を格納する

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;

static MenuElement_t MenuElement[2] = {
	{ 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
	{ 300, 450, "タイトルへ戻る" },
};

static int SelectNum = 0; // 現在の選択番号

int SceneScore(void) {
	// 計算フェーズ
    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
            if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 270; // 座標を270にする
            }
            else {                       // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 300;// 座標を300にする
            }
        }
    }

    // 描画フェーズ
    LoadGraphScreen(0, 0, "hanakazari_waku_ao.png", TRUE);  //背景
    LoadGraphScreen(270, 75, "cooltext373678716545718.png", TRUE);  //スコアロゴ
    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);

        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }
	return 0;
}

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#11

投稿記事 by 参照魚 » 3年前

WinMainはmain.cに作成してください。これまで各画面で行っていたDxLibの設定やWhileループはここで行います。while ループの中でここまでに作成したSceneTitle/SceneGame/SceneScoreを呼び出すことになります。どれを呼び出すかは変数(int SceneMode)を用意して切り替えます。タイトル画面が表示されるか確認してください。これでとりあえず画面切り替えの骨格は完成です。

コード:

#include "DxLib.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅

extern int gpUpdateKey();

static int	SceneMode = 0;

extern SceneTitle( void );
extern SceneGame( void );
extern SceneScore( void );

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

	ChangeWindowMode(TRUE);			//ウィンドウモードで起動
	SetGraphMode(WIN_W, WIN_H, 32); 		//画面の解像度指定
	SetMainWindowText("リズムの達人"); 	//ウインドウのタイトルを設定
        SetBackgroundColor(255, 255, 255);

	if (DxLib_Init() == -1) { return -1; } 		//DxLib初期化処理

	SetWindowSizeChangeEnableFlag(FALSE);	//画面サイズ変更不可
	SetDrawScreen(DX_SCREEN_BACK);		//描画先を裏画面に設定

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
		switch ( SceneMode ) {
		case 0: SceneTitle();	break;
		case 1: SceneGame();	break;
		case 2: SceneScore();	break;
		}
	}

	DxLib_End();						// DxLib終了処理

	return 0;
}

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

souta

Re: ゲームの画面切り替えについて

#12

投稿記事 by souta » 3年前

アドバイスされたコードにしたらこのようなエラーが出ました。

・エラー LNK2001 外部シンボル "int * Key" (?Key@@3PAHA) は未解決です リズムゲーム 1行目
・エラー LNK2001 外部シンボル "int * Key" (?Key@@3PAHA) は未解決です リズムゲーム 1行目
・エラー LNK2019 未解決の外部シンボル _WinMain@16 が
関数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) で参照されました リズムゲーム  1行目
・エラー LNK1120 2 件の未解決の外部参照 リズムゲーム 1行目

souta

Re: ゲームの画面切り替えについて

#13

投稿記事 by souta » 3年前

すいません、追加のアドバイス試してみます!

souta

Re: ゲームの画面切り替えについて

#14

投稿記事 by souta » 3年前

Main.cppを教えていただいた通り作成したのですが10行目11行目12行目のコードにエラーが出ます。
明示的な型がありません ('int' が想定されます) と表示されています。

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#15

投稿記事 by 参照魚 » 3年前

戻り値の型が抜けていました。

extern SceneTitle( void );
extern SceneGame( void );
extern SceneScore( void );

extern int SceneTitle( void );
extern int SceneGame( void );
extern int SceneScore( void );

souta

Re: ゲームの画面切り替えについて

#16

投稿記事 by souta » 3年前

無事タイトル画面表示されました!!

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#17

投稿記事 by 参照魚 » 3年前

キー入力でSceneModeを変更できるようにして各画面が出るか確認してください。

コード:

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
		if (Key[KEY_INPUT_Z] == 1) { SceneMode = 0;	}
		if (Key[KEY_INPUT_X] == 1) { SceneMode = 1;	}
		if (Key[KEY_INPUT_C] == 1) { SceneMode = 2;	}

		switch ( SceneMode ) {
		case 0: SceneTitle();	break;
		case 1: SceneGame();	break;
		case 2: SceneScore();	break;
		}
	}
なお、各画面は1回だけしか正常に実行されない可能性があります。例えばタイトル→ゲーム→タイトルと遷移した場合、2回目のタイトルで挙動が変になったり、最悪はハングするかもしれません。それへの対処は次の段階になります。

souta

Re: ゲームの画面切り替えについて

#18

投稿記事 by souta » 3年前

27行目28行目29行目に 'Key': 定義されていない識別子です。とエラーが出ます。
<Main.p>

コード:

#include "DxLib.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅

extern int gpUpdateKey();

static int	SceneMode = 0;

extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);

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

	ChangeWindowMode(TRUE);			//ウィンドウモードで起動
	SetGraphMode(WIN_W, WIN_H, 32); 		//画面の解像度指定
	SetMainWindowText("リズムの達人"); 	//ウインドウのタイトルを設定
	SetBackgroundColor(255, 255, 255);

	if (DxLib_Init() == -1) { return -1; } 		//DxLib初期化処理

	SetWindowSizeChangeEnableFlag(FALSE);	//画面サイズ変更不可
	SetDrawScreen(DX_SCREEN_BACK);		//描画先を裏画面に設定

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
		if (Key[KEY_INPUT_Z] == 1) { SceneMode = 0; }
		if (Key[KEY_INPUT_X] == 1) { SceneMode = 1; }
		if (Key[KEY_INPUT_C] == 1) { SceneMode = 2; }

		switch (SceneMode) {
		case 0: SceneTitle();	break;
		case 1: SceneGame();	break;
		case 2: SceneScore();	break;
		}
	}

	DxLib_End();						// DxLib終了処理

	return 0;
}

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

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#19

投稿記事 by 参照魚 » 3年前

Keyは43行目に定義されています。使用する場所より前の適切な位置でextern 宣言をしてKeyを参照できるようにしてください。

souta

Re: ゲームの画面切り替えについて

#20

投稿記事 by souta » 3年前

無事に切り替えできました。

souta

Re: ゲームの画面切り替えについて

#21

投稿記事 by souta » 3年前

タイトル画面でゲームスタートとゲーム終了を選べるようにしたいのですが、ゲーム終了を入力したらウインドウを閉じるコードもよければ教えてほしいです!

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#22

投稿記事 by 参照魚 » 3年前

実際に画面選択する前にもう少し準備が必要です。menu.hを作成して、main.c/SceneTitle.c/SceneGame.c/SceneScore.cのそれぞれでインクルードしてください。

<menu.h>

コード:

#pragma once
enum {
	SCENE_GAMEOVER= -1,
	SCENE_TITLE,
	SCENE_GAME,
	SCENE_SCORE,
};
画面切り替え用の変数SceneNextを追加する。

コード:

static int	SceneMode = SCENE_TITLE;
static int	SceneNext;
これまで数値で直接書いていた画面の番号をenumで置き換える。

コード:

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {
		switch (SceneMode) {
		case SCENE_TITLE: SceneNext = SceneTitle();	break;
		case SCENE_GAME: SceneNext = SceneGame();	break;
		case SCENE_SCORE: SceneNext = SceneScore();	break;
		}
		
		if ( SceneNext == SCENE_GAMEOVER ) {
			break;
		}
	}

souta

Re: ゲームの画面切り替えについて

#23

投稿記事 by souta » 3年前

menu.hの3行目に ’}’が必要です とエラーが出ます。
main.pに識別子 "SCENE_GAMEOVER" が定義されていません 識別子 "SCENE_SCORE" が定義されていません
識別子 "SCENE_GAME" が定義されていません 識別子 "SCENE_TITLE" が定義されていません
識別子 "SCENE_TITLE" が定義されていません とエラーが出ます。

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#24

投稿記事 by 参照魚 » 3年前

SCENE_GAMEOVER= -1, =が全角になってました。半角に修正してください。

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#25

投稿記事 by 参照魚 » 3年前

ここまでの流れに直接関係ないですが、SceneTitle.c/SceneScore.cでMenuElement_tという同じ構造体をそれぞれのファイル内で宣言されています。複数のファイルで共通に使用される#defineや構造体はヘッダファイルに集約すると後々の管理/修正が容易になります。

<menu.h>

コード:

#pragma once
enum {
	SCENE_GAMEOVER =  -1,
	SCENE_TITLE,
	SCENE_GAME,
	SCENE_SCORE,
};

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;
menu.hで宣言したら、SceneTitle.c/SceneScore.cからは削除します。

souta

Re: ゲームの画面切り替えについて

#26

投稿記事 by souta » 3年前

main.pのエラーはどうやって直しますか?
"SCENE_GAMEOVER"と"SCENE_SCORE"と"SCENE_GAME"と"SCENE_TITLE"と"SCENE_TITLE" が定義されていませんとでます。

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#27

投稿記事 by 参照魚 » 3年前

>main.c/SceneTitle.c/SceneGame.c/SceneScore.cのそれぞれでインクルードしてください。
main.cに#include "menu.h"するのを忘れていませんか?

souta

Re: ゲームの画面切り替えについて

#28

投稿記事 by souta » 3年前

'SceneMode': 再定義されています。2 回以上初期化されています。とエラーが出ます。

コード:

#include "DxLib.h"
#include "menu.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅

extern int gpUpdateKey();

static int	SceneMode = 0;

static int	SceneMode = SCENE_TITLE;
static int	SceneNext;

extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);

extern int Key[256]; // キーが押されているフレーム数を格納する

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

	ChangeWindowMode(TRUE);			//ウィンドウモードで起動
	SetGraphMode(WIN_W, WIN_H, 32); 		//画面の解像度指定
	SetMainWindowText("リズムの達人"); 	//ウインドウのタイトルを設定
	SetBackgroundColor(255, 255, 255);

	if (DxLib_Init() == -1) { return -1; } 		//DxLib初期化処理

	SetWindowSizeChangeEnableFlag(FALSE);	//画面サイズ変更不可
	SetDrawScreen(DX_SCREEN_BACK);		//描画先を裏画面に設定

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {

		switch (SceneMode) {
		case SCENE_TITLE: SceneNext = SceneTitle();	break;
		case SCENE_GAME: SceneNext = SceneGame();	break;
		case SCENE_SCORE: SceneNext = SceneScore();	break;
		}

		if (SceneNext == SCENE_GAMEOVER) {
			break;
		}
	}

	DxLib_End();						// DxLib終了処理

	return 0;
}

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

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#29

投稿記事 by 参照魚 » 3年前

9行目の方のSceneMode = 0 は削除してください。


souta

Re: ゲームの画面切り替えについて

#31

投稿記事 by souta » 3年前

切り替えの仕方はどうやってするのでしょうか?前のコードではキーボード入力で切り替えできていたのですが。

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#32

投稿記事 by 参照魚 » 3年前

SceneTitle/SceneGame/SceneScoreの各関数は返り値にシーン番号を返すように修正してください。main.cの下記のswitch文は実行された各画面の返り値で次に実行する画面を受け取ります。

コード:

switch (SceneMode) {
case SCENE_TITLE: SceneNext = SceneTitle();	break;
case SCENE_GAME: SceneNext = SceneGame();	break;
case SCENE_SCORE: SceneNext = SceneScore();	break;
}
例えばSceneTitleであれば、概念的に下記のとおりとなります。

コード:

int SceneTitle( void )
   :
   省略
   :
   return SCENE_TITLE;
}
このままであればタイトル画面が実行されつづけます。キーボードの入力で切り替える場合は下記のようになります。

コード:

int SceneTitle( void )
   :
   省略
   :
   if ( Key[KEY_INPUT_A] == 1 ) { // キーの種類は適当
   	switch ( SelectNum ) {
   	case 0: return SCENE_GAME;
   	case 1: return SCENE_GAMEOVER;
   	}
   }
   return SCENE_TITLE;
}

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#33

投稿記事 by 参照魚 » 3年前

main.cではSceneNextを受け取ってSceneModeを切り替えます。

コード:

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {

		switch (SceneMode) {
		case SCENE_TITLE: SceneNext = SceneTitle();	break;
		case SCENE_GAME: SceneNext = SceneGame();	break;
		case SCENE_SCORE: SceneNext = SceneScore();	break;
		}

		if (SceneNext == SCENE_GAMEOVER) {
			break;
		}
		
		if ( SceneNext != SceneMode ) {
			SceneMode = SceneNext;
		}

souta

Re: ゲームの画面切り替えについて

#34

投稿記事 by souta » 3年前

タイトル画面の46行目47行目50行目に 識別子 "SCENE_TITLE" が定義されていません 識別子 "SCENE_GAME" が定義されていません 識別子 "SCENE_GAMEOVER" が定義されていません とそれぞれエラーが出ます。

<タイトル画面のコード>

コード:

#include "DxLib.h"

extern int Key[256]; // キーが押されているフレーム数を格納する

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;

static MenuElement_t MenuElement[2] = {
    { 300, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
    { 330, 400, "ゲーム終了" },
};

static int SelectNum = 0; // 現在の選択番号

int SceneTitle(void) {
    LoadGraphScreen(0, 0, "001.png", TRUE);  //背景
    LoadGraphScreen(180, 120, "002.png", TRUE);  //タイトルロゴ
    
    // 計算フェーズ
    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
            if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 300; // 座標を320にする
            }
            else {                       // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 330;// 座標を350にする
            }
        }
    }

    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }
    
    if (Key[KEY_INPUT_Z] == 1) { // キーの種類は適当
        switch (SelectNum) {
        case 0: return SCENE_GAME;
        case 1: return SCENE_GAMEOVER;
        }
    }
    return SCENE_TITLE;
}
<Main.c>

コード:

#include "DxLib.h"
#include "menu.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅

extern int gpUpdateKey();

static int	SceneMode = SCENE_TITLE;
static int	SceneNext;

extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);

extern int Key[256]; // キーが押されているフレーム数を格納する

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

	ChangeWindowMode(TRUE);			//ウィンドウモードで起動
	SetGraphMode(WIN_W, WIN_H, 32); 		//画面の解像度指定
	SetMainWindowText("リズムの達人"); 	//ウインドウのタイトルを設定
	SetBackgroundColor(255, 255, 255);

	if (DxLib_Init() == -1) { return -1; } 		//DxLib初期化処理

	SetWindowSizeChangeEnableFlag(FALSE);	//画面サイズ変更不可
	SetDrawScreen(DX_SCREEN_BACK);		//描画先を裏画面に設定

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {

		switch (SceneMode) {
		case SCENE_TITLE: SceneNext = SceneTitle();	break;
		case SCENE_GAME: SceneNext = SceneGame();	break;
		case SCENE_SCORE: SceneNext = SceneScore();	break;
		}

		if (SceneNext == SCENE_GAMEOVER) {
			break;
		}

		if (SceneNext != SceneMode) {
			SceneMode = SceneNext;
		}

	DxLib_End();						// DxLib終了処理

	return 0;
}

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

souta

Re: ゲームの画面切り替えについて

#35

投稿記事 by souta » 3年前

あと、Main.cの54行目に ';' が必要です 'gpUpdateKey': ローカル関数の定義が正しくありません。とエラーが出ます。

souta

Re: ゲームの画面切り替えについて

#36

投稿記事 by souta » 3年前

このように直したらエラー出なくなりました。大丈夫でしょうか?

コード:

int gpUpdateKey();

souta

Re: ゲームの画面切り替えについて

#37

投稿記事 by souta » 3年前

また自分で直してみたのですが、今度はタイトルとスコアのコードの10行目に 'MenuElement_t': 再定義されています。異なる基本型です。 とエラーが出ます。

<タイトル>

コード:

#include "DxLib.h"
#include "menu.h"

extern int Key[256]; // キーが押されているフレーム数を格納する

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;

static MenuElement_t MenuElement[2] = {
    { 300, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
    { 330, 400, "ゲーム終了" },
};

static int SelectNum = 0; // 現在の選択番号

int SceneTitle(void) {
    LoadGraphScreen(0, 0, "001.png", TRUE);  //背景
    LoadGraphScreen(180, 120, "002.png", TRUE);  //タイトルロゴ
    
    // 計算フェーズ
    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
            if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 300; // 座標を320にする
            }
            else {                       // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 330;// 座標を350にする
            }
        }
    }

    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }
    
    if (Key[KEY_INPUT_Z] == 1) { // キーの種類は適当
        switch (SelectNum) {
        case 0: return SCENE_GAME;
        case 1: return SCENE_GAMEOVER;
        }
    }
    return SCENE_TITLE;
}
<スコア>

コード:

#include "DxLib.h"
#include "menu.h"

extern int Key[256]; // キーが押されているフレーム数を格納する

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
    int x, y;       // 座標格納用変数
    char name[128]; // 項目名格納用変数
} MenuElement_t;

static MenuElement_t MenuElement[2] = {
    { 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
    { 300, 450, "タイトルへ戻る" },
};

static int SelectNum = 0; // 現在の選択番号

int SceneScore(void) {
    // 計算フェーズ
    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {         // メニュー項目数である2個ループ処理
            if (i == SelectNum) {            // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 270;     // 座標を270にする
            }
            else {                         // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 300;   // 座標を300にする
            }
        }
    }

    // 描画フェーズ
    LoadGraphScreen(0, 0, "004.png", TRUE);  //背景
    LoadGraphScreen(270, 75, "003.png", TRUE);  //スコアロゴ
    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }
    if (Key[KEY_INPUT_C] == 1) { // キーの種類は適当
        switch (SelectNum) {
        case 0: return SCENE_TITLE;
        case 1: return SCENE_GAMEOVER;
        }
    }
    return SCENE_SCORE;
}
<menu.h>

コード:

#pragma once
enum {
	SCENE_GAMEOVER = -1,
	SCENE_TITLE,
	SCENE_GAME,
	SCENE_SCORE,
};

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
	int x, y;       // 座標格納用変数
	char name[128]; // 項目名格納用変数
} MenuElement_t;

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#38

投稿記事 by 参照魚 » 3年前

タイトルとスコアのMenuElement_tの宣言は、menu.hをインクルードしているので必要ありません。

souta

Re: ゲームの画面切り替えについて

#39

投稿記事 by souta » 3年前

消したのですが、また別のエラーが出ます。
LNK2001 外部シンボル "int * Key" (?Key@@3PAHA) は未解決です C:\ckadai\リズムゲーム\リズムゲーム.obj
LNK2001 外部シンボル "int * Key" (?Key@@3PAHA) は未解決です C:\ckadai\リズムゲーム\タイトル.obj
LNK2001 外部シンボル "int * Key" (?Key@@3PAHA) は未解決です C:\ckadai\リズムゲーム\スコア.obj
LNK2019 未解決の外部シンボル "int __cdecl gpUpdateKey(void)" (?gpUpdateKey@@YAHXZ) が関数 _WinMain@16 で参照されました C:\ckadai\リズムゲーム\Main.obj
とでます。

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#40

投稿記事 by 参照魚 » 3年前

main.cからint Key[256]とint gpUpdateKey(void)をコメントアウトかなにかしましたか?

souta

Re: ゲームの画面切り替えについて

#41

投稿記事 by souta » 3年前

コード送ります。変なところありますか?
<main.c>

コード:

#include "DxLib.h"
#include "menu.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅

extern int gpUpdateKey();

static int	SceneMode = SCENE_TITLE;
static int	SceneNext;

extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);

extern int Key[256]; // キーが押されているフレーム数を格納する

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

	ChangeWindowMode(TRUE);			//ウィンドウモードで起動
	SetGraphMode(WIN_W, WIN_H, 32); 		//画面の解像度指定
	SetMainWindowText("リズムの達人"); 	//ウインドウのタイトルを設定
	SetBackgroundColor(255, 255, 255);

	if (DxLib_Init() == -1) { return -1; } 		//DxLib初期化処理

	SetWindowSizeChangeEnableFlag(FALSE);	//画面サイズ変更不可
	SetDrawScreen(DX_SCREEN_BACK);		//描画先を裏画面に設定

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {

		switch (SceneMode) {
		case SCENE_TITLE: SceneNext = SceneTitle();	break;
		case SCENE_GAME: SceneNext = SceneGame();	break;
		case SCENE_SCORE: SceneNext = SceneScore();	break;
		}

		if (SceneNext == SCENE_GAMEOVER) {
			break;
		}

		if (SceneNext != SceneMode) {
			SceneMode = SceneNext;
		}

	DxLib_End();						// DxLib終了処理

	return 0;
}

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

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#42

投稿記事 by 参照魚 » 3年前

①②のところがコードの意味として間違っています

コード:

	DxLib_End();						// DxLib終了処理

	return 0;
	}
}  //①

int Key[256]; // キーが押されているフレーム数を格納する

// キーの入力状態を更新する
int gpUpdateKey(){ // ②
	char tmpKey[256];	

souta

Re: ゲームの画面切り替えについて

#43

投稿記事 by souta » 3年前

正直、理解が浅くてどうすればいいか良く分かりません。すみません。
18行目に '{': 一致するトークンが見つかりませんでした。とでます。

コード:

#include "DxLib.h"
#include "menu.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅

extern int gpUpdateKey();

static int	SceneMode = SCENE_TITLE;
static int	SceneNext;

extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);

extern int Key[256]; // キーが押されているフレーム数を格納する

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

	ChangeWindowMode(TRUE);			//ウィンドウモードで起動
	SetGraphMode(WIN_W, WIN_H, 32); 		//画面の解像度指定
	SetMainWindowText("リズムの達人"); 	//ウインドウのタイトルを設定
	SetBackgroundColor(255, 255, 255);

	if (DxLib_Init() == -1) { return -1; } 		//DxLib初期化処理

	SetWindowSizeChangeEnableFlag(FALSE);	//画面サイズ変更不可
	SetDrawScreen(DX_SCREEN_BACK);		//描画先を裏画面に設定

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {

		switch (SceneMode) {
		case SCENE_TITLE: SceneNext = SceneTitle();	break;
		case SCENE_GAME: SceneNext = SceneGame();	break;
		case SCENE_SCORE: SceneNext = SceneScore();	break;
		}

		if (SceneNext == SCENE_GAMEOVER) {
			break;
		}

		if (SceneNext != SceneMode) {
			SceneMode = SceneNext;
		}

		DxLib_End();						// DxLib終了処理

		return 0;
	}

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

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#44

投稿記事 by 参照魚 » 3年前

これでまだエラーになるようなら、menu.hのコードをお知らせください。

コード:

#include "DxLib.h"
#include "menu.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅

extern int gpUpdateKey();

static int	SceneMode = SCENE_TITLE;
static int	SceneNext;

extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);

extern int Key[256]; // キーが押されているフレーム数を格納する

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

	ChangeWindowMode(TRUE);			//ウィンドウモードで起動
	SetGraphMode(WIN_W, WIN_H, 32); 		//画面の解像度指定
	SetMainWindowText("リズムの達人"); 	//ウインドウのタイトルを設定
	SetBackgroundColor(255, 255, 255);

	if (DxLib_Init() == -1) { return -1; } 		//DxLib初期化処理

	SetWindowSizeChangeEnableFlag(FALSE);	//画面サイズ変更不可
	SetDrawScreen(DX_SCREEN_BACK);		//描画先を裏画面に設定

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {

		switch (SceneMode) {
		case SCENE_TITLE: SceneNext = SceneTitle();	break;
		case SCENE_GAME: SceneNext = SceneGame();	break;
		case SCENE_SCORE: SceneNext = SceneScore();	break;
		}

		if (SceneNext == SCENE_GAMEOVER) {
			break;
		}

		if (SceneNext != SceneMode) {
			SceneMode = SceneNext;
		}

		DxLib_End();						// DxLib終了処理

		return 0;
	}
}

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

souta

Re: ゲームの画面切り替えについて

#45

投稿記事 by souta » 3年前

エラーは出なくなりましたがデバックすると勝手にウインドウが閉じてしまいます。よければ全部のコードを送るのでチェックしてもらってもいいですか?丸投げとなってしまって申し訳ないです。
<main.c>

コード:

#include "DxLib.h"
#include "menu.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅

extern int gpUpdateKey();

static int	SceneMode = SCENE_TITLE;
static int	SceneNext;

extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);

extern int Key[256]; // キーが押されているフレーム数を格納する

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

	ChangeWindowMode(TRUE);			//ウィンドウモードで起動
	SetGraphMode(WIN_W, WIN_H, 32); 		//画面の解像度指定
	SetMainWindowText("リズムの達人"); 	//ウインドウのタイトルを設定
	SetBackgroundColor(255, 255, 255);

	if (DxLib_Init() == -1) { return -1; } 		//DxLib初期化処理

	SetWindowSizeChangeEnableFlag(FALSE);	//画面サイズ変更不可
	SetDrawScreen(DX_SCREEN_BACK);		//描画先を裏画面に設定

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {

		switch (SceneMode) {
		case SCENE_TITLE: SceneNext = SceneTitle();	break;
		case SCENE_GAME: SceneNext = SceneGame();	break;
		case SCENE_SCORE: SceneNext = SceneScore();	break;
		}

		if (SceneNext == SCENE_GAMEOVER) {
			break;
		}

		if (SceneNext != SceneMode) {
			SceneMode = SceneNext;
		}

		DxLib_End();						// DxLib終了処理

		return 0;
	}
}

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;
}
<タイトル>

コード:

#include "DxLib.h"
#include "menu.h"

extern int Key[256]; // キーが押されているフレーム数を格納する

static MenuElement_t MenuElement[2] = {
    { 300, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
    { 330, 400, "ゲーム終了" },
};

static int SelectNum = 0; // 現在の選択番号

int SceneTitle(void) {
    LoadGraphScreen(0, 0, "001.png", TRUE);  //背景
    LoadGraphScreen(180, 120, "002.png", TRUE);  //タイトルロゴ
    
    // 計算フェーズ
    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
            if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 300; // 座標を320にする
            }
            else {                       // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 330;// 座標を350にする
            }
        }
    }

    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }
    
    if (Key[KEY_INPUT_Z] == 1) { // キーの種類は適当
        switch (SelectNum) {
        case 0: return SCENE_GAME;
        case 1: return SCENE_GAMEOVER;
        }
    }
    return SCENE_TITLE;
}
<ゲーム>

コード:

#include "DxLib.h"
#include "menu.h"

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

extern int Key[256]; // キーが押されているフレーム数を格納する
static int SelectNum = 0; // 現在の選択番号

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

static bool bar_f[LANE_SIZE][BAR_SIZE] = {}; //barの存在フラグ
static float bar_y[LANE_SIZE][BAR_SIZE]; //barのY座標

static LONGLONG start_time; //開始した時刻
static LONGLONG now_time; //現在のフレームの時刻
static int currentTime; //開始してからの経過時間
static int counter = 0;
static const int bpm = 120;

enum  judge_value {
	NONE, GOOD, MISS
};

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

static int state = 0;
static int SHandle;
static int good;
static int miss;

int SceneGame(void) {
	int score;
	LoadGraphScreen(1, 1, "a0.png", TRUE);
	if (buf[KEY_INPUT_ESCAPE] == 1) {
		return 0; // 終了
	}

	SHandle = LoadSoundMem("ゆかいな日常.mp3");

	switch (state) {
	case 0:
		PlaySoundMem(SHandle, DX_PLAYTYPE_BACK);
		state = 1;
		break;
	case 1:
		if (CheckSoundMem(SHandle) == 0)
			state = 2;
			break;
	case 2:
		StopSoundMem(SHandle);
		DeleteSoundMem(SHandle);
	}

	//時間関係
	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;
					DrawFormatString(115, 300, GetColor(0, 0, 255), "MISS");
					judge_time = JUDGE_DISPLAY_TIME;
					PlaySoundMem(miss, DX_PLAYTYPE_BACK);
				}
			}
		}
	}

	// 判定
	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(115, 300, GetColor(255, 0, 0), "GOOD");
						judge_time = JUDGE_DISPLAY_TIME;
						PlaySoundMem(good, DX_PLAYTYPE_BACK);
					}
				}
			}
		}
	}
	if (judge != NONE) {
		if (judge == GOOD) {
			DrawFormatString(115, 300, GetColor(255, 0, 0), "GOOD");
			// GOODを描画する (テキスト・画像など)
		}
		else if (judge == MISS) {
			DrawFormatString(115, 300, GetColor(0, 0, 255), "MISS");
			// MISSを描画する (テキスト・画像など)
		}
		judge_time--;
		if (judge_time <= 0) judge = NONE; // 指定の時間が経過したら、判定を消す
	}

	//判定ライン描画
	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);
			}
		}
	}
	
	if (Key[KEY_INPUT_X] == 1) { // キーの種類は適当
		switch (SelectNum) {
		case 2: return SCENE_SCORE;
		}
	}
	return SCENE_GAME;
}
<スコア>

コード:

#include "DxLib.h"
#include "menu.h"

extern int Key[256]; // キーが押されているフレーム数を格納する


static MenuElement_t MenuElement[2] = {
    { 270, 400, "もう一度プレイする" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
    { 300, 450, "タイトルへ戻る" },
};

static int SelectNum = 0; // 現在の選択番号

int SceneScore(void) {
    // 計算フェーズ
    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {         // メニュー項目数である2個ループ処理
            if (i == SelectNum) {            // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 270;     // 座標を270にする
            }
            else {                         // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 300;   // 座標を300にする
            }
        }
    }

    // 描画フェーズ
    LoadGraphScreen(0, 0, "004.png", TRUE);  //背景
    LoadGraphScreen(270, 75, "003.png", TRUE);  //スコアロゴ
    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
        SetFontSize(32);
        SetFontThickness(4);
        ChangeFontType(DX_FONTTYPE_ANTIALIASING);
    }
    if (Key[KEY_INPUT_C] == 1) { // キーの種類は適当
        switch (SelectNum) {
        case 1: return SCENE_TITLE;
        case 2: return SCENE_GAMEOVER;
        }
    }
    return SCENE_SCORE;
}
<mune.h>

コード:

#pragma once
enum {
	SCENE_GAMEOVER = -1,
	SCENE_TITLE,
	SCENE_GAME,
	SCENE_SCORE,
};

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
	int x, y;       // 座標格納用変数
	char name[128]; // 項目名格納用変数
}MenuElement_t;

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#46

投稿記事 by 参照魚 » 3年前

DxLib_EndがWhileループの中に入っていました。

コード:

#include "DxLib.h"
#include "menu.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅

extern int gpUpdateKey();

static int	SceneMode = SCENE_TITLE;
static int	SceneNext;

extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);

extern int Key[256]; // キーが押されているフレーム数を格納する

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

	ChangeWindowMode(TRUE);			//ウィンドウモードで起動
	SetGraphMode(WIN_W, WIN_H, 32); 		//画面の解像度指定
	SetMainWindowText("リズムの達人"); 	//ウインドウのタイトルを設定
	SetBackgroundColor(255, 255, 255);

	if (DxLib_Init() == -1) { return -1; } 		//DxLib初期化処理

	SetWindowSizeChangeEnableFlag(FALSE);	//画面サイズ変更不可
	SetDrawScreen(DX_SCREEN_BACK);		//描画先を裏画面に設定

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {

		switch (SceneMode) {
		case SCENE_TITLE: SceneNext = SceneTitle();	break;
		case SCENE_GAME: SceneNext = SceneGame();	break;
		case SCENE_SCORE: SceneNext = SceneScore();	break;
		}

		if (SceneNext == SCENE_GAMEOVER) {
			break;
		}

		if (SceneNext != SceneMode) {
			SceneMode = SceneNext;
		}
	}

	DxLib_End();						// DxLib終了処理

	return 0;
}

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


souta

Re: ゲームの画面切り替えについて

#47

投稿記事 by souta » 3年前

無事切り替えができるようになったみたいです。長々とありがとうございました。丸投げのような感じになってしまい本当にすみませんでした。助言感謝します!!

参照魚
記事: 109
登録日時: 6年前

Re: ゲームの画面切り替えについて

#48

投稿記事 by 参照魚 » 3年前

ここまでで当初の質問の内容は達成できたと思います。ただこのままだと繰り返し切り替えをしていると挙動がおかしくなる可能性が残っています。最後にそれを解消するコードを提示します。

main.c

コード:

#include "DxLib.h"
#include "menu.h"

#define WIN_W 800 //ウインドウの横幅
#define WIN_H 600 //ウインドウの縦幅

static int	SceneMode = SCENE_GAMESTART;
static int	SceneNext = SCENE_TITLE;

extern void InitSceneTitle(void);
extern void InitSceneGame(void);
extern void InitSceneScore(void);
extern int SceneTitle(void);
extern int SceneGame(void);
extern int SceneScore(void);

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

	ChangeWindowMode(TRUE);			//ウィンドウモードで起動
	SetGraphMode(WIN_W, WIN_H, 32); 		//画面の解像度指定
	SetMainWindowText("リズムの達人"); 	//ウインドウのタイトルを設定
	SetBackgroundColor(255, 255, 255);

	if (DxLib_Init() == -1) { return -1; } 		//DxLib初期化処理

	SetWindowSizeChangeEnableFlag(FALSE);	//画面サイズ変更不可
	SetDrawScreen(DX_SCREEN_BACK);		//描画先を裏画面に設定

	while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && gpUpdateKey() == 0) {

		if (SceneNext != SceneMode) {
			switch (SceneMode) {
			case SCENE_TITLE: InitSceneTitle();	break;
			case SCENE_GAME : InitSceneGame();	break;
			case SCENE_SCORE: InitSceneScore();	break;
			}
			SceneMode = SceneNext;
		}

		switch (SceneMode) {
		case SCENE_TITLE: SceneNext = SceneTitle();	break;
		case SCENE_GAME : SceneNext = SceneGame();	break;
		case SCENE_SCORE: SceneNext = SceneScore();	break;
		}

		if (SceneNext == SCENE_GAMEOVER) {
			break;
		}
	}

	DxLib_End();						// DxLib終了処理

	return 0;
}

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;
}
menu.h

コード:

#pragma once
enum {
	SCENE_GAMESTART= -2,
	SCENE_GAMEOVER = -1,
	SCENE_TITLE,
	SCENE_GAME,
	SCENE_SCORE,
};

// メニュー項目の表示に必要な構造体を用意する
typedef struct {
	int x, y;       // 座標格納用変数
	char name[128]; // 項目名格納用変数
}MenuElement_t;

extern int Key[256]; // キーが押されているフレーム数を格納する
extern int gpUpdateKey();
SceneTitle.c
SceneGame.c/SceneScore.cも同様に変更します。

コード:

#include "DxLib.h"
#include "menu.h"

static MenuElement_t MenuElement[2] = {
    { 300, 300, "ゲームスタート" }, // タグの中身の順番で格納される。xに80が、yに100が、nameに"ゲームスタート"が
    { 330, 400, "ゲーム終了" },
};

static int SelectNum = 0; // 現在の選択番号

static int	background;
static int	titlelogo;

void InitSceneTitle(void) {

    background = LoadGraph( "001.png" );  //背景
    titlelogo  = LoadGraph( "002.png" );  //タイトルロゴ

	SetFontSize(32);
	SetFontThickness(4);
	ChangeFontType(DX_FONTTYPE_ANTIALIASING);
}

int SceneTitle(void) {

    DrawGraphScreen(  0,   0, background, TRUE);  //背景
    DrawGraphScreen(180, 120, titlelogo,  TRUE);  //タイトルロゴ

    // 計算フェーズ
    if (Key[KEY_INPUT_DOWN] == 1) { // 下キーが押された瞬間だけ処理

        SelectNum = (SelectNum + 1) % 2; // 現在の選択項目を一つ下にずらす(ループする)

        for (int i = 0; i < 2; i++) {              // メニュー項目数である2個ループ処理
            if (i == SelectNum) {          // 今処理しているのが、選択番号と同じ要素なら
                MenuElement[i].x = 300; // 座標を320にする
            }
            else {                       // 今処理しているのが、選択番号以外なら
                MenuElement[i].x = 330;// 座標を350にする
            }
        }
    }

    for (int i = 0; i < 5; i++) { // メニュー項目を描画
        DrawFormatString(MenuElement[i].x, MenuElement[i].y, GetColor(0, 0, 0), MenuElement[i].name);
    }

    if (Key[KEY_INPUT_Z] == 1) { // キーの種類は適当
        switch (SelectNum) {
        case 0: return SCENE_GAME;
        case 1: return SCENE_GAMEOVER;
        }
    }
    return SCENE_TITLE;
}
なお、こちらではビルド確認や動作確認はしていないので、やる場合はここまでの動作するコードはバックアップしておいてからにしてください。

souta

Re: ゲームの画面切り替えについて

#49

投稿記事 by souta » 3年前

返信遅くなりました。すいません。最後までありがとうございました!!

返信

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