ホーム < ゲームつくろー! < ツール編

その2 非同期ファイル読み込み


 ゲームのロードセーブ、シーン切り替え時などにファイルからデータを読み込みます。この時、大量の大きなファイルを読み込むと読み込みが完了するまで制御が戻ってきません。という事は、描画もそこで止まってしまいます。プレイヤーはフリーズした画面をずっと見続ける状態となります。それはちょっとまずいわけです。

 そこで登場するのが「非同期読み込み」です。これは本筋と独立したファイル読み込みスレッドによって、ゲームが進行しつつ大きなファイルを読み込める仕組みです。ゲームでよく「Now Loading !」という類の絵が出たり点滅したりしていますが、これは裏で非同期読み込みが使われています。

 ここで紹介するAsyncFileReadクラスは非同期読み込みをサポートするクラスです。

ツール名 非同期ファイル読み込みクラス
名前空間 Dix
クラス名 AsyncFileRead
公開メソッド AsyncFileRead() コンストラクタ
ASYNCFILEREADSTATE readBackground( fileName, offset, size )
TCHAR* fileName   // ファイル名
size_t offset      // 読み込みオフセット
size_t size       // 読み込みサイズ
非同期読み込みを開始する
読み込み成功ならtrue、失敗ならfalseを返す
ASYNCFILEREADSTATE getState() 現在の状態を取得。
戻り値はASYNCFILEREADSTATE列挙型で以下の通り:
ASYNCFILEREAD_WAIT        // 読み込み開始待ち状態
ASYNCFILEREAD_READING   // 読み込み中
ASYNCFILEREAD_FINISHED    // 読み込み終了
ASYNCFILEREAD_INVALID      // 読み込みエラー
char* getBuffer() 読み込んだバッファへのポインタを取得
読み込み最中及び有効なポインタが無い場合はNULLを返す
void deleteBuffer() バッファをクリアする
呼出し後オブジェクトは再利用可能になる
バージョン v1.00 (2007. 9. 14)
ファイル AsyncFileRead.h, AsyncFileRead.cpp



@ AsyncFileReadクラスの使い方

 ファイルを読み込む時にはAsyncFileRead::readBackgroundメソッドを呼び出します:

ファイル読み込み
AsyncFileRead *pAFR = new AsyncFileRead;
if( pAFR->readBackground( _T("test.dat", offset, size ) != ASYNCFILEREAD_READING ) {
   return false;   // 読み込み失敗
}

第1引数には読み込むファイル名、第2引数には読み込み位置までのオフセット値、第3引数には読み込みサイズを指定します。ファイルが読み込み可能状態ならばこの時点で読み込みが開始されます。ファイルサイズが不明の場合は0を指定できるようにしました。その場合、内部で指定ファイルのサイズを求めてバッファを確保します。

 非同期読み込みオブジェクトの寿命は比較的短いのですが、動作中はほぼ確実に関数の外へプログラムが出てしまいますので、new演算子などを使いスコープが広い変数として宣言します。現在の読み込み状況を取得するにはAsyncFileRead::getStateメソッドを呼び出します:

読み込み状況チェック
bool LoadFile {
   // 完了チェック
   if ( pAFR->getState() != ASYNCFILEREAD_FINISHED )
      return false;

   // 読み込み終了
   char *p = pAFR->getBuffer();    // ファイルバッファ取得

   /* ポインタ先から情報を読む */

   delete pAFR;   // 消去してOK
   return true;
}

 getStateメソッドは読み込み中の場合ASYNCFILEREAD_READINGを返し、読み込みが終了したときはACYNCFILEREAD_FNISHEDを返します。このようにgetStateメソッドを何度も呼んで状態を聞く作業を繰り返すのが非同期ファイル読み込みの特徴です。

 読み込み完了を確認したらgetBufferメソッドで情報を格納したバッファを取得できます。後は取得したポインタ先から必要な情報を抜き取るだけです。バッファの寿命はAsyncFileReadオブジェクトの寿命と一緒ですが、情報を読み取った後にdeleteBufferメソッドを呼び出すことで早々に解放させる事もできます:

バッファクリア
pAFR->deleteBuffer();

解放後オブジェクトは再利用できます。



A バージョン情報

2007/9/15
v1.00 最低限の非同期読み込みを実装