タイピングゲーム 入力動作に関して1

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

タイピングゲーム 入力動作に関して1

#1

投稿記事 by Ken2929 » 1年前

ある程度タイピングゲームらしきものを作り直しました。

ループ処理でcsvにあるデータ、表示文字列、入力部分を読みこみお題をランダム生成するようにしてます
スペースキーを押すまでプログラムは動かない状態(待機画面)、またはBackSpaceを押すと一つシーン前(難易度選択画面)に戻るという選択項目を作ってます
スペースを押すと、ゲームがスタートし2つの白い文字列、表示文字列、入力文字列が画面の真ん中辺りに表示されローマ字入力すると入力した箇所には緑、間違えた部分は一瞬だけ赤で表示させて正解するまでは留まるという仕様にしてます
時間は60秒、現在の時刻を習得し、そこから0になるまで処理を継続するカウントダウンをしてます
Escキーを押すとポーズ的な(?)感じの画面を出し、1を選択したら最初から、2を選択したら続きから(時間だけはそのまま経過している(※バグ))、3を選択したら一つシーン前(難易度選択画面)に戻るというようにしています
goto系はあまり使わない方がいいと他の方に言われましたが、どうやってゲームスタート、リセット、またはコンテニューに戻れればいいのか分からなかったため今はこのプログラムにしてます。

問題
・お題を解いている最中たまに表示文字列、入力文字列部分に全て「フ」という謎のバグが発生している。
・Escキーを押すと一時的にゲームは止まりはしますが、時間が見えない形でカウントダウンし続けているため2を選択した場合時間が減っている。
・間違った箇所がほんの一瞬でしか赤で表示されない(間違った箇所は緑ではなく赤で表示し続けるにはどうすればいいか?)

表示文字列.csvはこのようになってます。
表示文字.csv
感情移入
先天性心疾患
財団
西郷隆盛
東京特許許可局
環境省
冷徹残忍
中高生対象
万歩計
大和西大寺駅
神戸電子専門学校
清濁併せ呑む
引かれ者の小唄
煮え湯を飲まされる
無い袖は振れない
灯台下暗し
青天の霹靂
紺屋の白袴
窮鼠猫を噛む
蛙の面に水
猿猴月を取る
木乃伊取りが木乃伊になる
武士は食わねど高楊枝
二度あることは三度ある
問うに落ちず語るに落ちる
月に叢雲花に風
故郷へ錦を飾る
弘法も筆の誤り
聞いて極楽見て地獄

入力部分の文字列はこれです。
打つ文字.csv
kanzyouinyuu
senntennseisikkann
zaidann
saigoutakamori
toukyoutokkyokyokakyoku
kankyousyou
reitetuzannninn
tyuukouseitaisyou
mannpokei
yamatosaidaizieki
koubedennsisenmongakkou
seidakuawasenomu
hikaremononokouta
nieyuwonomasareru
naisodehahurenai
toudaimotokurasi
seitennnohekireki
kouyanosirobakama
kyuusonekowokamu
kaerunoturanimizu
enkoutukiwotoru
miiratorigamiiraninaru
busihakuwanedotakayouzi
nidoarukotohasandoaru
touniotizukataruniotiru
tukinimurakumohaanikaze
kokyouhenisikiwokazaru
kouboumohudenoayamari
kiitegokurakumitezigoku

どういった原因で文字化け、Escキーを押した後何故タイムはカウントダウンし続けるのか?、間違った箇所の入力が一瞬、僅かな時間だけしか赤で表示されないのか
を教えていただけますか?

アドバイスお願いします。

コード:

#include "J1game.h"
#include "SceneMgr.h"
#include "DxLib.h"
#include "Keyboard.h"
#include "Sound.h"

//更新
void J1game_Update() {
    //画面出力色設定
    const auto color_white = GetColor(255, 255, 255);
    const auto color_red = GetColor(255, 0, 0);
    const auto color_green = GetColor(0, 255, 0);
    const auto color_blue = GetColor(0, 0, 255);

    //初めからゲームスタート、リセットポイント
    GAMESTART:

    //初期化、文字配列
    const int japan_string_size = 160;
    const int alpha_string_size = 40;
    const int example_count = 30;
    char japan_strings[example_count][japan_string_size]{};           //表示文字列
    char alpha_strings[example_count][alpha_string_size]{};           //打つ文字列
    char input_string[alpha_string_size]{};
    char input_char = 0;
    char miss = 0;
    int input_cursor = 0;
    int input_count = 0;
    int random_lot = 0;
    int start_time = 0;
    int x = 0;
    int answer_count = 0;
    int miss_count = 0;
    DATEDATA date;

    //表示させる文字データを読込む
    int file_japan = FileRead_open("./data/Typing/日本語/01.表示文字.csv");
    int file_alpha = FileRead_open("./data/Typing/日本語/03.打つ文字.csv");
    for (int i = 0; i < example_count; i++) {
        FileRead_gets(japan_strings[i], japan_string_size, file_japan);
        FileRead_gets(alpha_strings[i], alpha_string_size, file_alpha);
    }
    FileRead_close(file_japan);
    FileRead_close(file_alpha);

    //お題をランダム生成
    random_lot = GetRand(example_count);
    const char* japan_string = japan_strings[random_lot];
    const char* alpha_string = alpha_strings[random_lot];

    ClearDrawScreen();
    DrawString(0, 0, "J1 やさしい ゲームタイピング画面です。", color_white);
    DrawString(0, 20, "Escキー又はBackSpaceを押すとメニュー画面に戻ります。", color_white);
    DrawString(0, 40, "Spaceキーを押すとゲームが開始されます。", color_white);

    while (true) {
        if (CheckHitKey(KEY_INPUT_SPACE) == 1) break;     //スペースキーが押されたら下の処理に行く
        if (CheckHitKey(KEY_INPUT_BACK) == 0) {
            //一つ戻る、もしくは別の画面に移動させる
            SceneMgr_ChangeScene(eScene_J1);
            Sound_Update1();
            break;
        }
    }

    //現在時刻の入手
    GetDateTime(&date);
    //現在経過時間の入手
    start_time = GetNowCount();
    //コンテニュー
    GAMECONTINUE:

    // ESCキーが押されるか、何らかの内部エラーが発生するまでループする
    while (!ProcessMessage() && (CheckHitKey(KEY_INPUT_ESCAPE) == 0)) {
        //描画をクリアにする
        ClearDrawScreen();
        //表示
        SetFontSize(18);
        DrawString(0, 0, "J1 やさしい ゲームタイピング画面です。", color_white);
        DrawFormatString(0, 60, color_white, "残り:%d秒", (60000 - (GetNowCount() - start_time)) / 1000);
        //最初に表示される黒文字
        SetFontSize(30);
        DrawString(150, 200, japan_string, color_white);
        DrawString(150, 250, input_string, color_green);
        //DrawString(150, 250, miss, color_red);
        DrawString(150 + x, 250, alpha_string + input_cursor, color_white);
        //InputAnswerに格納されている答えの文字と比較して一致するまで入力させる
        input_char = tolower(GetInputChar(TRUE));
        if (isalpha(input_char)) {
            if (input_char == alpha_string[input_cursor]) {
                input_count++;
                input_string[input_cursor++] = input_char;
                x += 16;
            }
            else {
                char miss[2]{ alpha_string[input_cursor],0 };
                DrawString(150 + x, 250, miss, color_red);
                miss_count++;
                continue;
            }
            if (alpha_string[input_cursor] == 0) {
                random_lot = GetRand(example_count);
                random_lot++;
                japan_string = japan_strings[random_lot];
                alpha_string = alpha_strings[random_lot];
                answer_count++;
                memset(input_string, 0, input_cursor);
                input_cursor = 0;
                x = 0;
            }
        }
        //計測開始から60秒が過ぎるまでループ 
        if (GetNowCount() - start_time > 60000) break;
    }
    //ゲーム処理結果
    ClearDrawScreen();
    SetFontSize(16);
    DrawString(0, 0, "J1 やさしい ゲームタイピング終了です。", color_white);
    DrawString(0, 20, "初めから    1", color_white);
    DrawString(0, 40, "続ける      2", color_white);
    DrawString(0, 60, "終了        3     のキーを押してください", color_white);
    DrawFormatString(0, 80, color_white, "残り秒数    : %d 秒", (60000 - (GetNowCount() - start_time)) / 1000);
    DrawFormatString(0, 100, color_white, "総合入力打数 : %d 打", input_count);
    DrawFormatString(0, 120, color_white, "平均入力打数 : %.2f 打", (double)input_count / answer_count / 2.5);
    DrawFormatString(0, 140, color_white, "ミス入力打数 : %d 打", miss_count);
    DrawFormatString(0, 160, color_white, "お題回答数   : %d 個", answer_count);

    while (true) {
        if (CheckHitKey(KEY_INPUT_1) == 1 || CheckHitKey(KEY_INPUT_RETURN) == 1) goto GAMESTART;          //ゲームリセットスタート
        if (CheckHitKey(KEY_INPUT_2) == 1 || CheckHitKey(KEY_INPUT_SPACE) == 1) goto GAMECONTINUE;       //途中からゲームスタート
        if (CheckHitKey(KEY_INPUT_3) == 1 || CheckHitKey(KEY_INPUT_DELETE) == 1 || CheckHitKey(KEY_INPUT_BACK) == 1 || Mouse_Get(M_RIGHT) == 1 ) {
            SceneMgr_ChangeScene(eScene_J1);
            Sound_Update1(); 
            break;
        }
    }
}

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

Re: タイピングゲーム 入力動作に関して1

#2

投稿記事 by usao » 1年前

コードをちょっと眺めた感じでしかないけども…

> 文字化け

random_lot の決め方に問題があるのでは?
GetRand() 関数の戻り値の範囲を誤解しているとか.
あと,ループの前とループ内とでは処理が異なっている(ループ内でのみ ++ している)のも怪しい気がする.


> Escキーを押した後何故タイムはカウントダウンし続けるのか?

【ループ直前の時間 ~ 現在の時間】の経過時間を見ているだけでは
ポーズ中の期間が考慮されていないから,でしょう.


> 間違った箇所の入力が一瞬、僅かな時間だけしか赤で表示されない

赤で表示する条件が「間違った入力をされたとき」限定になっているからでしょう.
(ループの次の回では赤で表示する条件を満たさない)

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

Re: タイピングゲーム 入力動作に関して1

#3

投稿記事 by usao » 1年前

・文字化け → 変な表示状態での変数値等を調べて何が起こっているかを把握されたい.
・制限時間 → 制限されるべきは「ゲーム状態下で経過した時間」なのであって,「現在時刻 - 開始時刻」ではない,という点をまずは認識すべき.
・赤の表示 → しばらく表示し続けたいなら「赤いのを表示するか否かフラグ」でも用意して制御してみてはどうか.

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

Re: タイピングゲーム 入力動作に関して1

#4

投稿記事 by usao » 1年前

> goto

今のコードでループがたくさん並んでいることを改めるのが分かりやすいような気もする.
たとえば

コード:

while( ... )  //単一のループ
{
  if( 初回のスペースキー待ち状態なら ){ ... }
  else if( ポーズ中なら ){ ... }
  else{ ゲーム処理 }
}
とかいう形に組み替えれば,ifで判定している何か(:現状態を示す変数とか)を更新してやればそれでやることが切り替わるので,gotoは要らなくなるだろう.
状態の初期化のような処理は関数にでもしてしまえばリセットしたい箇所では単にその関数を呼んでやればいいし.

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

Re: タイピングゲーム 入力動作に関して1

#5

投稿記事 by みけCAT » 1年前

他の部分については既に回答がついているようなので、省略します。

赤い文字の表示を続けるには、たとえば間違えたときに赤い文字の描画の情報 (座標と描画する文字列) をリスト (std::vector、配列など) に格納し、それに基づいて描画をする方法が考えられます。

擬似コード

コード:

赤い文字の描画情報リスト = []
ループ {
    その他の部分を描画する
    緑の文字を描画する
    赤い文字の描画情報リストのそれぞれの要素 e について {
        e に基づいて赤い文字を描画する
    }
    入力判定をする // 間違えたら赤い文字の描画情報リストに情報を追加する
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Ken2929
記事: 6
登録日時: 1年前

Re: タイピングゲーム 入力動作に関して1

#6

投稿記事 by Ken2929 » 1年前

ありがとうございました、参考にします

返信

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