[Unity] 新UGUIでゲーム内にモーダルダイアログ(ポーズメニュー)を表示する

Pocket

Unityでゲーム内モーダルダイアログ(ポーズメニュー)の表示に挑戦しようと思います。

発端は「Escapeキーが押されたらダイアログを出したい!」と思い調べてみたら、Unityにはモーダルダイアログ/モーダルウィンドウの類は存在しないこと知りました。無いものはしょうがないので自作しよう、というわけで実装してみた内容をまとめました。今回も実装方法が正しいかどうかわかりません。

 

2015/1/27 追記

この方法だとポーズを解いた時にアニメーションが停止位置から再生されません。やはりTime.timeScale=0の方法が良さそうですね。

 

 

 

環境

Unity 4.6 + UGUI

 

参考にしたサイト

【Unity Action】 ポーズメニュー怖い(Time.timeScale = 0 関連の話)
http://hideapp.cocolog-nifty.com/blog/2013/06/unity-action-ti.html

[Unity] ポーズ動作をTime.timeScale=0を使わずに実現する
http://ftvoid.com/blog/post/660

[Unity] ポーズ動作をTime.timeScale=0を使わずに実現する(その2)
http://ftvoid.com/blog/post/662

モーダルダイアログではなくポーズメニューが一般的だったね。まぁモーダルダイアログでも通じると思うから・・・。

 

目標

  • モーダルダイアログ表示中は他の操作を無効にしたい
  • ゲーム内時間を止めたい

 

定義

2つの組み合わせで4つのパターンが出来ます・・・

  1. 他の操作無効 + ゲーム内時間の停止 = システムモーダルダイアログ
  2. 他の操作無効 + ゲーム内は停止しない = モーダルダイアログ
  3. 他の操作も可能 + ゲーム内は停止しない = モーダレスダイアログ
  4. 他の操作も可能 + ゲーム内時間の停止 = 一時停止機能

※ゲーム内時間の停止にはアニメーションの停止を含みたい場合と、アニメーションは停止させたくない場合がありそうです。例えば攻撃モーション中にポーズをした時、ゲーム内の状態が変わりうる攻撃モーションは停止するが、ゲーム内の状態が変わらない草木の揺らぎなどは停止する必要がない、みたいなの。でもとりあえず考えない!

 

結果

注意、音が出ます!

画面上に3つボタンがあり、ダイアログの出方が異なります。ただすべての状態でTime.deltaTimeは一定のままです。

3Dモデル : Animated Knight and Slime Monster

音楽 : 魔王魂

 

 

時間停止を再現する方法

こちらの考えをいただきました。ありがたやー。

[Unity] ポーズ動作をTime.timeScale=0を使わずに実現する
http://ftvoid.com/blog/post/660

[Unity] ポーズ動作をTime.timeScale=0を使わずに実現する(その2)
http://ftvoid.com/blog/post/662

Behaviour.enabled = falseでUpdateメソッドが呼ばれなくなるなんて!

 

入力無効にする方法

Canvasの下にあるGameObjectを対象にし、 UnityEngine.UI.Selectableコンポーネントを検索し interactable = false とすることで入力系を無効にしました。

 

考え方

参考にした記事では時間停止/入力無効にしたいGameObjectに対してPauserスクリプトを追加することで対応していますが、開発が進んでいくと面倒になりそう、デバッグが大変になりそう、などが考えられるのでPauserスクリプトを追加することなく実装していきます。

つまり開発しているプロジェクトの途中でも追加できる!

 

実装方法

単純にGameObjectを列挙し「Canvasの子GameObjectはすべてUI関係」、「Canvas以外のGameObjectはすべてGame関係」と判断します。

列挙したものに対して参考サイトのPauserスクリプトの内容を実行してあげます。これで完成です。

 

時間停止/入力無効クラス(TimePauserクラス)

参考サイトのPauserスクリプトを元に改造したコードです。

TimePauser.cs

 

2種類のダイアログクラス

実際に制御が必要なのはシステムモーダルダイアログ、モーダルダイアログの2種類なのでクラス化しておきます。

作成したクラスはダイアログ化したいGameObjectに追加すればOK。

Dialog.cs

NormalModalDialog.cs

SystemModalDialog.cs

 

時間停止/入力無効をしたくない例外的なオブジェクト

UIを無効にし、ゲーム内時間を止めたとしても無効にされなくないオブジェクトが存在します。そういうオブジェクトに何かスクリプトを付けて・・・と思ったのですがこれも面倒、忘れそうだったので、TimePauserクラス内で判断するようにしました。

例外オブジェクトは

  1. カメラ
  2. ライト
  3. イベントシステム
  4. GameObject.Nameに”(non_timescale_object)”が含まれるもの

最後の「GameObject.Nameに”(non_timescale_object)”が含まれるもの」が必要な理由は、空のGameObject + 音楽制御用のスクリプト等だった場合、無効にすると音楽が停止します。(うわーローカルルールが増えたー。)

この例外的オブジェクトチェックはプロジェクトによって変化すると思います。あとカメラやライトが一番上の階層にいる前提なので注意ですね。

 

制限

  • Canvasを利用しているのでUGUI 4.6でないとUIとGameの2つに分離できない。つまり旧GUI(?)やOnGUIを使用している場合は対応できない。
  • カメラ、ライト、イベントシステムが一番上の階層にいることが前提。
  • 時間停止をしたくないオブジェクトは、一番上の階層に配置し、かつ名前の中に「(non_timescale_object)」を含めなくてはいけない。
  • なぜかパーティクルは停止しない、これは意図していません。

 

まとめ

依存関係を作ることなくモーダルダイアログ機能を実装できました。気に入らなければTimePauser、Dialog、SystemModalDialog、ModalDialogの4つのファイルを消せば元通り。

さらにTime.timeScaleを0にしているわけではないのでTime.deltaTimeなどはそのまま使用できますし、ゲーム内の時間が停止しているなのでアニメーションも動きます。

 

ただTime.timeScale = 0で止める方が正解かも。

【Unity Action】 ポーズメニュー怖い(Time.timeScale = 0 関連の話)
http://hideapp.cocolog-nifty.com/blog/2013/06/unity-action-ti.html

【Unity】時間を止めてもアニメーションさせる
http://bribser.co.jp/blog/timescale-animation/

 

こちらのサイトでもTime.timeScale = 0を使用してポーズを再現しています

CREATE A SLIDING PAUSE MENU – UNITY 4.6 GUI
http://www.thegamecontriver.com/2014/10/create-sliding-pause-menu-unity-46-gui.html

シンプルでわかりやすい。

 

ただ今回の記事で他のボタン等の入力を不可に出来たので、その点だけは使えるのかなと・・・

Pocket

希木小鳥

Diablo1でハクスラの世界に。今はPath of Exileをプレイ中。長くやっていてもNoob属性は常に付いている。そのくらい行き当たりばったり。オタクになれないゲーマー。

You may also like...