何はともあれメニューが必要(2)

もくじへ戻る


前回,とりえあず原始的な実装を考えたけど,実際に使っていくには階層構造
(:「このキャラクタの → このアイテムを → このキャラクタに → 使う」みたいに次々と選んでいくやつ)
を扱うための実装が必要だろう.
……というわけで考えてみる.


スタックですか?→多分そう

「このキャラクタの → このアイテムを → このキャラクタに → 使う」みたいに次々と選んでいくやつ

とかいう話は,「スタックかな?」とか真っ先に思うのでその方向で.
とはいえ,我の拙い経験上,そこで「そしたら std::stack で!」と安易に飛びつくと可能な操作が限定されすぎていて後で泣くことになるのが目に見えているのですぞ!
……ってことで,とりあえずは std::list あたりに逃げておくことにしよう.

//スタックに積まれるやつ.
//「メニュー」だけに限定する必要はないので「入力を処理できて,何か描画できるやつ」という話にする
//(まともな名前が全然思いつかない!!)
struct IGUI
{
  //更新処理.
  //戻り値は未定,引数は操作入力情報
  virtual UpdateResult Update( const IController &Controller ) = 0;
  
  //描画処理
  virtual void Draw() const = 0;
};

//スタック
struct GUIStack
{
public:
  //プッシュ
  void Push( std::unique_ptr<IGUI> upGUI ){  m_GUIs.emplace_back( std::move(upGUI) );  }
  
  //更新処理
  //スタックのトップにあるやつの Update() を呼ぶ
  void Update( const IController &Controller )
  {
    if( !m_GUIs.empty() )
    {  m_GUIs.back().Update( Controller );  }
  }
  
  //描画
  //スタックに Push された順に Draw() を呼ぶ
  void Draw() const
  {
    for( const auto &upGUI : m_GUIs )
    {  upGUI->Draw();  }
  }
  
private:
  std::list< std::unique_ptr<IGUI> > m_GUIs;  //順序は,最後にPushされたものが back 側
};

とりあえず最初の形としてはこのくらいじゃなイカ?

Push() の引数はそれでいいのか?

「引数が std::unique_ptr の場合は↑のコードみたく値渡しな書き方なのかそれとも std::unique_ptr<IGUI> && って書くのか? どっち?」とかいう実装方法の迷いの話ではなくて,
std::unique_ptr だと Push() に渡した物の所有権が持ってかれるけど,それOKか?」っていう話.

このへんは以下のように他の型についても考えたんだけども,今現在の結論は「 unique_ptr でおk」かな,と.

いつ Pop するのか?

IGUI::Update() が戻り値で「俺はもう終わり」って言ってきたら m_GUIs から除去する,っていうルールでいいんじゃないかな.

Draw()の仕様はそれでいいのか?

「階層的なメニュー」を想像すると,とにかく全員の Draw() を呼ぶ必要があると思う.
しかし,誰かが「画面全体」を占める描画を行う場合,それより先に行われた描画処理は全て無駄ってことになる.
そんな無駄な処理はしたくないが……

その他

必要に応じて IGUI に各タイミングでスタック側から呼ばれるメソッドを付けておくとよいかも.
(メニューにフォーカスがあるか? みたいなのの制御に使えそう)


スタックにメニューを積むには?

前回考えたメニューの実装と,ここで考えた IGUI とを繋ぐ型を用意する必要がある.

//スタックに積めるメニュー型
class Menu_As_IGUI : public IGUI
{
  /* IGUI::Update() や IGUI::Draw() で先に考えたメニューの実装を使う */
};