【Unity】RPGを作るチュートリアルその94 フェードインとフェードアウトの実装

【Unity】RPGを作るチュートリアルその94 フェードインとフェードアウトの実装

シンプルなRPGをUnityで作るチュートリアルシリーズの94回目です。

第93回では操作キャラクターが触れた時にイベントを起動する仕組みを実装しました。

今回はフェードイン、フェードアウトの機能を実装していきます。

 

 

制作環境

MacBook Pro 2023 Apple M2 Max

Unity6 (6000.0.30f1) Silicon

 

作業内容と順序

シンプルなRPGを作る上でどんな作業が必要か、どんな順番で作っていくと良さそうか、別ページで検討しました。基本的にこの流れに沿って進めていきます。

 

チュートリアルの一覧

このシリーズ全体の一覧は以下のページにまとめています。

 

前回の内容

前回は操作キャラクターが触れた時にイベントを起動する仕組みを実装しました。

 

フェードインとフェードアウト

現在の実装だと、例えばマップを切り替える際は一瞬で画面が切り替わっています。急な切り替えは遊んでいるユーザがびっくりする可能性が高いので、徐々に画面が切り替わることを伝えるとグッド。そのための手段として画面のフェードイン、フェードアウトを実装したいと思います。

フェードとは徐々に消える、薄れる、といった意味合いで、ゲームでは画面がフェードインする=徐々に画面が表示される、フェードアウト=徐々に画面が消えていく、といった意味合いで使われたりします。これを実現するための簡単な方法として、画面を覆う画像を用意して、その画像の不透明度を徐々に変えていくものがあります。画面遷移に関しては「トランジション 種類」などで検索するとフェード以外にも切り替え時の表現が見つかるので、ゲームに合うものを試してみると良いかと思います。

フェードイン、フェードアウトの機能はイベントのみならず、システム側からも呼べると便利なので、管理用のクラスについてはpublicでstaticなフィールドを用意して簡単に呼べるようにしたいと思います。このクラスでは対応する画像をInspectorウィンドウでセットしたいので、MonoBehaviourのスクリプトで、DontDestroyOnLoadが付与されるようにします。

 

フェード画像用のUIを作成

画面をフェードイン、フェードアウトさせるにあたって、フェード用の画像を用意します。シーンを跨いで使用する可能性を考え、個別のCanvasを用意して、そこに管理用のクラスをアタッチして、シーンのロード時に破棄されず、かつシングルトンで動作するようにします。

画像については「Panel」のUIを作成することで画面いっぱいに広げたものを簡単に作成できるので、こちらを使っていきましょう。

Canvasの設定は使いまわしたいので、Hierarchyウィンドウから「Canvas」のゲームオブジェクトを複製し、名前を [FadeCanvas] に変更します。「FadeCanvas」の子オブジェクトについては全て削除しておきましょう。

フェード用のCanvas
フェード用のCanvas

 

「FadeCanvas」は通常のUIよりも画面手前に表示されるようにしたいので、Inspectorウィンドウから「Canvas」コンポーネントにて、「Sort Order」の値を [1] に変更します。

Sort Orderの設定
Sort Orderの設定

 

「FadeCanvas」の子オブジェクトとして、[UI] -> [Panel] からパネルを作成します。名前は [FadeMask] にしました。

フェード用のマスク画像
フェード用のマスク画像

 

作成した「FadeMask」のゲームオブジェクトを選択し、Inspectorウィンドウから「Image」コンポーネントの設定を行います。「Source Image」は「None」を選択して画像を使わない形にして、「Color」では黒色の [000000] にします。シーン内で作業を行う関係で、現時点では不透明度を [0] にしておきましょう。

Imageの設定
Imageの設定

 

フェードインとフェードアウトの機能を実装

続いてフェード機能を管理するクラスの実装を行います。フェードインやフェードアウトでは、完了時にそれを通知できると便利なので、通知用のインタフェースも作りたいと思います。

 

フェードの完了を通知するインタフェース

フェード完了時に通知を行うインタフェースを作成します。Projectウィンドウから「Assets/Scripts/System」のフォルダを開き、空のスクリプトファイルを作成します。名前は [IFadeCallback] にしました。

インタフェースの作成
インタフェースの作成

 

作成した「IFadeCallback」の中身は以下のように記載しました。

フェードの完了を受け取りたいクラスにてこのインタフェースを実装するようにします。

 

フェードを管理するクラス

続いてフェードを管理するクラスを作成します。Projectウィンドウから同じく「Assets/Scripts/System」のフォルダにて、MonoBehaviourのスクリプトファイルを作成します。名前は [FadeManager] にしました。

フェードを管理するクラス
フェードを管理するクラス

 

作成した「FadeManager」の中身は以下のように記載しました。

「SimpleLogger」などのように、シングルトンのMonoBehaviourクラスとして作成します。

「_fadeImage」のフィールドでは上で作成した「FadeMask」への参照を保持します。「_fadeCallback」のフィールドではコールバック先を保持します。コールバックを登録する場合はSetCallback()のメソッドを使用します。

FadeInScreen()、FadeOutScreen()のメソッドではそれぞれ画面のフェードイン、フェードアウトを行います。画面をフェードインさせるということは、マスク画像を透明にする動きになります。そのため、FadeInScreen()では画像の色を黒から透明へ、FadeOutScreen()では透明から黒へ色を変更するようにします。

MovePlayerProcess()のコルーチンでは時間経過による不透明度の変更を行います。ColorのクラスでもLerp()メソッドがあるので、こちらを使って時間経過に応じた変化の割合を計算し、不透明度の計算を行います。この実装では変化が一定になるので、もし不透明度の変化に緩急をつけたい場合は、DOTweenなどを使うと便利です。

フェード処理が完了した後にPostFade()を呼び、コールバック先が登録されていれば完了を通知します。

 

フェードインとフェードアウトのイベントを実装

せっかくフェード機能を作ったので、イベントプロセスとしても実装したいと思います。フェードイン、フェードアウトのそれぞれでクラスを作っていきましょう。

Projectウィンドウから「Assets/Scripts/Event/Process」のフォルダを開き、MonoBehaviourのスクリプトファイルを作成します。名前は [EventProcessFadeIn] にしました。

フェードインのイベント
フェードインのイベント

 

作成した「EventProcessFadeIn」の中身は以下のように記載しました。

「_fadeTime」のフィールドでInspectorウィンドウからフェードにかかる時間を変更できるようにしています。「_isWaitFade」のフラグをtrueにした場合は、フェードの完了を待って次のプロセスに進みます。

Execute()の中ではフェードの完了を待つ場合にコールバックを登録し、フェードインの処理を行います。待たない場合はフェードインの処理を呼び出したら次のプロセスに進むようにします。

 

フェードアウトについても同様にイベントプロセスを作成します。Projectウィンドウから「Assets/Scripts/Event/Process」のフォルダにて、MonoBehaviourのスクリプトファイルを作成します。名前は [EventProcessFadeOut] にしました。

フェードアウトのイベント
フェードアウトのイベント

 

作成した「EventProcessFadeOut」の中身は以下のように記載しました。

フェードインとの違いはクラス名が変わったのと、「FadeManager」で呼び出すメソッドが変わったくらいです。

フラグを使ってひとつのイベントプロセスで実装する手もありますが、イベントを試しに実装する中ではクラス名で判別した方が分かりやすかったのでこの形にしています。

 

スクリプトのアタッチ

作成したスクリプトをアタッチしていきます。

 

フェードの管理クラス

フェード用のCanvasである「FadeCanvas」に「FadeManager」をアタッチします。「Fade Image」のフィールドには「FadeMask」をアサインします。

フェードの管理クラスをアタッチ
フェードの管理クラスをアタッチ

 

フェードイン、フェードアウトのイベントプロセス

前回作成したマップ切り替えのイベントについて、急に切り替わるのではなくフェードを挟んでマップを切り替えたいと思います。イベントプロセスの処理順として、画面のフェードアウト、マップ切り替え、画面のフェードインと進めたいので、まずはフェードアウトのイベントプロセスから作成していきます。

Hierarchyウィンドウから「Map_0001_Village」の子オブジェクトの「Event_MoveMap」を選択し、さらにその子オブジェクトである「Processes」の子オブジェクトとして空のゲームオブジェクトを2つ作成します。名前はそれぞれ [FadeOut][FadeIn] にしました。並び順は以下のようにしました。

イベントプロセスの作成
イベントプロセスの作成

 

「FadeOut」のゲームオブジェクトには「EventProcessFadeOut」をアタッチします。このプロセスが先頭になるので、次のプロセスを呼ぶため「Next Process」に「MoveMap」をアサインします。

フェードアウトのプロセス
フェードアウトのプロセス

 

「FadeIn」のゲームオブジェクトには「EventProcessFadeIn」をアタッチします。最後のプロセスになるので「Next Process」はnullのままでOKです。

フェードインのプロセス
フェードインのプロセス

 

「MoveMap」では次のプロセスとして「FadeIn」をアサインします。

マップ移動のプロセス
マップ移動のプロセス

 

「EventPage」では開始プロセスが変更になったため、「Start Process」に「FadeOut」をアサインし直します。

イベントページの設定
イベントページの設定

 

イベントの設定が終わったら、「Map_0001_Village」のゲームオブジェクトを選択してPrefabに変更を反映します。

 

動作確認

スクリプトの保存とアタッチが完了したら動作確認を行います。シーン内の「Map_0001_Village」についてはPrefabに変更を適用後に非表示にしておきましょう。

マップ移動のイベント発生時、画面がフェードアウトすること、画面がフェードインすることを確かめます。

闇に飲まれる瞬間
闇に飲まれる瞬間

 

暗転後の処理が終わった後、すぐに画面を表示するか、演出として0.1秒くらい待つかは好みの分かれるところですが、ゲームの雰囲気に合わせて調整すると良いかと思います。イベントの実行中に待ち時間を発生させるプロセスについては今後作成予定です。

 

今回のブランチ

 

まとめ

今回はフェードイン、フェードアウトの機能を実装しました。画面の切り替え処理としてはフェードイン、フェードアウトは簡単に実装できるのでモック作成時に導入するのも良いかと思います。後からトランジション処理を変えるのもアリだと思います。

次回はHP/MPが全回復するイベントや待ち時間を発生させるイベント、選択肢を呼ぶイベントを実装していきます。これらを組み合わせて宿屋の処理を実装します。

 

     

ゲーム開発の攻略チャートを作りました!

CTA-IMAGE

「ゲームを作ってみたいけど、何から手を付けていいか分からない!」


そんなお悩みをお持ちの方向けに、todoがアプリをリリースした経験を中心に、ゲーム作りの手順や考慮すべき点をまとめたe-bookを作成しました。ゲーム作りはそれ自体がゲームのように楽しいプロセスなので、「攻略チャート」と名付けています。


ゲームを作り始めた時にぶつかる壁である「何をしたら良いのか分からない」という悩みを吹き飛ばしましょう!