★ゲームを作ろう6(ノベルゲーム1)★


ファイルを使ったプログラムも何個か作りましたので、簡単なノベルゲームの元を作りたいと思います。

グラフィックも使えませんので、非常にシンプルな文章のみとなりますが、これを発展させるのは皆さんのモチベーション次第です。

さて、ノベルゲームではシナリオと簡単な命令を組み合わせた「スクリプト」ファイルというものをよく使います。

今回は簡単なスクリプトを考え、そのスクリプトを元にプログラムを組みましょう。

<スクリプトの取決め>

#で始まらない文字列は「文章」とし、そのまま表示する。

#(シャープ)で始まる文字列は「命令」とし、以下の3種類が存在する。

 #1 別のファイルを開く(ファイル番号は01から99まで)

 例) #1 34

    34番ファイルを開く

 #2 選択肢が表示され、選択した方のファイルを開く

 例) #2 23 18
     選択肢1
     選択肢2

    選択肢1を選ぶと23番、選択肢2を選ぶと18番ファイルを開く

 #3 終了

 例) #3

    スクリプトの実行を停止し、プログラムを終了する

<スクリプトファイル>

今回は、4つのファイルを準備しました。

プロジェクトのフォルダに「Scenerio」フォルダを作成してください。

下にある4つのファイルをダウンロードして、Scenarioフォルダに入れてください。

<ダウンロードファイル>

 Scenario1.txt
 Scenario2.txt
 Scenario3.txt
 Scenario4.txt

ファイル名を右クリックして「対象をファイルに保存」で保存してください。

ダウンロードが分からない場合は自分で4つのファイルを作成していただいても結構です。


まずは、配列などから準備していきましょう。

<sample program 119-01>

#include <stdio.h>

#define SENTENCE_MAX 50

#define FILE_MAX 50

int main(void)
{
    char sentence[SENTENCE_MAX];

    char filename[FILE_MAX];

    int fileNo = 1;
    
    return 0;
}

sentenceは1行分のデータを入れるための配列です。

filenameは前回同様、ファイル名を入れます。

fileNoは現在のファイル番号が入っています。


これを元に最初のファイル「Scenario1.txt」を開くプログラムを追加します。

<sample program 119-02>

#include <stdio.h>

#define SENTENCE_MAX 50

#define FILE_MAX 50

int main(void)
{
    char sentence[SENTENCE_MAX];

    char filename[FILE_MAX];

    int fileNo = 1;

    FILE* fp;

    sprintf(filename, "Scenario\\Scenario%d.txt", fileNo);

    fp = fopen(filename, "r");

    if (fp == NULL) {
        printf("OPEN ERROR\n");
        return 1;
    }


    fclose(fp);

    return 0;
}

「Scenario1.txt」には数行の文章が入っていますので、それを読み込むプログラムを追加します。

<sample program 119-03>

#include <stdio.h>

#define SENTENCE_MAX 50

#define FILE_MAX 50

int main(void)
{
    char sentence[SENTENCE_MAX];

    char filename[FILE_MAX];

    int fileNo = 1;

    FILE* fp;

    sprintf(filename, "Scenario\\Scenario%d.txt", fileNo);

    fp = fopen(filename, "r");

    if (fp == NULL) {
        printf("OPEN ERROR\n");
        return 1;
    }

    for (;;) {

        fgets(sentence, SENTENCE_MAX, fp);

        if (feof(fp)) {
            break;
        }

        printf("%s", sentence);
    }

    fclose(fp);

    return 0;
}

<実行結果>

シナリオの冒頭です。
セリフやナレーションが表示されます。
主人公「あ、斧落としてしもうた・・・」
泉「・・・・・・」
次で別のファイルに映ります。
#1 02
続行するには何かキーを押してください・・・

今のところは、全ての文章が一気に表示されています。

ノベルゲームですから、もう少しプレイヤーが介在したいですね。

前に使ったgetchar関数を使って、エンターキーで文章が進むようにしましょう。

<sample program 119-04>

#include <stdio.h>

#define SENTENCE_MAX 50

#define FILE_MAX 50

int main(void)
{
    char sentence[SENTENCE_MAX];

    char filename[FILE_MAX];

    int fileNo = 1;

    FILE* fp;

    sprintf(filename, "Scenario\\Scenario%d.txt", fileNo);

    fp = fopen(filename, "r");

    if (fp == NULL) {
        printf("OPEN ERROR\n");
        return 1;
    }

    for (;;) {

        fgets(sentence, SENTENCE_MAX, fp);

        if (feof(fp)) {
            break;
        }

        printf("%s", sentence);

        getchar();
    }

    fclose(fp);

    return 0;
}

<実行結果>

シナリオの冒頭です。

セリフやナレーションが表示されます。

主人公「あ、斧落としてしもうた・・・」

泉「・・・・・・」

次で別のファイルに映ります。

#1 02

続行するには何かキーを押してください・・・

「#」で始まる文字列は「命令」用なので、表示してはいけません。

fgetsで読み込んだ後で先頭の文字を調べて、「命令」と「文章」を分けてみます。

<sample program 119-05>

#include <stdio.h>

#define SENTENCE_MAX 50

#define FILE_MAX 50

int main(void)
{
    char sentence[SENTENCE_MAX];

    char filename[FILE_MAX];

    int fileNo = 1;

    FILE* fp;

    sprintf(filename, "Scenario\\Scenario%d.txt", fileNo);

    fp = fopen(filename, "r");

    if (fp == NULL) {
        printf("OPEN ERROR\n");
        return 1;
    }

    for (;;) {

        fgets(sentence, SENTENCE_MAX, fp);

        if (feof(fp)) {
            break;
        }

        if (sentence[0] == '#') {

        }
        else {
            printf("%s", sentence);
        }

        getchar();
    }

    fclose(fp);

    return 0;
}

<実行結果>

シナリオの冒頭です。

セリフやナレーションが表示されます。

主人公「あ、斧落としてしもうた・・・」

泉「・・・・・・」

次で別のファイルに映ります。


続行するには何かキーを押してください・・・

文章の先頭文字を調べるにはsentence[0]を調べれば良いです。

「#」で無い時だけ、文章を表示すれば「命令」は表示されません。

まだプログラムを組んでいないので、エンターキーを2回押さなければ終わらないなど、違和感があります。

今回の「命令」は、

 #01 02

です。

sentenceの中身
  0 1 2 3 4 5 6 
 +−+−+−+−+−+−+−+
 | #| 1|  | 0| 2|\n|\0|
 +−+−+−+−+−+−+−+

これは、2番のファイルを開くという意味です。

fileNoに2を入れて、ファイルを開くプログラムの箇所に戻れば自動的に2番のファイルを開いてくれます。

2番のファイルを表すため、

 02

という文字列があります。

これは、文字の「'0'」と文字の「'2'」です。

これらを数値にしてfileNoに2を入れなければなりません。

ただし、右側の「'2'」だけを数値にすれば良いという訳にはいきません。

ファイル番号は01〜99まである可能性があるので、全てに対応出来るよう考えます。


文字の所で説明したように、文字はコードです。

文字の「'0'」は、10進数で48、16進数で30です。

文字の「'2'」は、10進数で50、16進数で32です。

文字から数値に変換するためには、文字から48を引けば良いのです。

そうすれば、

 文字「'0'」 48 − 48 = 0

 文字「'2'」 50 − 48 = 2

となり、数値になります。

文字の「'0'」はsentence[3]に入っており、「'2'」はsentence[4]に入っています。

計算式としては、

sentence[3] - 48

または、

sentence[3] - '0'

で数値に変換出来ます。

それでは、最終的な式を作りましょう。

「'0'」は10の位、「'2'」は1の位ということを考え、

fileNo = (sentence[3] - '0') * 10 + (sentence[4] - '0');

で行けそうです。


<sample program 119-06>

#include <stdio.h>

#define SENTENCE_MAX 50

#define FILE_MAX 50

int main(void)
{
    char sentence[SENTENCE_MAX];

    char filename[FILE_MAX];

    int fileNo = 1;

    FILE* fp;

    for (;;) {

        sprintf(filename, "Scenario\\Scenario%d.txt", fileNo);

        fp = fopen(filename, "r");

        if (fp == NULL) {
            printf("OPEN ERROR\n");
            return 1;
        }

        for (;;) {

            fgets(sentence, SENTENCE_MAX, fp);

            if (feof(fp)) {
                break;
            }

            if (sentence[0] == '#') {

                /* 別ファイルへ */
                if (sentence[1] == '1') {
                    fileNo = (sentence[3] - '0') * 10 + (sentence[4] - '0');
                    break;
                }
            }
            else {
                printf("%s", sentence);
            }

            getchar();
        }

        fclose(fp);
    }

    return 0;
}

<実行結果>

シナリオの冒頭です。

セリフやナレーションが表示されます。

主人公「あ、斧落としてしもうた・・・」

泉「・・・・・・」

次で別のファイルに映ります。

2つ目のファイルです。

ここでは選択肢が出ます。

泉「あなたが落としたのはどっち?」


1.金の斧

2.鉄の斧

2つ目のファイルです。

・
・
・

永久に続くので、×ボタンで終了させてください。

選択肢のスクリプトを処理するプログラムが無いため、無限にループしてしまいます。

次回は選択肢の処理プログラムを作成しましょう。


次へ

戻る

目次へ