インタラクティブ・ゲーム制作 <プログラミングコース> 第8回 ファイル入出力と アルゴリズム 今日の内容 • やるやる言いつつできなかった – ファイル入出力 • 本質ではないけど見た目もこだわる – 石のアニメーション • アルゴリズムをガチで考える – 置ける場所とひっくり返し判定 こ、今度こそ! ファイル入出力 ファイル入出力の重要性 • セーブ/ロードをしたいなら必須処理 • ソース中にパラメータを直書きするのは 「ハードコーディング」と言われて、 現場では忌み嫌われる行為 – ちょっとマップを手直しするのにもビルドが 必要=Visual Studioが必要=マップも自分で 作らなくてはいけなくなる=あばばばばばb 読み書きのターゲットは • とりあえずテキストファイル – 特に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クラスは基本的な機能しか ないので、ちょっと高度なことをやろう とすると、自前で頑張るか、boostなどに 頼ることになります。 • 最低限の処理を使えるようになり、 データを取り出しやすいファイル構造を 作ろう 区切り取り出し関数実装例 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()関数 – 第1引数の文字列を、第2引数の文字で 区切り、バラした結果を返す – vector<string>型で受け取る • FKUT/Misc.hで定義してあるので、 利用する場合はこれをインクルードする 整数値・実数値変換 • Cの標準関数をなんだかんだで使う – atoi()が整数変換にあたる – atof()が実数変換にあたる • ただしstring型の変数は直接引数に 渡せないので、c_str()関数を使う – atoi(anyStr.c_str())のようにする • 実数値は誤差に厳しいものだと変換時に 値がズレることがあるので注意 データ形式を仮決めしよう • 次のようなテキストファイルを作ること にする – 最初の行に[MY BOARD DATA]と表記する – 次の行に石の個数を記述する – 3行目以降から、 1行で石1個分を表すことにする • X座標, Z座標, 色指定(とりあえず英語で) データの例 [BOARD DATA] 4 -5.0, -5.0, Black 5.0, -5.0, White 5.0, 5.0, Black -5.0, 5.0, White 細かいところだけど重要な 石のアニメーションで 使っているテクニック ポイントになるもの • update()関数の利用 – 毎フレーム呼び出して動きを更新する – アニメーションの進行状態が分かるように メンバ変数を持たせておく • 三角関数おいしい! – 一番好きな関数です! – 時間経過に応じて0~1の値を得るのに便利 動きを付ける時によくやるやり方 • 線形補間 P = (1 - t)*(startPos) + t*(endPos) • 半分半分また半分 P = 0.5*(nowPos) + 0.5*(endPos) • 色々な数式や関数の特徴を覚えておくと、 色んな場面で役立ちます! 本日のメインディッシュ 置ける場所とひっくり返し判定 置ける場所の定義(1) • 置くことで ひっくり返せること – そのためには、 置く場所の 周囲8マスに 相手の石が 置かれているのが 前提条件になる – 初手で黒が置けるのは、 前提条件のみだと 右の赤いセル ○ ● ●○ あるセルにおける 周囲の情報を得るには • cellInfo[x][y]の周囲8セル – [x-1][y-1], [x][y-1], [x+1][y-1] – [x-1][y], [x+1][y] – [x-1][y+1], [x][y+1], [x+1][y+1] • 範囲外(0未満、8以上)の場合は対象外 • これをこのままコーディングすると ださいので、座標のペアを配列に しまってループで処理できるとクール 置ける場所の定義(2) • 相手の石があった 方向の先に、 自分の石があること – 端に到達した場合は その時点でNG – 隣接する相手の石が 複数存在した場合は、 それぞれの方向で判定 – 初手の場合青いセルが 最終的にOKになる ○ ● ●○ 実装方針 • 位置と方向を与えて、その方向を調べる 関数を作る • 先ほどリストアップした隣接した相手の 石リストを関数に流し込んでいく • あとは実演! TO BE CONTINUED…
© Copyright 2024 ExpyDoc