Unityに関連する記事です

 会話ウインドウの表示位置をキャラの上下位置ではなく、Canvas の固定位置に表示する制御処理を実装します。
 
 処理の実装内容が多いので、2回に分けて実装を行います。
今回は NPC キャラに対してウインドウの表示設定を自動的に行う機能を実装し、1つずつウインドウの表示の設定を行う作業をなくし、効率化を図ります。


<実装動画 _堝型会話ウインドウを利用する>
動画ファイルへのリンク


<実装動画◆仝把蠏寝駭奪Εぅ鵐疋Δ鰺用する>
動画ファイルへのリンク


手順29 ー固定型の会話ウインドウと稼働型の会話ウインドウの切り替え制御処理の実装ー
51.GameData スクリプト、NonPlayerCharacter スクリプト、GameManager スクリプトの修正を行い、
   会話ウインドウの設定に合わせて、固定型の会話ウインドウにするか、稼働型の会話ウインドウにするか自動的に分岐制御する処理を追加する



 新しい学習内容は、以下の通りです。

 ・自動化処理による作業の効率化



51.GameData スクリプト、NonPlayerCharacter スクリプト、GameManager スクリプトの修正を行い、会話ウインドウの設定に合わせて、固定型の会話ウインドウにするか、稼働型の会話ウインドウにするか自動的に分岐制御する処理を追加する

1.設計


 前回の手順において、会話ウインドウの作成と、表示する会話ウインドウの切り替え機能を実装しました。

 無事に実装できましたので、この手順では各 NPC キャラごとに1つずつ会話ウインドウの設定を行う方式ではなく、
1つの設定をすべての NPC のキャラに設定することで会話ウインドウの設定を片方に統一する制御処理を実装します。



 NPC の数が増えたり、あるいはシーンが複数あったりとなると、管理を行う対象の NPC の数が膨大になります。
それらを1つずつ会話ウインドウの設定を行っていては作業効率がよくありません。

 ゲームにおいて、会話ウインドウの表示の方法は、稼働型か固定型かを設定すれば、
あとはそのゲームにおいては常にその種類の方法で会話ウインドウを表示するようになると思います。
(ゲームを実行するたびに変えたいような演出があるなら別ですが)

 そのため、ゲームの起動に合わせて、今回のゲームではどちらの種類の会話ウインドウを利用するのかを設定する場所を別に1つ用意しておきます。
そして、この設定をすべての NPC キャラの会話ウインドウの設定に自動的に反映するようにすることによって、個別に設定する作業を無くします。

 こうすることにより、処理を自動化できるとともに、設定漏れを防ぐことにもなりますので、管理・保全という部分から考えても利点が多い設計になります。



 ゲーム内において利用する会話ウインドウの設定を行う場所を新しく作成し、用意するということは、
いずれかのクラスに変数を作成して、それを参照する、という設計になります。

 参照しやすいクラスに情報を用意することが利便性を考えるとベターな選択になりますので、
今回はシングルトンクラスである GameData クラスに新しい変数を用意するようにします。
これは参照のしやすいシングルトンクラスの特徴を生かすためですので、どうしてなのかは復習をしておいてください。

 どのような型で変数を宣言するかですが、単純に bool 型や int 型での作成も可能です。
これは、それぞれの値を読みかえて利用する方式です。例えば、false や 0 のときには稼働型、true や 1 のときには固定型とする、というように
変数の運用にあたって、それをどのように利用していくのかを自分で考えて、それを処理として組み込んでいく方法です。

 ただしこの場合、ぱっと見ただけではどのように利用されているのかがわかりにくく、後々に見直した際にわかりやすくするためコメントなどを用意しておく必要も出てきます。
また、if 文などにもこの変数を利用した条件式を書くようになるため、if(会話ウインドウの変数名 == 1) というような書式となるので、処理の不透明さが目立ちます。

 こういったケースには enum を新しく作成し、それを運用していく方法で処理のロジックを考えていくようにしましょう。

 enum であれば、具体的な名称として列挙子を登録することができるため、例えば、次のような登録が可能になります。

<enum による管理方法>
    public enum TalkWindowType {
        Fixed,   // 固定型
        Movable  // 稼働型
    }
 enum は日本語でも登録できますので、コメントで記述している方を登録しておくことも可能です。
見やすさ、わかりやすさ、読みやすさを考えて設計をしていきます。

 そしてこの enum の TalkWindowType 型の変数を1つ作成します。これが「ゲーム内で利用する会話ウインドウの設定の値」となります。

<enum 用の変数>
    [Header("会話ウインドウの種類を設定")]
    public TalkWindowType useTalkWindowType;

 この変数には TalkWindowType 型に登録してある列挙子の情報が1つだけ代入されていることになりますので、
値を排他的に管理することが可能になります。また列挙子に登録していない情報が代入される心配もありませんので、
この変数の値は常に「稼働型(Movable)」か「固定型(Fixed)」のいずれかのみに限定されるようになります。

 こちらの変数を利用する場合、if 文などの条件式も if (useTalkWindowType == TalkWindowType.Fixed) という書式になるため、
条件の分岐内容が非常に分かりやすくなります。

 こういった運用していく部分も含めて、処理の設計を考えて変数の宣言を行っていくようにしてみましょう。



 今回の実装では、複数のスクリプトの修正が必要になります。
それは「どういった機能を追加したい」のかを考えて、ゴール地点(実装目標)を決めて、
その上で、そのゴール地点に対してのスタート地点を考えていきます。

 スタート地点とゴール地点が確定すれば、あとはそこに至るまでの「道のり」を考えていきます。

<ゴール地点>
 各 NPC の会話ウインドウの設定を固定型か稼働型に自動で設定したい

 このゴール地点に対して、スタート地点を考えます。

<スタート地点>
 ゲーム全体で利用する会話ウインドウの設定を行って、それを反映させたい

 この2つの情報を元に、どのようにすればスタート地点からゴール地点までの「道のり」が作っていくことができるか、
道のりは1つではありませんので、この道中ともいうべきロジックを考えていくことがエンジニアの仕事になります。



 まずは最初に、ゴール地点の処理と、スタート地点の処理を作成することを考えてみましょう。

 ゴール地点では NPC の設定に関連する処理ですので、該当するスクリプトは NonPlayerCharacter スクリプトになります。

 このスクリプト内にスタート地点の情報を反映して、会話ウインドウの設定を切り替えする処理を用意したメソッドを準備することを検討します。
メソッドを準備できれば、あとは呼び出しの命令を受けることによって、会話ウインドウの設定を自動的に切り替えるようにします。
会話ウインドウの設定を切り替える部分には、前回用意してある isFixedTalkWindowUsing 変数を利用しましょう。

 このように制御したい処理をメソッド単位でまとめて、処理を実行できる準備を進めていく手順が重要になります。
そのため、実際の処理の流れと、その処理を実装していく部分とでは順番が前後することが多々あります。

 処理の流れ通りに実装も行いたいのであれば、スタート地点から処理の実装を考えてみましょう。
ただしこれはゴール地点から処理を実装するよりもはるかに難しいので、始めはゴール地点となる処理からさかのぼっていく方が実装はしやすいと思います。



 次に、スタート地点の処理を考えていきます。
ゲーム全体で利用する情報を用意する部分になりますので、こちらは先ほども説明しましたように、GameData クラス内に新しい enum と、その型を利用する変数を用意することを考えます。
この変数を参照することによって、ゲーム全体で利用する会話ウインドウの種類を特定できるようにします。

 この変数の情報は public 修飾子の変数として用意します。そうすることでインスペクターより設定が可能になりますので、
この部分だけを設定すれば、あとは、すべての NPC に同じ会話ウインドウの設定がいきわたるようにイメージをしてください。
変更する場合にもこの部分だけ変更すればよい設計になります。

 enum の作成場所は GameData クラス内でもよいですし、別のスクリプトとして用意しても構いません。
この enum を宣言する変数については GameData クラス内で用意しますが、変数の宣言は public 修飾子ではなくて、SerializeField 属性にしておいて、
プロパティを利用して取得する設計にしてもいいでしょう。



 最後にこのスタート地点とゴール地点とをつなげていく処理を考えていきます。
基本的には、複数のクラスのメソッドの呼び出しを行き来して処理が実行されていくイメージになります。

 今回の場合、NonPlayerCharacter クラスに用意した会話ウインドウの設定を行うメソッドの呼び出しを行う部分がゴール地点です。
まずはここにどのようにすればたどり着けるのかを考えていきます。

 NonPlayerCharacter クラスですが、各 NPC のゲームオブジェクトに1つずつアタッチされているのですが、
これらをまとめて管理を行っているクラスはありません。そのため、ゲームシーン内に存在している NPC を管理している情報がない状態です。

 ここでは宝箱の管理をしたときのことを思い出して復習します。
宝箱も同様で、ゲームシーンには存在しているものの、それを管理していない状態であったため、
まずは、それらを1つの変数としてまとめて、管理できる状態にしました。

 それと同じことを、NonPlayerCharacter クラスについても行うようにしましょう。
管理用の変数を用意する場所は、宝箱と同じく、GameManager クラスにしておきます。
このクラスは、ゲームシーンの管理を行うための役割を持つクラスですので、こういった情報を一手に任せるようにします。

 用意する変数も List 型にして準備するようにし、それを public 修飾子で宣言しておきます。
このようにすることで、宝箱の場合と同じように、インスペクターよりヒエラルキーにある NonPlayerCharacter クラスがアタッチされている
ゲームオブジェクトをドラッグアンドドロップしてアサインし、登録することが出来ます。

 今後、1つずつアサインすることが大変な位に NonPlayerCharacter クラスが増えた場合には、
今回実装する方法を参考にして、「ゲーム開始時に、ヒエラルキーにある NonPlayerCharacter クラスがアタッチされているすべてのゲームオブジェクトを取得して List に代入する」という機能を考えてみましょう。

 List 変数とすることにより、1つの変数内に複数の NonPlayerCharacter クラスの情報をまとめて管理できるようになります。
NonPlayerCharacter クラスの情報があれば、それを利用して NonPlayerCharacter クラスに準備した会話ウインドウの設定を行うメソッドを
各 NonPlayerCharacter クラスに対して実行していくことができる状態になります。

 最後に、無条件で会話ウインドウの設定を変更するわけにはいきませんので、GameData クラスに用意した
会話ウインドウの種類の設定値を確認し、その上で、会話ウインドウの設定が必要なときにだけ、固定型に変更するメソッドを実行するように制御を行います。



 以上のような流れが、今回実装するべき処理の一連の流れになります。
この情報を元に、各スクリプトの修正を行います。念頭に置きつつ、実際に修正する際にはこの設計部分を読み返しながら、
どのように処理を組み立てていくのかをしっかりと把握しながら処理を記述していってください。

 ただ処理を書くだけでは覚えることは出来ません。どのようにして動いているのかをイメージしていくことが大切です。

 なお、設計を読んでイメージが沸いた部分については、教材を見る前に自分で処理を書いてみましょう。
間違っていても問題ありません。挑戦し、確認することが成長につながります。やらないでいると、いつまでも成長できなくなりますので、
常に向上心を持って取り組んでいく姿勢を身につけていきましょう!


2.GameData スクリプトを修正する


 設計においてスタート地点にあたる処理を実装します。
今回は enum の作成はこのクラス内で行っています。

 またこの enum の変数については public 修飾子にて宣言しています。
一度ゲームが動くところまで実装できましたら、プロパティにしてみてもいいでしょう。


GameData.cs

<= クリックすると開きます。


 スクリプトを修正したらセーブします。


3.GameData ゲームオブジェクトの設定を行う


 GameData ゲームオブジェクトのインスペクターを確認し、useTalkWindowType を Fixed(固定型) に変更します。


インスペクター画像



 以上で設定は完了です。


4.NonPlayerCharacter スクリプトを修正する


 GameManager クラスより、GameData クラスの会話ウインドウの設定に合わせて呼び出すためのメソッドを準備します。
このメソッドは固定型の会話ウインドウを利用する際に呼び出してもらうことにより、NonPlayerCharacter クラス内に固定型の会話ウインドウを利用するという設定を行います。

 このメソッド内において、先ほどの手順では個別でチェックを入れて固定型の会話ウインドウを利用するように設定していた isFixedTalkWindowUsing 変数について、
ゲームの実行時に、固定型の会話ウインドウを利用するか否かに応じて、自動的に設定を行うように設計します。

 合わせてUIManager クラスの情報を GameManager クラスよりメソッドの引数として受け取って設定を行うように変更します。
そのため、Start メソッド内で UIManager クラスを取得していた処理は不要になります。


NonPlayerCharacter.cs

 <= クリックすると開きます。


 スクリプトを修正したらセーブを行います。



 すべての NPC 用のゲームオブジェクトのインスペクターを順番に確認します。
isFixedTalkWindowUsing 変数のチェックを外して false の状態にしておいてください。


NPC 用のゲームオブジェクト インスペクター画像


 
 この値が自動的に切り替わる対象の値です。
GameData クラスの会話ウインドウの設定が Fixed(固定型)である場合には true になり、固定型の会話ウインドウの設定を行い、UIManager クラスを通じて固定型の会話ウインドウを制御します。

GameData クラスの会話ウインドウの設定が Movable(稼働型)である場合には false になり、今までと同じようにキャラの上下に稼働型の会話ウインドウを制御します。


5.GameManager スクリプトを修正し、GameData クラスの会話ウインドウの種類の設定に応じて、各 NPC の会話ウインドウの表示設定を行う処理を追加する


 変数としては、NonPlayerCharacter クラスを管理するための List の変数を用意します。
public 修飾子で宣言したり、SerializeField 属性にて宣言することで、宝箱の List と同じようにインスペクターより
ヒエラルキーにある NPC ゲームオブジェクトをドラッグアンドドロップしてアサインできるようになります。

 ゲームの開始に合わせてどのような種類の会話ウインドウかを設定確認を行いたいため、
Start メソッドを利用して GameData クラスに設定されている今回のゲームで利用する会話ウインドウの種類を確認し、
固定型を利用する場合にだけ、NonPlayerCharacter クラスの会話ウインドウを設定するメソッドを実行するようにします。

 この処理を List に登録されている NonPlayerCharacter クラスの数だけ繰り返すようにしておくことで
すべての NPC キャラの会話ウインドウの設定を自動的に行う処理を実装しています。

 宝箱の確認処理と同じように yield return を利用して StartCoroutine にてコルーチンメソッドを実行することにより、
NonPlayerCharacter クラスの会話ウインドウの制御処理をすべて終了するまで、GameManager クラス内の処理が一時中断するようになっています。

 そのため、設定が終わっていないのにゲームが始まってしまう、という状態にならないようにも制御を行っています。
想定される挙動に合わせて、処理の制御をきちんと行っておくことにより、不具合の発生を未然に防ぐための設計になります。


GameManager.cs

<= クリックすると開きます。


 スクリプトを作成したらセーブを行います。


6.GameManager ゲームオブジェクトの設定を行う


 GameManager ゲームオブジェクトのインスペクターを確認し、修正した GameManager スクリプトの設定を行います。

 ヒエラルキー上にある UIManager ゲームオブジェクトを uiManager 変数にドラッグアンドドロップしてアサインします。
自動的に UIManager スクリプトの情報が変数に代入されます。

 nonPlayerCharactersList 変数の Size を現在ヒエラルキーに用意してある NPC のゲームオブジェクトの数に設定します。
その後、Element にそれらの NPC のゲームオブジェクトをヒエラルキーより、ドラッグアンドドロップしてアサインしてください。
ここに登録されている NPC ゲームオブジェクトに対して、GameData クラスの設定を元に、会話ウインドウを表示設定の制御を行えるようになります。


インスペクター画像



 以上で設定は完了です。


7.ゲームを実行して動作を確認する


 実装した機能が正常に動作しているかどうか、確認を行います。


<実装動画 _堝型会話ウインドウを利用する>
動画ファイルへのリンク


<実装動画◆仝把蠏寝駭奪Εぅ鵐疋Δ鰺用する>
動画ファイルへのリンク


 以上でこの手順は終了です。

 次は 手順30 ー複数ページのメッセージ表示とページ送り機能機能の実装ー です。

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu



プログラムの基礎学習

コード練習

技術/知識(実装例)

2Dおはじきゲーム(発展編)

2D強制横スクロールアクション(発展編)

3Dダイビングアクション(発展編)

2Dタップシューティング(拡張編)

レースゲーム(抜粋)

2D放置ゲーム(発展編)

3D脱出ゲーム(抜粋)

2Dリアルタイムストラテジー

2Dトップビューアドベンチャー(宴アセット使用)

3Dタップアクション(NavMeshAgent 使用)

2Dトップビューアクション(カエルの為に〜、ボコスカウォーズ風)

3Dトップビューアクション(白猫風)

VideoPlayer イベント連動の実装例

VideoPlayer リスト内からムービー再生の実装例(発展)

AR 画像付きオブジェクト生成の実装例

AR リスト内から生成の実装例(発展)

private



このサイト内の作品はユニティちゃんライセンス条項の元に提供されています。

管理人/副管理人のみ編集できます