この記事は「恋愛ホラー風ノベルゲーム」の作り方講座の第11回です。
前回キャラクターの画像や文字送りとページ送りで文章を変化させることで一通りの会話ができるようになりました。
前回の記事:
今回はノベルゲームで欠かせない会話シーン中の背景画像の変更システムの実装を行っていきます。
Unityでノベルゲームの背景画像の変更方法をマスターしよう
ここまで背景画像に関して触れてきませんでしたが、背景画像も変更できるように処理を作成していきます。
まずは現在教室の背景になっている「GameView」の子「Bg」ですが、これを「TalkWindow」で変更したいので、「TalkWindow」の子にしておきましょう。
この時ヒエラルキー上ではキャラ画像より上に配置してください。キャラ画像より前に表示されるとキャラが見えなくなります。
会話データ入力欄に背景情報を設定してみる
まずは処理の確認をするため現在の仮データに別の背景を入れておきましょう。
先ほど選択肢の時にデータを追加した「TalkWindow」の「Talks」変数の3つ目の要素の「Place」の部分に「夜の学校」という値を入れておきます。
Scriptable Objectで背景画像データを作成
次にキャラと同じく背景を変更するための画像データを作成します。
データ自体は少ないですが、キャラクターデータの時にScriptableObjectを使用したのでこちらでも同じように作成してみましょう。
新しく「BackgroundData.cs」を作成しスクリプトを下記のように作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
using System.Collections; using System.Collections.Generic; using UnityEngine; [CreateAssetMenu(fileName = "BackgroundData", menuName = "ScriptableObjects/BackgroundData")] public class BackgroundData : ScriptableObject { // メモ. [SerializeField] string Memo = ""; // パラメータリスト. public List<Parameter> Parameters = new List<Parameter>(); // ------------------------------------------------------ // 背景のパラメータ. // ------------------------------------------------------ [System.Serializable] public class Parameter { // 名前. public string Name = ""; // 画像パラメーターのリスト. public Sprite Sprite = null; } // ----------------------------------------------------------------------- // 画像名から画像を取得する. // ----------------------------------------------------------------------- public Sprite GetSprite( string imageName ) { foreach( var param in Parameters ) { if( param.Name == imageName ) return param.Sprite; } return null; } } |
内容は「CharacterData」とほぼ同じで「Parameter」の内容が変わっています。
「Parameter」には画像名の「Name」と画像「Sprite」のみがあり、そのリスト、そしてそれを取得するための関数「GetSprite()」があるだけです。
ではUnityに戻ってこちらも同じようにProjectWindowで右クリックしてCreate。「ScriptableObject/BackgroundData」から新しくデータを作成して「BackgroundData01」という名前にします。
作成したデータに「教室」と「夜の教室」というNameのデータを作成して、下記のようにSpriteの欄に画像をドラッグ&ドロップします。
(画像は他のでも構いませんが、「Sprite」である必要がありますので、インポートした画像は「Sprite」にしておきましょう。)
背景変更処理の作成
では「TalkWindow.cs」に背景変更処理を作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
・・・ public class TalkWindow : MonoBehaviour { ・・・ // 背景データ. [SerializeField] BackgroundData bgData = null; ・・・ // 背景イメージ. [SerializeField] Image bgImage = null; // 背景トランジション. [SerializeField] UITransition bgTransition = null; ・・・ // ----------------------------------------------------------------- // 会話の開始. // ----------------------------------------------------------------- public async UniTask<List<int>> TalkStart( List<StoryData> talkList, float wordInterval = 0.2f ) { currentLeft = ""; currentCenter = ""; currentRight = ""; List<int> responseList = new List<int>(); foreach( var talk in talkList ) { if( string.IsNullOrEmpty( talk.Place ) == false ) { await SetBg( talk.Place, false ); } ・・・ } return responseList; } ・・・ // ----------------------------------------------------------------- // 背景の設定. // ----------------------------------------------------------------- public async UniTask SetBg( string place, bool isImmediate ) { var sp = bgData.GetSprite( place ); bgTransition.gameObject.SetActive( true ); var currentBg = bgImage.sprite.name; if( currentBg == sp.name ) { Debug.Log( "同じ背景なので変更をスキップします。" ); return; } if( isImmediate == false ) { await bgTransition.TransitionOutWait(); bgImage.sprite = sp; await bgTransition.TransitionInWait(); } else { bgImage.sprite = sp; } } } |
追加した内容について確認していきましょう。まずは変数の追加です。
追加変数は全て「SerializeField」になっているのでUnityエディタから後でセットします。
先ほど作成した「BackgroundData」型で「bgData」、「Image」型で「bgImage」、「UITransition」型で「bgTransition」を宣言します。
「TalkStart()」関数内で新しく作成する関数を実行します。まずはその追加する関数「SetBg()」をみていきます。
「public async UniTask」で非同期処理の待機ができるようにして「public」で外部から呼び出せるように宣言します。
関数の第1引数は「string place」で背景の名前を受け取ります。第2引数は「bool isImmediate」で遷移処理を入れるか、即背景を変更するかのフラグになります。
では関数の中身を見ていきましょう。
「var sp = bgData.GetSprite( place );」では背景データの変数に引数の名前を入れて対応するスプライト画像を取得しています。この関数は先ほどBackgroundData.csで作成したものですね。
次に「bgTransition.gameObject.SetActive( true );」でとりあえずゲームオブジェクトを表示しておきます。
その下「var currentBg = bgImage.sprite.name;」では「bgImage」つまり背景のイメージの「.sprite」で現在設定されている画像を取得し、その「name」つまり名前を取得します。
その値を使用して「if( currentBg == sp.name )」という条件は、取得した現在の画像の名前と「sp.name」つまり設定する画像の名前が同じ場合に「true」となります。
ここで設定しようとしている画像と現在の画像が同じ場合に、括弧内の処理でログを出して「return;」で処理を中止しています。
そして「if( isImmediate == false )」は遷移するフラグが「false」の場合です。これはフェードして変更するか即変更するかという意味です。
フェードする場合は「await bgTransition.TransitionOutWait();」で背景画像を一旦消す遷移を行いそれを待ちます。
次に「bgImage.sprite = sp; 」で画像を変更。
そして最後に「await bgTransition.TransitionInWait();」で再度表示する遷移を行います。
「else」のときは「bgImage.sprite = sp;」でただ画像を変更するだけです。
では、この関数を実行する部分を見ていきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public async UniTask<List<int>> TalkStart( List<StoryData> talkList, float wordInterval = 0.2f ) { currentLeft = ""; currentCenter = ""; currentRight = ""; List<int> responseList = new List<int>(); foreach( var talk in talkList ) { if( string.IsNullOrEmpty( talk.Place ) == false ) { await SetBg( talk.Place, false ); } // 選択肢の場合. ・・・ } |
追加部分あたりまで抜き出してみます。
追加部分は「foreach」の中の最初「if( string.IsNullOrEmpty( talk.Place ) == false ) 」部分です。
if文の条件は
を使用して「talk.Place」の値がある場合です。
変更しない場合は空白「””」がくるのでその時は処理を行わないようにします。
処理は「await SetBg( talk.Place, false );」で先ほどの背景設定を行い、それを「await」で待機します。
Unityエディターのインスペクター設定
ではUnityに戻って必要な設定をします。
まずは「TalkWinow」の子にある背景の画像「Bg」に「UITransition」を付与しておきましょう。
Fadeは有効にして、Scaleのチェックは外しておきましょう。「Duration」は「1」でOKです。
次に「TalkWindow.cs」で作成した変数「BgData」、「BgImage」、「BgTransition」に適切なゲームオブジェクトを当てはめていきます。
「BgData」には作成したデータ「BackgroundData01」を、「BgImage」と「BgTransition」にはInspectorから「Bg」を当てはめます。
これで設定は完了です。
背景画像が変更されるかどうかテスト再生
では再生して確認してみましょう。現在は「TalkStart()」の「Start()」関数内でテスト実行しているのでまずはそのまま再生してみます。
開始時には最初に設定している背景から会話開始時に変更され、また会話途中でさらに背景が変更されています。
途中の変更は想定通りですが、シーン移動直後の遷移としては会話開始時の背景が設定されている状態で始まるようにしておく方が自然ですね。
またキャラクター画像の変化と背景変化が重なると一度不自然に消えてから出てきてしまいます。
このキャラクターに関してはInspectorで消しておくというのも解決策の一つですが、最後にこの辺りも含めて調整しておきましょう。
GameViewで会話の実行
まずは「TalkWindow.cs」の「Start()」関数にあるテスト処理を削除(コメントアウト)しておきましょう。
そしてここで「Awake()」にも初期処理を追加します。 また、GameViewクラスからTalkWindowの会話内容を参照するのでpublicにしておきます(外部から読み取れる変数であることがわかりやすくなるようにtalksの1文字目を大文字に変更しました)。
まとめと次回に向けて
今回はノベルゲームの会話シーン中に背景を変化させる処理を実装しました。また、非同期処理の途中キャンセル処理の実装を行い、UniTaskのエラーを解消しました。
次回は会話の内容をグーグルスプレッドシートを使い外部から読み込んで使用できるようにしていきます。
次回の記事 :
コメント