.csvを読み込む

.csvとはコンマ","区切りのドキュメントのことであり、Excelなどで表として編集できるので敵データやアイテムのデータの管理にとても優れたファイル形式である。
データの読み込み方法は幾つかあるが、基本的にはカンマをプログラム側で抽出し、前後の文章を切り分けていくという処理になる。
以下に筆者のプログラムで実際に動いているコードを記す。が、boostを使っているのでboostが無い環境では代替関数やコードの書き直しを行うべし。また、FileRead_getcなどはDXライブラリの関数なので適宜標準ライブラリの関数などに置き換えるべし(動作はほぼ同じ)。

void ReadEnemyData() {
	int fp = IO::OpenFileStream("Zatoumushi/creatures/Enemy.csv");
	IO::PassTwoSentence(fp);
	memset(EData,0,sizeof(EData));

	/* データ取得 ここから */
	int n=0;
	while (true) {
		vector<string> v;
		IO::GetOneSentence(fp,v);

		if (v.size()<13) break;
		EData[n].id		=	atoi(v[0].c_str());
		strncpy_s(EData[n].Name,32,v[1].c_str(),_TRUNCATE);
		EData[n].Pattern	=	atoi(v[2].c_str());
		EData[n].HP		=	atoi(v[3].c_str());
		EData[n].Img		=	atoi(v[4].c_str());
		EData[n].rectX		=	atoi(v[5].c_str());
		EData[n].rectY		=	atoi(v[6].c_str());
		EData[n].gX		=	atoi(v[7].c_str());
		EData[n].gY		=	atoi(v[8].c_str());
		EData[n].AntiShock	=	atoi(v[9].c_str());
		EData[n].Mass		=	atoi(v[10].c_str());
		EData[n].Flag		=	atoi(v[11].c_str());
		EData[n].Score 		=	atoi(v[12].c_str());
		n++;
		if (IO::CheckEOF(fp)||n>=ENEMY_DATA_MAX) break;
	}
	IO::EndFileStream(fp);
}

EData[]が格納先の配列である。静的クラスIOは以下の通りである。

#include "DxLib.h"
#include "CIOBox.h"

#include <vector>
#include <string>
using namespace std;

class IO {
public:
	static int OpenFileStream(const char *addr,...);
	static int GetOneSentence(int fp,vector<string> &v);
	static void PassOneSentence(int fp);
	static void PassTwoSentence(int fp);
	static int CheckEOF(int fp) { return FileRead_eof(fp); }
	static int EndFileStream(int fp) { return FileRead_close(fp); }
};

#pragma warning(disable: 4996)
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

int IO::OpenFileStream(const char *addr,...) {
	int len, tmpfp;
	char buf[MAX_PATH];
	va_list ap;
	va_start(ap,addr);
	len = vsprintf_s(buf,MAX_PATH,addr,ap);
	va_end(ap);
	if(len!=EOF) {
		if ((tmpfp = FileRead_open(buf))!=NULL) {
			return tmpfp;
		}
	}
	// ここにはエラーメッセージを入力
	return -1;
}

int IO::GetOneSentence(int fp,vector<string> &v) {
	char buf[1024];
	FileRead_gets(buf,1024,fp);
	string sbuf(buf);
	boost::algorithm::split( v, sbuf, boost::algorithm::is_any_of(",") );
	return 0;
}
void IO::PassOneSentence(int fp) {
	while(FileRead_getc(fp)!='\n'); 
}
void IO::PassTwoSentence(int fp) {
	while(FileRead_getc(fp)!='\n'); 
	while(FileRead_getc(fp)!='\n'); 
}

簡単に説明すると、vectorに切り分けて項目を入れて戻している。
これらはあくまで我流なので恐らく効率的ではないし最適化されているわけでもない。が、Cでstrtokを使って書くよりは幾分か簡略になっているので、参考にしてみると良いと思う。