画像(logo)

HOME/[C言語DXライブラリ]STGの作り方 目次/おまけ1 敵データのファイルからの読み込み

広告

[C言語 DXライブラリ STGの作り方]
おまけ1 敵データのファイルからの読み込み

広告

↓2016年02月29日発売↓

12歳からはじめる ゼロからのC言語 ゲームプログラミング教室

目次へ戻る

敵データのファイルからの読み込み

今回はおまけその1としてエクセルなどで作った外部ファイルからの敵データの読み込みをやっていきたいと思います。

これができればエクセルの機能を使ってより迅速にデータの入力・編集などができたり、なによりソースがすっきりしますね!

実戦的なプログラム作成にはなくてはならない技術です。

それではいってみましょう!

敵データを作る

まずは肝心の敵データをエクセルを使って作ってみましょう!

画像(cdxs_24_1)

まあ難しく考えずこんな感じで作っていけば・・・、

画像(cdxs_24_2)

大丈夫です。

そして作り終えたら保存するワケですがこの時注意する事が通常のエクセルファイル形式ではなく「csv」形式なるものを選んで保存します。

画像(cdxs_24_3)

ファイルの種類から「csv」形式を選択して保存しましょう。

保存する時に場合によってはエクセルの機能が失われます的な事を聞かれますがムシして大丈夫です。

これで敵データはオッケーです。

1つのファイルにボス含み全ての敵データを入れる事ももちろんできますが、今回はわかりやすいように通常の敵データのみでステージごとに分けて用意します。

配列の準備

次に読み取ったデータを受け取る配列を準備します。

まあ準備と言っても今まであった配列のデータ部分をなくすだけなので

int ary_enemy_data[STAGE_MAX][STAGE_ENEMY_MAX * ENEMY_DATA_MAX] = {
	{
	0,100,100,260,10,0,1,10,0,
	1,120,100,260,10,0,1,10,0,
	2,140,100,260,10,0,1,10,0,
	/*以下省略*/
	},
	{
	0,100,-100,260,17,2,20,10,0,
	1,100,100,260,17,2,20,10,0,
	2,500,100,260,10,0,1,10,0,
	/*以下省略*/
	},
	{
	0,100,100,260,10,0,1,10,0,
	1,120,100,260,10,0,1,10,0,
	2,140,100,260,10,0,1,10,0,
	/*以下省略*/
	}
};

int ary_enemy_data[STAGE_MAX][STAGE_ENEMY_MAX * ENEMY_DATA_MAX];

こんな感じで大丈夫です。

もちろん配列に保存しなおさずに読み取った値をそのまま使用することもできますが、それだとプログラムの直しが増えるし今回はこのカタチでいきたいと思います。

ファイル読み込み

それではプログラムの方を見てみましょう。

外部ファイルからデータを読み込む「my_load_enemy_data()」になります。

void my_load_enemy_data(){
	int fp;
	char c;

	char str[64];
	int str_count = 0;

	int ary_enemy_data_count = 0;

	switch(stage_num){
	case 0:
		fp = FileRead_open("../enemy_data1.csv");
		break;
	case 1:
		fp = FileRead_open("../enemy_data2.csv");
		break;
	case 2:
		fp = FileRead_open("../enemy_data3.csv");
		break;
	default:
		break;
	}

	if(fp == NULL){
                printfDx("ファイル読み込みエラー\n");
                return;
        }

	while (FileRead_getc(fp) != '\n');

	while(1){
		c = FileRead_getc(fp);
		str[str_count] = c;
		
		if(str[str_count] == ',' || str[str_count] == '\n' || str[str_count] == EOF){
			str[str_count] = '\0';
			ary_enemy_data[stage_num][ary_enemy_data_count] = atoi(str);
			str_count = -1;
			ary_enemy_data_count++;
		}

		if (c == EOF || ary_enemy_data_count == STAGE_ENEMY_MAX * ENEMY_DATA_MAX)break;
		str_count++;
	}
	
	FileRead_close(fp);

}

基本的なファイルの読み書きなどについてわからない場合はこちらにまとめてありますので参考にしてみてください。

普通にC言語のファイル読み書きの作法で大丈夫だと思いますが(細かく確認はしてないです)、DXライブラリ用の関数が用意されているので素直にそちらを使います。

ファイルオープン・クローズ

それではファイル用の変数を用意してそこにオープンしたファイルを関連づけていきましょう。

int fp;

switch(stage_num){
case 0:
	fp = FileRead_open("../enemy_data1.csv");
	break;
case 1:
	fp = FileRead_open("../enemy_data2.csv");
	break;
case 2:
	fp = FileRead_open("../enemy_data3.csv");
	break;
default:
	break;
}

if(fp == NULL){
	printfDx("ファイル読み込みエラー\n");
	return;
}

FileRead_close(fp);

いきなりですが、ファイル用の変数は「FILE」型ではなく「int」型で大丈夫です。

ポインタ変数にする必要もありません。

なんでもかんでも「int」ひとつで済んでしまうのもDXライブラリの大変ありがたいところですね!

そこに用意した敵のデータファイルをオープン、関連づけていきます。

fp = FileRead_open("../enemy_data1.csv");

ファイルのオープンには「FileRead_open("ファイルパス")」を使います。

そしていつも通りのエラーチェックをして作業を終えたら最後忘れずにファイルをクローズすれば大丈夫です。

ファイルの内容を読む

while (FileRead_getc(fp) != '\n');

while(1){
	c = FileRead_getc(fp);
	str[str_count] = c;
		
	if(str[str_count] == ',' || str[str_count] == '\n' || str[str_count] == EOF){
		str[str_count] = '\0';
		ary_enemy_data[stage_num][ary_enemy_data_count] = atoi(str);
		str_count = -1;
		ary_enemy_data_count++;
	}

	if (c == EOF || ary_enemy_data_count == STAGE_ENEMY_MAX * ENEMY_DATA_MAX)break;
	str_count++;
}

それではファイルの内容を読み込んでいきます。

まず「fgetc()」に程近い役割をするのが「FileRead_getc()」になります。

一文字だけ読んでポインタを一つ進めます。

それを踏まえた上で

while (FileRead_getc(fp) != '\n');

先頭の一文です。

「\n」は改行の意味になるので改行ではない間「while()」ループで「FileRead_getc()」を繰り返すといった感じの意味になりますね。

これは難しく考えず定型句として覚えた方が良いです。

要は一行読み飛ばすという意味です。

これを使ってタイトル行なんかを読み飛ばします。

続いてデータ本体を読み込んでいきます。

必要な変数を用意します。

/*読み込んだ一文字を保存*/
char c;

/*例えば「5」,「6」のように一文字ずつ読んだ*/
/*単体の文字をつなげて「56」にする為の文字列*/
char str[64];

/*先ほどの文字列の為のカウント*/
int str_count = 0;

/*読み込んだ敵データを受け取る配列の為のカウント*/
int ary_enemy_data_count = 0;

こんな感じになります。

それでは残りの部分を説明します。

while(1){
	c = FileRead_getc(fp);
	str[str_count] = c;
		
	if(str[str_count] == ',' || str[str_count] == '\n' || str[str_count] == EOF){
		str[str_count] = '\0';
		ary_enemy_data[stage_num][ary_enemy_data_count] = atoi(str);
		str_count = -1;
		ary_enemy_data_count++;
	}

	if (c == EOF || ary_enemy_data_count == STAGE_ENEMY_MAX * ENEMY_DATA_MAX)break;
	str_count++;
}

まず一文字読んで変数「c」に保存、さらにその一文字を文字列「str」に保存しなおします。

c = FileRead_getc(fp);
str[str_count] = c;		

次に「if」文が出てきますがここはいったん読み飛ばして次の部分を見てみます。

if (c == EOF || ary_enemy_data_count == STAGE_ENEMY_MAX * ENEMY_DATA_MAX)break;

再び「if」文です。

この部分は終了条件ですね。

変数「c」がファイルの終端「EOF」か、配列内のカウントを表す「ary_enemy_data_count」が「STAGE_ENEMY_MAX * ENEMY_DATA_MAX」、つまりは配列の個数の限界に達したら「break」します。

「EOF」だけでよさそうですが、なんらかのミスで元のファイルのデータの個数が受け取る側の配列の個数を超えてしまっている可能性もあるのでバッファオーバーフローしないように必ず配列の個数に対する終了条件も加えておきます。

次の部分です。

str_count++;

何もなければ2桁以上のデータを読む為に文字列の位置を表す「str_count」をインクリメントして次に備えます。

ここまでの話をまとめると、終了条件に達しない間、例えば「123」というデータがあったとしたら

1・最初の数字「1」を変数「c」に保存

2・配列「str」に保存しなおす

この時点での「str」の内容・・・[1][][]

3・「str_count」をインクリメント

4・次の数字「2」を変数「c」に保存

5・配列「str」に保存しなおす

この時点での「str」の内容・・・[1][2][]

6・「str_count」をインクリメント

7・次の数字「3」を変数「c」に保存

8・配列「str」に保存しなおす

この時点での「str」の内容・・・[1][2][3]

9・「str_count」をインクリメント

みたいな感じで進んでいきます。

なんとなく伝わりましたでしょうか?

では残りの「if」文を見ていきます。

if(str[str_count] == ',' || str[str_count] == '\n' || str[str_count] == EOF)

「str[str_count]が「カンマ」か「改行」か「EOF」の場合は実行」という意味ですね。

つまりこれはデータの途切れ目がきたら、そのデータを加工して配列「ary_enemy_data」に保存しなおすという部分になります。

では中身を見てみましょう。

str[str_count] = '\0';

まず読み取った最後の部分には「,」か「\n」か「EOF」がいるはずなのでそこを文字列の終端を表す「\0」に置き換えます。

たとえばさっきの例で言いますと

「str」の内容・・・[1][2][3][\0]

こんな状態になるという事です。

ここまでくればあとはこの文字列「str」を数字に変換するだけです。

「文字列→数字変換」

おそらくC言語の入門時にこちらをやった方もいるかもしれません。

地味にめんどくさいですよね。

なのでここは便利な関数を使って一発で変換してしまいます。

ary_enemy_data[stage_num][ary_enemy_data_count] = atoi(str);

「atoi()」という関数になります。

これを使えば引数の文字列を一気に数字に変換してくれます。

「atoi()」の場合は「int」型数値に変換されます。

「stdlib」をインクルードする必要があります。

そして変換された数値を「ary_enemy_data」に保存しなおして

str_count = -1;
ary_enemy_data_count++;

それぞれのカウントを修正すれば完了です。

「str_count」はこの「if」文の後すぐにインクリメントされるので「-1」で初期化しておく事に注意しましょう。

画像(cdxs_24_4)

ファイル読み込み完了!

エクセルがない!

「エクセルなんてハイカラなものは持ってねー!」

という方へ

心配する事はありません。

先ほどのデータファイル「ary_enemy_data1.csv」をメモ帳で開いてみます。

画像(cdxs_24_5)

お分かりいただけましたでしょうか?

この「csv」ファイルの中身というのはただデータをカンマで区切ってあるだけなのです。

なのでエクセルがなくてもメモ帳でこのような形式でデータファイルを作れば今のやり方で問題なく読み取ってくれます。

試しにメモ帳で今の形式のファイルを作ってエクセルで開いてみましょう。

画像(cdxs_24_6)

こんな感じで作って保存。

拡張子を「csv」に。

これをエクセルで開くと・・・、

画像(cdxs_24_7)

カンマの部分がセルの区切りになりましたね!

このお互いの関係はけっこう大事なので覚えておきましょう。

ソースになります。

おまけソース1

ちなみに「csv」の正式名称は

「comma separated values」

と言います。

「カンマで分けた値」とそのまんまですね!

□ページの先頭へ□

□目次へ戻る□

□HOME□

広告

↓2017年06月16日発売↓

やさしいC 第5版 (「やさしい」シリーズ)

新品価格
¥2,700から
(2017/5/1 13:05時点)

↓2014年08月09日発売↓

新・明解C言語 入門編 (明解シリーズ)

新品価格
¥2,484から
(2017/5/1 13:08時点)

↓2016年02月20日発売↓

新・解きながら学ぶC言語

新品価格
¥2,160から
(2017/5/1 13:10時点)

↓2017年02月11日発売↓

C言語プログラミング基本例題88 88

新品価格
¥3,024から
(2017/5/1 13:12時点)

↓2016年12月15日発売↓

Cの絵本 第2版 C言語が好きになる新しい9つの扉

新品価格
¥1,490から
(2017/5/1 13:13時点)

↓2017年02月08日発売↓

新・明解C言語で学ぶアルゴリズムとデータ構造 (明解シリーズ)

新品価格
¥2,700から
(2017/5/1 13:15時点)