プロジェクト演習Ⅳ・Ⅵ インタラクティブゲーム制作 第2回 ファイル入出力
今日の内容 ファイルの読み書きができるようになろう もうパラメータとかをプログラム中で ゴリゴリ代入するのはまっぴらだ! 「ハードコーディング」と言われて、 現場では忌み嫌われる行為
読み書きのターゲットは とりあえずテキストファイル マップデータ、キャラクタパラメータ、 シナリオデータ、セーブデータなどなど 特にCSVやタブ区切りテキストは扱えると 超便利 マップデータ、キャラクタパラメータ、 シナリオデータ、セーブデータなどなど 「テキストファイルとか見られたら 恥ずかしいし…」とか言うのは後だ!
とりあえず使うもの C++の標準機能だけでやってみよう インクルードは以下の通り 読み込みは「ifstream」 書き込みは「ofstream」 インクルードは以下の通り #include <iostream> #include <fstream> 両方必要なので気をつける 必要に応じてusing namespace std;も
書き込みは絶望的に簡単だ! インスタンス生成時にファイル名指定 is_open()で開けているかチェック <<で書き込むデータを繋げて流し込む 最後はclose() ofstream out_file(“ファイル名”); if(out_file.is_open() == false) エラー処理; out_file << “書き込みたい文字” << endl; // int値やdouble値も<<で繋いで書ける // もちろんstring型やchar型もOK out_file << x << “,” << y << endl; //書き込み終わったらcloseして終了 out_file.close();
読み込みも ただ読み込むだけなら簡単だ! インスタンス生成時にファイル名指定 is_open()で開けて いるかチェック getlineで1行ずつ 取り出し、必要に 応じて処理する 最後はclose() ifstream in_file(“ファイル名”); string lineStr; vector<string> readBuffer; if(in_file.is_open() == false) エラー処理; // 1行ずつwhileループで読み出す while(getline(in_file, lineStr) == true) { // lineStrに1行分入る // とりあえず配列にしまうならこう readBuffer.push_back(lineStr); } in_file.close();
結局何が面倒って 読み込んだ後の文字列処理なんです C++のstringクラスはJavaに比べると 機能が正直貧弱です 最低限のものは揃っているので、うまく素材を組み合わせて関数を作ろう サンプルあります データを取り出しやすいファイル構造を作ろう
区切り取り出し関数実装例 vector<string> fk_StrSplit(string argStr, string argToken) { vector<string> retStrArray; string::size_type curPos = 0, nextPos = 0; while(nextPos != string::npos) { nextPos = argStr.find(argToken, curPos); retStrArray.push_back(argStr.substr(curPos, nextPos-curPos)); curPos = nextPos+argToken.size(); } return retStrArray;
区切って取り出す fk_StrSplit()関数 カンマ区切り、タブ区切りはExcelでの 編集が容易なので、出来ておいて損は ない JavaのStringクラスのsplit()のようなもの 正規表現は使えないけどカンマ区切り、 タブ区切り程度なら対応可能 カンマ区切り、タブ区切りはExcelでの 編集が容易なので、出来ておいて損は ない マップやシナリオのエディタをExcelで 代用しているソフトハウスもあります
整数値・実数値変換 Cの標準関数をなんだかんだで使う ただしstring型の変数は直接引数に 渡せないので、c_str()関数を使う atoi()がInteger.parseInt()にあたる atof()がDouble.parseDouble()にあたる ただしstring型の変数は直接引数に 渡せないので、c_str()関数を使う atoi(anyStr.c_str())のようにする 実数値は誤差に厳しいものだと変換時に値がズレることがあるので注意
ファイル形式の作り方のコツ FK Performerのモーションデータなどを見てみるとよい 「ファイルヘッダ」は必ず付けると ファイルの先頭でファイルの種類が 識別できるようにする [BEGIN]~[END]で囲っておくと、 データを読み込むべき範囲が 分かりやすくなるので処理しやすい
ファイル入出力のクラス化例 fkut_ConfigDataクラス 「A=B」という記述形式を読み書きすることに特化したクラス 元々はパッドのコンフィグデータ用に作ったが、パラメータ調整などにも使えそう ここまでの資料をもとにソースを読み解いてみると良いかも
読み込み内容に基づく データ生成 例えば読み込んだデータに基づいて 立方体を配置するプログラムを考える 個数が固定ならいいが、そうではない ケースの方が圧倒的に多い クラスオブジェクトの動的な生成が必須
今日の課題 CSVテキストに基づいて、3D空間中に 立方体を配置するプログラムを作れ ファイル形式も自分で決める 位置、姿勢、大きさはデータによって決定 立方体の個数は任意(ファイル内容次第) マテリアルも指定できるならそれもよし 1行の文字列から””で囲まれた文字列を取り出す関数を作れ