ファイルを使ったプログラムも何個か作りましたので、簡単なノベルゲームの元を作りたいと思います。
グラフィックも使えませんので、非常にシンプルな文章のみとなりますが、これを発展させるのは皆さんのモチベーション次第です。
さて、ノベルゲームではシナリオと簡単な命令を組み合わせた「スクリプト」ファイルというものをよく使います。
今回は簡単なスクリプトを考え、そのスクリプトを元にプログラムを組みましょう。
<スクリプトの取決め>
#で始まらない文字列は「文章」とし、そのまま表示する。 #(シャープ)で始まる文字列は「命令」とし、以下の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つ目のファイルです。
・
・
・
永久に続くので、×ボタンで終了させてください。
選択肢のスクリプトを処理するプログラムが無いため、無限にループしてしまいます。
次回は選択肢の処理プログラムを作成しましょう。