徳島ゲーム開発ごっこ 技術ブログ

ゲームを作るために役に立ったり立たなかったりする技術を学んでいきます!

【Unity】僕もPhotonを使いたい #17 シーンを管理したい

 再びPhotonを使ったゲーム作りを再開しましょう。
 ひと月前に、Photonのプロジェクトを三か月ぶりに立ち上げ警告文を消すだけで終わった前回の作業。
 ちなみに、Photonがまた更新されていたので、まったく同じ作業をもう一度やるはめになりましたよ!

 それでは今回は、このプロジェクトのシーン管理システムを作っていきましょう。
 シーンの切り替えなどはちゃんとシステム化しておいたほうがいいですからね。

 とはいえ、どういう風にシーンを管理をしましょうか。
 一度前回のゲームジャムで作ったシーン管理システムを見直してみましょうか。


この記事にはUnity5.6.0f3を使用しています。

私はこのシーン管理クラスでゲームジャムを乗り切りました

 さて直近作ったゲームと言えば、今年の一月末に参加したゲームジャムの作品ですね。
 このゲームのシーン管理はこんな感じで作っていました。

SceneController.cs SceneController.cs

SceneTable.cs SceneTable.cs

シーンの情報はScriptableObjectを使って管理!

 各シーンの情報は先日にも書いたScriptableObjectを使って管理しています。

www.urablog.xyz

 各シーンの識別はenumを使い、さらに以前作ったEnumListLabelを使用して、アセット上でどのシーンなのか分かりやすくしています。

www.urablog.xyz

f:id:urahimono:20170406232555p:plain

 シンプルな作りで使いやすい形にはなっているのですが、この各シーンの識別にenumを使う点はどうなのでしょうか。
 シーンをロードする際など、スクリプト上で各シーンを識別する際に、シーンのファイル名を直接扱っていると、文字列であるため打ち間違えてもコンパイルエラーにはならないし、シーン名が変わったらそのシーン名を使っているスクリプトをすべて書き直す必要があります。
 enumを使えば上記点をクリアできるのですが、いくつか欠点が。

 シーンを増やす場合、このenumも一緒に増やす必要があるということ。
 シーンを増やすのにスクリプトも書き換えねばならないのは、ちょっと面倒くさいなぁ。
 そしてEnumListLabelとの相性の問題から、enumに追加する場合、今まであるenumの間に挿入すると、テーブルが壊れてしまうという欠点が……。
 現に実際に使っていたenumも、最初の方はゲームの遷移順に記述されているけど、途中からバラバラになっていってるのがわかります。
 Logoとかすげぇ下の方に書いてるもんなぁ。

 今回のゲームでは改善してみたいな。

フェードシステムは去年の福島ゲームジャムの使いまわし!

 シーンがパッと切り替わるより、フェードがあった方が見栄えがいい!
 そしてフェードシステムは、以前纏めましたから、それを組み込むだけ。簡単!

www.urablog.xyz

 ただこれにも欠点が……。
 SceneControllerChangeSceneProcess()を見てみるとシーンの切り替え手順として、

  • フェードアウト
  • シーン読み込み
  • フェードイン

 となっています。
 問題なのは、フェードインの最中にはすでにシーンが読み込み終わっているので、読み込まれたシーンは元気いっぱいにUpdate()が呼ばれまくっているということです。
 ゲームジャムの作品でキャラクターの選択シーンがあるのですが、フェード中にキャラクター選択のアニメーションが開始してしまい、フェードが明けた後にはすでにアニメーションが終わっているという悲劇が……。作ってくれた学生さんすまない。

 フェードが明けてから、シーン内のUpdaete()が掛かるように工夫する必要がありますね。

SceneControllerにAudioを持たせる大技!

 ゲームジャムのシーン管理システム振り返ってみて、一番気になったところがここだよ。
 SceneControllerAudioSourceを持っている点だよ。

private AudioSource     m_bgmAudio              = null;
private FadeController  m_fadeController        = null;
private string          m_beingChangedSceneName = null;

private void Awake()
{
    m_bgmAudio      = gameObject.AddComponent<AudioSource>();
    m_bgmAudio.loop = true;

    gameObject.AddComponent<AudioListener>();
}

 えーと、スクリプトを見る限り、シーン切り替え時にこのAudioSourceを使って各シーンのBGMを鳴らしているというわけだね。
 そういえば、シーンのScriptableObjectにもBGM用のアセットデータを持つプロパティがあったよ。それと組み合わせているわけか。
 ただ、この作りだとオプションでBGMの音量を調整するメニューを作った際に、BGMの音量を変えるためにSceneControllerにアクセスし始めるという不可思議システムになってしまう!

 この部分は今回作るゲームでは廃止しよう。
 音を管理するコントローラーにその手の処理は任せるとします。
 この件はゲームジャム専用処理ということで……。

 あっ!
 よく見たらAudioListenerまでSceneControllerにくっつけてるじゃないか!

docs.unity3d.com

 鳴らした音を実際に聴けるようにするには、シーン中にAudioListenerが必要なのですが、AudioListenerは一つあればいいんです。
 大抵は3Dサウンドのためなどに、カメラとかに付けている場合もあるのですが、ただSceneControllerには付けないだろう。
 しかも我らがUnity様は、シーン中にAudioListenerが複数あると、烈火のごとくログを吐き出すという仕様があるというのに。

f:id:urahimono:20170406232818p:plain

 このスクリプトだけで、当時どんだけ自分がテンパっていたかがわかるよ。

今回のプロジェクトでは?

 うーん、振り返ってみるといろいろ使いにくい点なども見えてきました。
 今回のプロジェクトはゲームジャムやぷちコンみたいに締め切りがあるわけではないので、少しシーン遷移について考えてみます。
 そもそもこのシーン管理システムの大元は二年ぐらい前から使っているものなので、複数シーン対応とか考えていませんからねー。
 折角なのでその辺も使ったシステムを作っていきましょう。