第16回:ローディングのテクニック
これまでは、ひとつひとつのテクスチャのために使う画像ファイルのデータがそれほど大きくなかったため、即プログラムが実行状態に入っていましたが、一定規模を持つゲームの場合、大量のデータファイルを読み込むことになり、一時的にフリーズ状態になってしまうでしょう。そこで今回は、最近のゲームで見かけないことのない「ローディング画面」を実装することにしましょう。
ロード画面を表示している後ろで、ハードディスクからデータを読み込む
ステージや状況によって、データを読み込むためのルーチンが異なってくるため、まずは、ローディングモードを実行するための基底クラスを作成します。このクラスでは、別スレッドで作成されたCGameObjectクラス群を格納するための一時的なリスト(temp)と、スレッドの完了を知るための変数(complete)をstatic属性にしていますが、これは、別スレッドで実行される関数はstatic属性でなければならず、その関数内で呼び出される変数もstatic属性にする必要があるためです。
class CLoadData : public CGameObject
{
private:
int brightness;
CDxFont *font;
public:
CLoadData();
virtual ~CLoadData();
protected:
static bool complete;
static list<ListData> temp;
virtual void Exec();
};
bool CLoadData::complete;
list<ListData> CLoadData::temp;
CLoadData::CLoadData()
{
// staticデータをリセット
complete = false;
temp.clear();
// 変数の初期化
brightness = 255;
font = new CDxFont(20);
}
CLoadData::~CLoadData()
{
if(font) delete font;
// 中断されたのであれば、追加予定だったオブジェクトを破棄する
if(complete == false){
list<ListData>::iterator i = temp.begin();
while(i != temp.end()){
if((*i).autodelete == true) delete (*i).gameobj;
i = temp.erase(i);
}
}
}
void CLoadData::Exec()
{
if(complete == false){
// バックグラウンド処理がまだ行われている
brightness -= 2;
if(brightness < 0) brightness = 255;
RECT rc = {0,0,630,470};
font->Draw(L"Now Loading...", -1, &rc,
DT_BOTTOM | DT_RIGHT | DT_SINGLELINE,
0x00FFFFFF | ((BYTE)brightness << 24));
}else{
// バックグラウンドで用意されたクラスをタスクに追加する
list<ListData>::iterator i;
for(i = temp.begin(); i != temp.end(); i++){
AppendObject(*i);
}
// 自分自身は用済みなので破棄
RemoveObject(this);
}
}
class CLoadStage : public CLoadData
{
protected:
virtual void Init();
static void LoadThread(void *data);
};
void CLoadStage::Init()
{
// 別スレッドでロードを開始
_beginthread(this->LoadThread, 0, NULL);
RemoveObject(this);
}
void CLoadStage::LoadThread(void *data)
{
// ここで時間のかかる処理を実行
//-----------------------------------------
// 以下はプログラム例
//-----------------------------------------
ListData ld;
ResetItemBox();
// 背景
ld.gameobj = new CBackGround();
ld.autodelete = true;
strcpy_s(ld.name, 32, "bg");
ld.priority = BACKGROUND_PRIORITY;
temp.push_back(ld);
// プレイヤー
ld.gameobj = new CPlayer();
ld.autodelete = true;
strcpy_s(ld.name, 32, "player");
ld.priority = PLAYER_PRIORITY;
temp.push_back(ld);
AppendItemBox("player", ld.gameobj);
//-----------------------------------------
// 以上はプログラム例
//-----------------------------------------
complete = true;
}
CGameObject game;
CoInitialize(NULL);
game.Initialize(mainWnd, hInstance);
CSound::CreateDirectSound(mainWnd);
game.AppendObject(new CTaskHead(), 0, true);
game.AppendObject(new CTaskTail(), INT_MAX, true);
game.AppendObject(new CLoadStage(), 1, true);
ShowWindow(mainWnd, nCmdShow);