C++ ゲーム開発

Unity っぽくゲームのシーン管理をしたい! 設計編.

まとめ

  • Unity っぽくシーン管理するための設計(というかまだ妄想)をしたのでそのメモ

 

そもそもシーン管理とは

要するに,
タイトル画面 → ゲーム画面 → リザルト画面
のような感じで,
各画面をシーンと呼び,
画面遷移を行うこと.

をシーン管理と呼ぶ.*1

本によっては「シーケンス」という呼ばれ方もしているが,
一般的には シーン と呼ばれることが多いように思う.

普通にやるだけなら switch で分岐すれば十分なのだけど,
大規模なゲームには複雑なシーン管理がつきもの*2

そうなると switch では役不足.
あときれいな設計にしたいのがプログラマの性.

汎用エンジンではどのように解決しているかをまずは知る.

実現したいこと

Unity でのシーン管理

Unity では,各シーンがファイル化されている.

スクリプト上から 別のシーンを読み込む時は以下のようにする.

SceneManager.LoadScene("Hoge");

※文字列でシーンの名前を指定して,
LoadScene する.

また,シーンの追加読み込みに対応していて,

SceneManager.LoadScene("Hoge", LoadSceneMode.Additive);

とする.

これはメニューを別シーンで表現したり,
広大なマップの追加読み込みに使用したりする*3

また,当然シーンのアンロードもできて,以下のようにする.

SceneManager.UnloadSceneAsync("Hoge");

忘れてはいけないのが,
スクリプト上からシーンを切り替えたいときには,
ビルド設定のシーン一覧に
あらかじめ呼び出し予定のシーンを
登録しておく必要がある

f:id:gothlab:20210722235727j:plain

実現したいこと

Unity のようなインターフェースで,
シーンの切り替えを実現したい.

つまり,

SceneManager::LoadScene("Hoge");

でシーン切り替え,

SceneManager::UnLoadScene("Hoge");

でシーンの解放,

SceneManager::LoadScene("Hoge", SceneManager::LoadSceneMode::Additive);

でシーンの追加読み込み.

を実現したい.

シーンのファイル化は今の所考えていないが,
コードのスクリプトコンポーネント化は行いたいので,
シーンの指定は文字列での指定としたい.
※リフレクションのような機能は使用しないため.

ざっくりした設計というか妄想

シーンの基底クラスとシーン管理クラスは必要そう.

  • Scene
  • SceneManager*4

Scene クラス

各シーンの基底となるクラス.
コイツを継承して,各 シーンクラスを実装する.

純粋仮想関数
Update()
を持ち,各シーンでの更新処理を行う.

SceneManager クラス

インターフェース

  • LoadScene()
  • UnLoadScene()
  • Update()

を持つ.

また,内部に現在実行すべき Scene を持ち,
その Scene の Update() を呼ぶことで,
各シーンの更新処理を一手に担う.

追加読み込み用の enum

  • Single,
  • Additive

も持つ.

ざっくりした使用方針

Scene を継承したシーンクラスを定義する.
例えば,

class TitleScene : public Scene
{
void Initialize();
void Update();
void Finalize();
};

のようなイメージ.

これの Initialize(), Finalize() でリソース管理,
Update() 内で各シーンの更新処理を行う.
例えば,

void TitleScene::Update()
{
//エンターを押したら ShootingScene シーンに遷移する.  
if( CheckHitKey( KEY_INPUT_RETURN ) == 1 )
{
SceneManager::LoadScene( "ShootingScene" );
}
}

みたいな感じ.

これで各シーンが自身が必要なリソースも管理できるし,
追加読み込みによってシーンを階層構造とする必要もないしで,
設計がスッキリしそう.

ユーザーは,
SceneManager::Update() をゲームのメインループの中で呼ぶ.

SceneManager は,
現在実行すべきシーンの Update() 全てを呼ぶ.

全ての シーン は Scene を継承しているので問題なく可能.
実行すべき Scene は リストで持つのが妥当.
※ Unity のように複数シーンを同時に実行する可能性があるので.

つまり,こんな感じ

for each( auto&& scene in m_currentScenes )
{
scene->Update();
}

おわりに

絶賛実装中.
実装できたら実装編を書く.

実装した.

*1:少なくともこのブログでは

*2:だと思っている

*3:のだと思っているが実際は知らない

*4:※Manager という命名は悪手だが,わかりやすさを重視する.

  • この記事を書いた人

GOTH

鹿児島県出身,吉祥寺在住の27歳.職業はゲーム会社でプログラマー.趣味はバイク,車,キャンプ,ガジェット,読書,そしてゲーム開発. サイトのテーマはプログラミングとガジェットでライフハック.たまに趣味に関する雑感や記録を残していく備忘録.ツイッターもやってます.
自己紹介
お問い合わせ

-C++, ゲーム開発