(このシリーズは知り合いの学生に教える資料用に作成しているメモです。。。)
ゲームプログラムはWindowsのイベントドリブン形式のプログラムと大きく異なる。
そして一般的に「タスク処理」といわれる処理形態をとることが多い。
(最近ではタスクは古いというチームもあるらしい?)
「タスク処理」とは擬似的にスレッドのような並列処理を行う処理概念のことである。
ナムコのギャラクシアンが最初に発明して瞬く間に広まったとされている。
ゲームプログラム特有の処理フローは実際にやってみた方が早い。
もしゲームプログラムを一度も組んだことが無い人は
http://www.twin-tail.jp/contents/el/index.htm
で基本的なゲームフローを実際に組むべし。。。(→課題①)
タスク処理には細かく分けるといろいろな形態が存在するが、今回は
自分のシステムで使用している処理形態だけを説明することにする。
Taskの正体は単純な「ツリー構造」のクラスである。
class Task
{
//--------------------------------------------------
//
//--------------------------------------------------
public:
Task* m_pParent;
Task* m_pChild;
Task* m_pPrev;
Task* m_pNext;
/// Task名
char* m_pTaskName;
//--------------------------------------------------
//
//--------------------------------------------------
protected:
Task();
virtual ~Task();
public:
static Task* Create_Task( Task* pParent );
const Task* Parent() const { return m_pParent; }
const Task* Child() const { return m_pChild; }
const Task* Prev() const { return m_pPrev; }
const Task* Next() const { return m_pNext; }
Task* Link( Task *pParent, int nPos = TAIL );
Task* UnLink();
void SetName( char* task_name );
//----------------------------------------------------------
// 以下がTaskとしての機能
//----------------------------------------------------------
// 定期メッセージ受け取り
virtual HRESULT Receive( Message* pMess );
// 基本処理
virtual HRESULT TaskInit(){return S_OK;}
virtual HRESULT TaskMain(){return S_OK;}
virtual HRESULT TaskDestroy(){return S_OK;}
};
ツリー構造は以下のような構成になる。
+->RootTask
+->DebugMenu
+->GameTask --GameMain--
+->GameRoot =================
| +-> CameraManager
| +-> PlayerTask
+->RenderRoot ================
+->Camera --Plugin_Mouse--
+->Sprite --GameWindow--
[RootTask]
一番の親タスクでゲームに関するタスクはすべてこのRootTaskの子供になる。
また、RootTaskが子供のTaskのReceiveにメッセージを
飛ばすことによって各タスク処理を行う。
main()
{
while(1)
{
RootTask::Run();
}
}
RootTask::Run()
{
while()
{
(各子供)->Recieve( TASK_MAIN );
}
}
各TaskのRecieveではメッセージに応じた関数を呼ぶ
Task::Recieve( Message msg )
{
switch( msg )
{
case TASK_INIT: TaskInit(); break;
case TASK_MAIN: TaskMain(); break;
case TASK_DESTORY: TaskDestroy(); break;
}
}
プログラマはこのTaskを継承し、
TaskMain内に各処理を記述することになる。
イメージとしては以下のようになる
main()
{
// RootTaskを親として[PlayerTask]を生成する
PlayerTask* pPlayerTask = PlayerTask::Create_PlayerTask( RenderRoot::GetInst() );
while(1)
{
// Runによって子供のPlayerTaskが呼ばれる
RootTask::Run();
}
}
//----------------------------------------------
// 各タスクはTaskを継承して独自のタスクを生成する
//----------------------------------------------
class PlayerTask : public Task
{
public:
static PlayerTask* Create_PlayerTask( Task* pParent );
// 基本処理
virtual HRESULT TaskInit();
virtual HRESULT TaskMain();
virtual HRESULT TaskDestroy();
};
//----------------------------------------------
// タスクの生成
//----------------------------------------------
PlayerTask* PlayerTask::Create_PlayerTask( Task* pParent )
{
Task* pTask = NEW Task;
if( !pTask ){ASSERT(0);return NULL;}
pTask->SetName("Task --noname--");
// 初期化処理を走らせる
pTask = (Task*)pTask->Recieve( TASK_INIT );
if( !pTask ){ASSERT(0);return NULL;}
return pTask;
}
//----------------------------------------------
// Player独自の処理
//----------------------------------------------
HRESULT PlayerTask::TaskMain()
{
// PADの検出
// Playerの移動
// Playerの当たり判定
// etc...
}
というかこのブログプログラムを掲載するのにはめちゃくちゃ使いにくい!!
タグが少なすぎ!ブログ変えようかな・・・