読者です 読者をやめる 読者になる 読者になる

Flat Leon Works

アプリやゲームを作ってます。

【C++ ゲームプログラミング】STLで実装する最小のタスクシステム

C++ 技術

タスクシステムとは

タスクシステムとはゲームプログラミングで利用されるプログラムの設計のことです。ゲームプログラムは更新処理と描画処理を繰り返すことで動作します。この更新処理と描画処理を小さな単位(タスク)にすることで実装しやすくしようというのがタスクシステムの根本のアイデアだと思います。

タスクシステムに必要な最小の機能は以下のとおりです。

  • タスクリストの管理(保持/追加/削除)
  • 各タスクの更新処理と描画処理の呼び出し
  • タスクの生成と破棄の仕組み
  • タスクに具体的な実装を与える仕組み

C++の場合、それぞれ以下のように実装するのが一番シンプルな方法でしょう。

  • タスクリストの管理(保持/追加/削除)
    • std::list
  • 各タスクの更新処理と描画処理の呼び出し
    • std::listを走査して呼び出す
  • タスクの生成と破棄の仕組み
    • new/deleteを利用する
  • タスクに具体的な実装を与える仕組み
    • 継承と仮想関数を利用する

実装例

#include <stdio.h>
#include <list>
#include <algorithm>

class Task
{
public:
    virtual ~Task(){}
    virtual void Update( void ){}
    virtual void Draw( void ){}
};

class TaskController
{
    std::list<Task*> m_TaskList;
public:
    ~TaskController()
    {
        for ( std::list<Task*>::iterator it = m_TaskList.begin(); it != m_TaskList.end(); ++it )
        {
            Task* p_task = *it;
            delete p_task;
        }
    }
    void AddTask( Task* p_task )
    {
        m_TaskList.push_back( p_task );
    }
    void EraseTask( Task* p_task )
    {
        std::list<Task*>::iterator it = std::find( m_TaskList.begin(), m_TaskList.end(), p_task );
        if ( it != m_TaskList.end() )
        {
            delete *it;
            m_TaskList.erase( it );
        }
    }
    void Update( void )
    {
        for ( std::list<Task*>::iterator it = m_TaskList.begin(); it != m_TaskList.end(); ++it )
        {
            Task* p_task = *it;
            p_task->Update();
        }
    }
    void Draw( void )
    {
        for ( std::list<Task*>::iterator it = m_TaskList.begin(); it != m_TaskList.end(); ++it )
        {
            Task* p_task = *it;
            p_task->Draw();
        }
    }
};

class TaskPlayer : public Task
{
    int m_AttackWait;
public:
    TaskPlayer() : m_AttackWait( 0 ){}
    virtual void Update( void )
    {
        m_AttackWait++;
        m_AttackWait %= 3;
    }
    virtual void Draw( void )
    {
        if ( m_AttackWait == 0 )
        {
            printf( "Player:Attack\n" );
        }
    }
};

class TaskEnemy : public Task
{
    int m_AttackWait;
public:
    TaskEnemy() : m_AttackWait( 0 ){}
    virtual void Update( void )
    {
        m_AttackWait++;
        m_AttackWait %= 10;
    }
    virtual void Draw( void )
    {
        if ( m_AttackWait == 0 )
        {
            printf( "Enemy:Attack\n" );
        }
    }
};

int main()
{
    TaskController taskController;
    taskController.AddTask( new TaskPlayer );
    taskController.AddTask( new TaskEnemy );
    for ( int i=0; i<30; ++i )
    {
        printf( "Turn:%d\n", i+1 );
        taskController.Update();
        taskController.Draw();
    }
    return 0;
}

※このコードはいろいろと安全性の配慮に欠けています。例えば、AddTaskにすでに追加済みのポインタやNULLポインタが入ってくることが考慮されていません。

まとめ

C言語とは違いC++では簡単にタスクシステムを構築することができます。クラス、継承、仮想関数、STLの勉強にもなるので自分で作ってみることをおすすめします。

【次回予告】タスクシステムからの脱却を考える