作りたいゲームがあるから作る ー場面を変える

ただの日記の1ページ

以下のことは「ゲームプログラマになる前に覚えておきたい技術」
という本に大体書いてある
この本はもう古いもの(になったと思う)だが、以下のこと以外も結構書かれており重要だと思う
ゲームエンジンで省略されている一部分もわかる、かもしれない

主題:タイトル画面→ゲーム画面→スコア画面→タイトル画面みたいに、場面を変えたい

場面変換、シーン制御、シーン遷移などと言ったりする、たぶん

やりたいことをもうちょい噛み砕いてみる
「タイトル画面では、上キーを押すとコマンドが移動して、
 newgameで決定キーを押すと新しくゲームが始まって...なんちゃら」
「ゲーム画面では、なんちゃら、スコアなんちゃら」
・・・各画面内での詳しい仕様は決まってないし、あとあとで仕様変更なんて日常茶飯事
とりあえず、各画面には「次に更新すべき画面番号」を返してもらって制御してみる

while(true){
  switch(今の画面の番号){
  case タイトルの番号:
    次の画面の番号 = タイトル画面を動かす();
    break;
  ...
  }
  今の画面の番号 = 次の画面の番号;
}
...

規模が小さければこれでぶっちゃけ十分である
しかし、物が大きくなるとこれでは済まされない部分(メモリだったり、画像や音声などのリソース)
も出てくる
あと、上のwhile文のswitchも冗長に見えて、
次の画面の番号ではなく、「次の画面」自体を返してしまえばいいのでは?と考えられる

ここで有用となるのがインターフェース、仮想関数、継承である
画面(インターフェース)クラスに次の画面を返す関数とかを用意してあげる
このクラスを継承した各画面では、動かすのに必要な分だけメモリやリソースの確保を行う

class 画面{
  virtual ~画面(){}
  virtual 画面* update(){return 次の画面;}
  virtual void draw(){}
  virtual void load(){}
}

class タイトル 継承 画面{...}

...
画面* 今の画面 = タイトル;//最初に出す画面
//(1)
while(true){
  画面* 次の画面 = 今の画面->update();
  if(次の画面 != 今の画面){
    ポインタを使うことによる安全対策;
    今の画面 = 次の画面;
    今の画面->load();
  }
}

なぜロードをコンストラクタとしてまとめず、分割しているかはいつかどっかに書くかもしれない
こんなような構成をすることで、どの画面からも自由に他の画面へ移れる
他の画面に移りたくないときはupdate内にthisで自分自身を次の画面として返せばいい

仮に、さらにタイトル内で細かい画面(続きから画面とか設定画面とか)を作りたくなったら、
タイトルクラス内でさらに画面クラスを継承した続きからクラス、設定クラスを管理して、
(1)の制御のwhileをとったようなものをupdate内に入れるとかやるとできる
この場合は、コマンドを動かしてnewgameとか続きからとかを選ぶ画面と、続きからの画面と、設定画面と、
みたいにわけてクラスを書くことになると思う

ぼやき

この記事軽く読み返したら意味わからんかった、冒頭に示した本の内容の受け売りだからな・・・
あと、3Dなどオープンワールド系のゲームを見てると必ずしもこれが正しい実装方針とは言えない気がする
やはりリソースのID登録消去方式なんだろうか・・・
考えることをやめないようにしたい

以上