が、その実装方法というものがどうしても泥臭くなりがちです。
皆さんは画面遷移するとき、どういう実装にするのでしょうか。
(正直に言うと、ここが一番知りたいところです)
例えばこんな感じでしょうか。
enum SCENE_ID
{
SCENE_ID_DUMMY = 0,
SCENE_ID_LOADING,
SCENE_ID_TITLE,
SCENE_ID_GAMEMAIN,
SCENE_ID_GAMEOVER,
};
namespace
{
SCENE_ID CURRENT_SCENE;
}
void mainloop()
{
for(;;)
{
switch(CURRENT_SCENE)
{
case SCENE_ID_LOADING:
loading_update();
loading_draw();
break;
case SCENE_ID_TITLE:
title_update();
title_draw();
break;
case SCENE_ID_GAMEMAIN:
loading_update();
loading_draw();
break;
case SCENE_ID_GAMEOVER:
gameover_update();
gameover_draw();
break;
case SCENE_ID_DUMMY:
default:
break;
}
}
}
これでも悪くはないのですが、画面にも細かい状態があり、初期化中であったり終了中であったりするはずです。
そうなるとloading_updateの中にさらにswitch文が重なっていくことになります。
そこで、画面を一つのインターフェイスとし、そこから派生して行けば楽ではないか?
ということで書いてみます。
class IScene
{
public:
Scene();
virtual ~Scene();
virtual void update() = 0;
virtual void draw() const = 0;
};
namespace
{
IScene *CURRENT_SCENE;
}
void mainloop()
{
for(;;)
{
CURRENT_SCENE->update();
CURRENT_SCENE->draw();
}
}
限りなく正解に近い気がしてきました。
でも、これだと肝心の画面遷移が出来ません。
だったら、ISceneのリストを持っておいて、画面遷移時にリストに新しいISceneを追加して、updateでfalseを返すと勝手に消してくれるようにすればうまくいきそうじゃないか。
class IScene { /* 省略 */ };
namespace
{
typedef std::vector SceneList;
SceneList CURRENT_SCENE;
}
void mainloop()
{
for(;;)
{
// 更新
for(SceneList::iterator it = CURRENT_SCENE.begin(); it != CURRENT_SCENE.end(); /* empty */ )
{
if(!it->update())
{
it = CURRENT_SCENE.erase(it);
}
++it;
}
// 描画
for(SceneList::iterator it = CURRENT_SCENE.begin(); it != CURRENT_SCENE.end(); ++it )
{
it->draw();
}
}
}
結局タスクみたいなことをしてるだけですが、最初のswitch文よりは保守性も可読性も上がったと思います。
(正直画面遷移に保守性も糞も無いと思うのですが……)
ということで、私はこんな感じでやってますが、皆さんはどんな実装なのでしょうか。
もっと良い実装があれば教えて欲しいです。