(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

シーンの遷移とフェードを管理するクラス【Unity】【uGUI】


このエントリーをはてなブックマークに追加

この記事でのバージョン
Unity 5.6.1f1


はじめに

今回はタイトル通り、シーンの遷移とフェードを管理するクラスのご紹介!

なるべく分かり易いようにシンプルな作りにしてみました。イメージとしては以下のような感じ。

//シーンの遷移とフェードを管理するオブジェクトの作成
new GameObject().AddComponent<SceneNavigator>(); 

//シーンの遷移&フェード
SceneNavigator.Instance.Change("SceneName");

f:id:kan_kikuchi:20170516055601g:plain


SceneNavigator

早速ですが、シーンの遷移とフェードを管理するクラスSceneNavigatorのプログラムです。

なお、SceneNavigatorを使うにはCanvasFaderSingletonMonoBehaviourが必要になります。



上記三つのスクリプトを作成し、適当なGameObjectにアタッチすると自動で設定が完了します。


f:id:kan_kikuchi:20170516055441p:plain
f:id:kan_kikuchi:20170516060550g:plain


また、プログラムから作成したい場合は以下の1行でOK。

//シーンの遷移とフェードを管理するオブジェクトの作成
new GameObject().AddComponent<SceneNavigator>(); 


ここで注意が必要なのが、SceneNavigatorは複数配置するとエラーが出る事です。

最初のシーンにだけ配置する、または作成するプログラムを一度だけ実行するようにしましょう。

もしくは以下の方法を併用すると良いかもしれません。





使い方

使い方も簡単、シーンの移動はシーン名を指定してChangeを使うだけ。

フェードの時間も設定できます。

//Scene1へ遷移
SceneNavigator.Instance.Change("Scene1");
//Scene1へ遷移、フェードインとフェードアウトの時間をそれぞれ1.5秒に設定(デフォルトは0.5秒)
SceneNavigator.Instance.Change("Scene1", 1.5f);


また、SceneNavigatorのイベントにメソッドを登録する事で、

フェードアウトやフェードイン終了時の処理を行う事も簡単にできます。

その際、CurrentSceneNameで現在のシーン名、BeforeSceneNameで一つ前のシーン名、

NextSceneNameで遷移しようとしている次のシーン名を取得できます。

private void Start () {
  DontDestroyOnLoad(gameObject);

  //イベントにメソッド登録
  SceneNavigator.Instance.FadeOutFinished += OnFinishedFadeOut;
  SceneNavigator.Instance.FadeInFinished  += OnFinishedFadeIn;
}

//フェードアウトが完了した(シーンの遷移はまだしていない)時に実行される
private void OnFinishedFadeOut () {
  Debug.Log(SceneNavigator.Instance.CurrentSceneName + " から " + SceneNavigator.Instance.NextSceneName + " へ遷移中!");
}
	
//シーンの移動後、フェードインが完了した後に実行される
private void OnFinishedFadeIn () {
  Debug.Log(SceneNavigator.Instance.CurrentSceneName + " に遷移完了!前のシーンは" + SceneNavigator.Instance.BeforeSceneName);
}

f:id:kan_kikuchi:20170516062940g:plain


利用方法としては、シーン移動前のフェードアウト時にメモリを解放を行う、

特定のシーンへの移動時に何か処理を挟む、などが考えられます。


さらにIsFadingでフェード中か(シーン遷移中か)を判定する事も出来ます。

private void Update (){
  if(SceneNavigator.Instance.IsFading){
    Debug.Log("フェード中です!");
   }
}

f:id:kan_kikuchi:20170517054223g:plain


これを使えば、シーン遷移中は処理しない、みたいな事が簡単に実装できます。


実装方法

実装方法も至ってシンプルで、

SceneNavigatorの子にCanvasを、さらにその子に黒い画像のImageを作成し、

それをキャンバスごとフェードさせているだけです。ようはuGUIを使っています。


f:id:kan_kikuchi:20170517054452p:plain


フェード用の画像を表示するCanvasのSort Order は999になっているので、

他のCanvasのSort Orderをそれより大きくすると前面に表示されてしまうので注意が必要です。


f:id:kan_kikuchi:20170517054702j:plain


フェードには前に書いたUIをまとめてフェードさせるCanvasFaderというものを使っています。

ただし、CanvasFaderは以下の記事のものから少し変更がされているので、

上記リンクのものを使用してください。



また、SceneNavigatorはどこからでもアクセス出来るよう、シングルトンで作られています。



さらに、アタッチした時に自動でキャンバスなどの生成、設定を行うために

Resetというメソッドを使っています。



なお、実機上やエディタを実行している時にはAddした場合はResetが実行されないので、

自動で実行されるInitからResetを実行しています。


おわりに

最初に述べた通りシンプルな作りなので、

マルチシーンには非対応だったり、

フェード用の画像を2000*2000の決め打ちで生成してたりと

改善点は結構あったりします。


また、シーン生成に時間がかかる場合は生成中にフェードインが始まってしまい、うまくいかなくなる

という問題もあります。

その場合は以下のような処理に変更する必要が出てきます。

フェードアウト → シーン遷移 → シーン生成完了 → 遷移先のシーンからフェードイン実行


もっと簡単に実装したい場合はフェードインを遅延させるという方法もありますが、

このやり方だと、デバイスやシーンによって生成時間が異なる場合には対応できません。



ここら辺のちょっと込み入ったSceneNavigatorもそのうち記事にするかもしれません(:3っ)∋〜