タスクシステムと描画管理

タスクマネージャの実装についてid:a_little_bit:20050323氏がNested Classというテクニックを紹介されている。なるほどこんなテクニックもあるのか、凄い。というわけでタスクシステムと描画管理について考えてみる。

今のところ漏れはこういう実装にしている。

class CTaskBase
{
    virtual void     onUpdate() = 0;

    virtual void    isVisible();
    virtual int      getDrawPriority();  
    virtual void    onDraw();
....
};

class CTaskManager {
    void callUpdate();
    void callDraw();   
    
    vector<CTaskBase*>  taskList;
    vector<CTaskBase*>  drawList;
  ...
};

CTaskManager::callUpdate()はtaskListに登録されている全てのクラスのonUpdate()を呼び出す。この時点でisVisible()がtrueであるタスクはdrawListに登録される。
CTaskManager::callDraw()でdrawListに登録されたタスクが描画優先順でソートされてCTaskBase::onDraw()が呼び出され、drawListは消去されるという仕組み。

気に入らないのは、CTaskBase::onDraw()やisVisible()などの関数が増えてしまうこと。描画だけならまだしも、衝突管理やタスク間メッセージのやりとりまで盛り込んで行くと、CTaskBaseやCTaskControlがどんどん肥大化していく。そもそもタスクを管理するのが仕事のCTaskControlが描画順の管理まで行うのは正しい設計ではないのでは?

そこで描画管理を専門に行うCDrawControlTaskというタスクを新たに作ることを考えた。描画インターフェースクラスであるIDrawableも新たに作る。

class IDrawable
{
     virtual void    onDraw() = 0;
     virtual int      getDrawPriority() = 0;  
};

class CDrawControlTask: public CTaskBase
{
    void addDrawable(IDrawable*);

    vector<IDrawable*>  drawList;
};

class CMyShip : public CTaskBase, public IDrawable
{
    virtual void onUpdate();
    virtual void onDraw();
....
};

CDrawControlTaskは特殊なシステムタスクとして、実行フェイズを全てのタスクの最後にずらしてやる必要がある。こうすれば、CTaskControlは描画順の管理から開放されるし、CTaskBaseも余計なメンバを持たずに済む。
多重継承はプログラムの見通しが悪くなりそうで、あんまり好きでなかったけれど、こういう使い方はいいかも。衝突管理やメッセージの送受信も似たような設計でいけるかな。