自己流SceneManager

github.com

Sceneに渡す引数をキャストしたくない

 今回は自己流のSceneManagerを作りました。今回一番重視した点は「Sceneに渡す引数をキャストしない」ことです。

 例えば、キャラクター詳細シーンがあった場合、どのキャラクターについて表示するかはキャラクター詳細シーンの呼び出し側からキャラクターのIDを渡すと思います。これをint型で渡すの難しく、大抵はobject型にキャストして渡すことになると思います。難しい理由は次の2点です。

  • シーンの読み込みは非同期なので呼び出し時点では呼び出されるシーンは存在しない
  • 他のシーンの引数がint型とは限らない

 呼び出し時点でシーンが存在しないので、シーン引数は一時的に保存しておく必要があります。また、シーン引数はシーンによって変わるため、どんな型が来ても大丈夫なようにobject型で保存することになります。

 ただ自分はどうしてもobject型へのキャストを避けたいと思っていました。その理由は2つです。

  • ダウンキャストは危険なので行いたくない
  • 引数のヒントが無くなる

 渡される引数がobject型なのでどんな型でも来る可能性があるということです。 int型を要求するシーンでも絶対にint型をもらえるとは限りません。

 また、どのような引数を渡せばよいか、object型ではひと目ではわかりません。引数の型については受け取るシーンのソースコードを読む必要があります。シーンを作成した直後は覚えているでしょうが、1ヶ月後にもなればシーンを作った本人も忘れています。ドキュメントにして残しても、変更があった場合にドキュメントが変更される保証はありません。

Sceneに渡す引数をActionで保存する

 この問題の解決策としてAction<T>として保存することにしました。Tはシーンが読み込まれたときにSceneDirecotr(自己流SceneManagerの名前)にアクセスするクラスです。このクラスにはわかりやすいように○○SceneStarterという名前を付けるようにしました。

 例えばTitleシーンの読み込みには

sceneDirector.LoadFromBuiltinAsset<TitleSceneStarter>("Title", (TitleSceneStarter ss) => ss.SetArgument("User1"));

という形で呼び出し、(TitleSceneStarter ss) => ss.SetArgument("User1")の部分をActionとして保存します。保存先はSceneDirectorの中に

class LoadedActionCache<T>
{
    public static Queue<Action<T>> Queue { get; } = new Queue<Action<T>>();
}

というCacheクラスを作って保存します。Queueなのは複数回同時にScene読み込みが行われた場合を想定しています。

参考:http://engineering.grani.jp/entry/2017/07/28/145035

 Titleシーンが読み込まれたらTitleSceneStarter.Start()がSceneDirectorにアクセスして保存してあったActionを受け取り、自分を引数にして実行します。これでシーン引数の受け取りが完了します。

懸念点

 Actionをstaticな領域に保存していますが、これを初期化する方法を考える必要があります。エラーで「タイトルに戻る」という処理を実装する場合、このstaticな領域にActionが残ったまま再開されてしまう可能性があります。