Unityでゲームのクエストを管理する機能とページUIを作成する

記事内に広告が含まれています。

最近のゲームではクエストと呼ばれる小さなイベントがありそれをこなしていくという機能が多くなりましたね。

ゲームをコンプリートしようという気持ちが強い人は全クエストをこなしたくなるものです。

(^_^)v

そこで今回はUnityでクエスト管理をする機能を作成してみようと思います。

クエストはステータス画面を開いた時に表示されるようにし、

クエスト画面ではクエストが終了したもの、してないものが一発でわかるようにしたり、タイトルやその内容を表示するようにします。

全クエストが100個あった場合等は全部のクエストをクエスト画面に表示すると大変なので数を決めて表示し、前のページ、次のページに遷移出来るようにボタンを配置します。

非常にシンプルに作成してはいますが、内容的にはボリュームが多いです。

それぞれの関連性を丁寧に見ていってください(あいかわらず説明は下手です)。

スポンサーリンク

クエストを管理するゲームオブジェクトとUIの作成

まずはクエスト画面を構成するゲームオブジェクトと個々のクエストの内容を表示するUIを作成していきます。

ヒエラルキー上で右クリック→Create Emptyで空オブジェクトを作成し、名前をQuestManagementとします。

その子要素に右クリック→UI→Canvasを選択し名前をQuestUIとします。

その子要素にUI→Panelを選択し名前をBackgroundとします。

Backgroundの子要素にはUI→Panelを選択し名前をQuest0とします。

Quest0の子要素にUI→Panelを2つ作り、名前をTitlePanel、InformationPanelとします。

TitlePanelの子要素にUI→Toggle、InformationPanelの子要素にUI→Textを作ります。

Toggleを選択しトグルの設定を変更します。

トグルの設定を変えて変更出来ないようにする

↑のようにInteractableのチェックを外し、TransitionをNoneにします。

これで手動でチェックボックスを操作する事が出来なくなります。

Quest0を選択した状態でCtrl+Dでコピーを4つ作成し、最後の番号を増やした名前にします。

最後にページ移動ボタン領域を作成します。

Backgroundの子要素にUI→Panelを選択し名前をButtonPanelとします。

その子要素にUI→Buttonを2つ作成し名前をPrevとNextにします。

PrevとNextの子要素にはTextがあるので表示されるテキストをPrevとNextに変更しておきます。

クエスト関連ヒエラルキー

↑が作成したクエスト関連のヒエラルキーになります。

Quest1~Quest4まではQuest0をコピーして名前の最後の数字を変えただけで同じです。

これでクエスト関連のゲームオブジェクトは出来ました。

BackgroundゲームオブジェクトのインスペクタでAdd Component→Layout→Vertical Layout Groupを設定します。

これでQuest0~Quest4、ButtonPanelのパネルが縦に並ぶようになります。

Vertical Layout Groupを追加し子要素を縦に並べる

↑のようにコンポーネントを追加しました。

最終的に出来たクエストの確認画面は

クエスト画面

↑のようになっています。Questの子要素のLabelのテキストで初期タイトル、Informationのテキストで初期内容を設定出来ます(後でスクリプトで操作するので特に意味はありませんが・・・)。

クエスト情報を保存するQuestクラスを作成する

クエストはそれぞれ情報を持っています。

名前や内容、どうすればクリア出来るか?といった情報です。

これらはクエスト用のクラスを作成しそこに情報を保持出来るようにし、クエストを管理するスクリプトからアクセスして個別のクエスト情報を得られるようにしましょう。

今回はクエストの名前と内容を保持出来るようにします。

Questスクリプトをクラスの形で作成します。

Questクラスは単純にインスタンス化した時にタイトルと内容を保持し、それを返すメソッドが定義されているだけです。

Questクラスはobjectクラスを継承して作成しておきます。

このQuestクラスはゲームオブジェクトに取り付けて使用するものではなく他のスクリプトからこのクラスのインスタンスを生成し使用するものです。

クエストを管理するQuestManagementスクリプトを作成する

個々のクエストクラスは出来ましたが、そのクエストクラスからインスタンスを生成し全クエストを管理するようなスクリプトが必要です。

その為QuestManagementゲームオブジェクトに新しくQuestManagementスクリプトを作成し取りつけます。

クエストはこのQuestManagementスクリプトで全て生成します。

クエストが完了しているかどうかもこのスクリプトで管理する為、クエスト数分のbool型の配列を用意しています。

今回はそれぞれのクエストを細かく作るのが大変なのでfor文を使ってクエストクラスを大量生産してます・・・(^_^;)

今回のクエスト画面はQキーを押したら開き、再度押したら閉じるという単純なものにしました。

OnEnableメソッドはこのスクリプトが設定されているゲームオブジェクトがアクティブになった時に呼ばれるので、クエスト画面が開いた時に実行されます。

クエスト画面が開いた時は常に最初のページを表示させる為、ここでnowPageを0に初期化しています。

実際にQuest0~Quest4にそれぞれのクエストの情報を入れているのはShowメソッドになります。

引数で指定している数値は何ページ目を開くかの数字です。

スクリプトでは0を渡しているのでクエストの最初のページが開きます。

QuestManagementで全クエストのリストを保持しているので、それに関する値を得られるようにゲッターを用意しています。

例えばクエストの0番目が終了しているかどうかはIsQuestFlag(0)と呼び出すわけですね。

クエストのUIを見て頂くとわかりますが、1度に表示するクエストは5個です。

そこでクエスト画面を開いた時は最初の5個を表示し、Nextボタンを押したら次の5個を表示、というようにしなければいけません。

Showメソッドでは1ページに表示するクエストの個数を表すnum数分繰り返し、クエストの情報をテキストに表示しています。

このnumに設定する数値は作成したクエスト個別のUIの数と一致させます。

このスクリプトのゲームオブジェクトの子要素の数からButtonPanelの分を引いて表示するクエスト数とします。

今回の場合はQuest0~Quest4の5つを作成したのでnumに5が入ります。

Showメソッドを細かく見てみる

Showメソッドを細かく見てみましょう。

引数として受け取るのは何ページ目か?という情報です。

表示するクエスト情報分のTransform配列を確保します。

pageNum(ページ情報)にnum(1ページで表示するクエストの個数)をかけ、i番目を足すと全クエストからの番号を得られます。

そのクエスト番号を使ってクエストのタイトルとクエストの内容情報を取得し一時変数に入れます。

QuestManagementスクリプトで管理している『クエストが終了しているかどうか?』のフラグを取得し、ToggleのisOnにその値を入れています。

こうすることでクエストが終了しているものはタイトル横のチェックボックスにチェックが入ります。

それぞれの子要素からテキストUIコンポーネントを取得し、そこにさきほど取得した情報を表示します。

1度に表示するクエストは5個ですが全クエストが3しかなかった場合等に残りの2つにも何らかの情報を表示しなければいけません。

その為にクエストの番号と全クエストの数とを比較しクエスト番号が全クエスト数を超えた場合は空文字等を表示するようにしています。

NextPageとPrevPageメソッドはNextボタンとPrevボタンをそれぞれ押した時に実行するメソッドです。

次のページや前のページに表示するクエストがない場合は表示しないように制限を加えて表示するようにしています。

クエスト関連の設定を行う

クエスト関連のスクリプトが出来たのでそれぞれ設定していきましょう。

まずはQuestManagementゲームオブジェクトに設定したQuestManagementスクリプトです。

QuestManagementスクリプトの設定

↑のように全クエスト数を50に設定します。

次にPrevとNextボタンのOn Click()に設定をします。

PrevとNextボタンを押した時に実行するメソッド

↑のようにPrevボタンのOn Click()のゲームオブジェクトにQuestManagementゲームオブジェクトをドラッグ&ドロップし、実行するメソッドにQuestManagementスクリプトのPrevPageメソッドを指定します。

Nextボタンも同じように設定し実行するメソッドはNextPageメソッドにします。

クエスト画面は最初表示されていると困るのでQuestUIゲームオブジェクトのインスペクタのチェックを外しておきます。

クエストが完了するサンプルの作成

クエスト画面の実装は出来ましたが、クエストが完了した時にどうなるのかがわかりません。

そこでそこに行くと設定したクエストが完了する領域を作成します。

クエスト完了領域を3つ作成

↑のようにヒエラルキー上で右クリック→3D Object→Cubeを3つ作成しそれぞれの名前の後にクエストの番号を付けておきます。

この番号は特に使うわけでなくわかりやすいかなと思って付けただけです(スクリプトで使う番号+1になっています)。

Completeスクリプトを作成し取りつける

コライダのIs Triggerにチェックを入れ物理的に当たらないようにします。

CubeそれぞれにはCompleteQuestスクリプトを作成し取りつけ、QuestManagementスクリプトと自身のクエスト番号をインスペクタで設定します。

↑のように侵入してきたのがPlayerタグを持っており、かつこのクエストが完了していない場合はQuestManagementスクリプトのSetQuestFlagメソッドを使ってクエストを完了させます。

Cube3はクエスト2を完了させる領域として使用するので、インスペクタは

Cube3領域のインスペクタ

↑のようにCompleteQuestのNumに2を設定します。

クエスト完了領域の実際の画面

実際のクエスト完了をさせる領域は↑のようになりました。

クエスト機能を確認する

これでクエスト機能が全て出来ました!

実際にキャラクターを動かしクエストを完了させる領域を周ってクエストを完了した後にクエスト画面を開いて確認してみます。

まずはQキーを押してクエスト画面を開きクエスト一覧が見れる事を確認し、その後クエスト1が完了するエリアに侵入しクエスト画面を開きます。

クエスト1に相当する最初のクエストのチェックが入りました。

次にクエスト10の領域に入りクエスト10にチェックが入っているかどうかを確認し、最後にクエスト2も確認してます。

今回の記事はクエストの管理機能を作ったんですが、それとは別にページ送りのUIも作成出来ましたね。

あ・・・最後に気付いたんですが、クエストUIに表示するものがない時はUI自体を非表示にしてしまえばいいかもしれませんね。

例えばQuest3とQuest4に表示するクエストがなければQuest3とQuest4を非表示にするとか。

ふむ・・・・・(-_-)。

クエストを一覧表示しスクロールして見れるようにする

ここまででクエスト機能ではクエストは5個毎にページを分けて見るようにしています。

そこでUIとスクリプトを少し改造して全部のクエスト一覧をスクロールして見れるようにしてみます。

ヒエラルキー上で右クリックからCreate Emptyを選択し、名前をQuestManagement2とします。

既に作っているQuestManagementの子要素のQuestUIを選択した状態でCtrl+Dキーを押して複製し、それをドラッグしてQuestManagement2の子要素に移動させます。

QuestManagementはインスペクタの名前の横のチェックを外し非アクティブにしておきます。

QuestUIの子要素のBackgroundのVertical Layout Groupを削除し、BackgroundのQuest0以外の全ての子要素を削除します。

Backgroundを選択した状態で右クリックからUI→Scroll Viewを選択します。

Scroll Viewと子要素のViewportのAnchor Presetsで横をstretch、縦をstretchとします。

Scroll Viewの子要素のContentを選択し、Add ComponentからLayout→Vertical Layout Groupを選択し取り付けます。

クエストUIのスクロールビューのContentにVertical Layout Groupを取り付ける

Anchor Presetsで横はstretchで縦はtopにし、Heightを2800にします(個々のクエストの高さとクエスト数によって変えてください)。

Vertical Layout GroupのLeft、Right、Top、Spacingを5にし、Control Child SizeのWidthにチェックを入れ子要素の個々のクエストの幅をコントロールします。

Child Force ExpandのWidthにチェックを入れ空き要素がある場合は強制で幅を広げます。

ここまでのQuestManagement2の階層は

QuestManagement2の階層

上のようになります。

Quest0を選択し、名前をQuestPrefabとします。

QuestPrefabをContentの子要素に移動させます。

QuestPrefabのAnchor Presetsで横をleft、縦をtopにし、Heightを50にします。

QuestPrefabのインスペクタ

ここまで出来たらQuestPrefabをAssetsエリア内にドラッグ&ドロップしてプレハブにします。

ヒエラルキーのQuestPrefabは削除します。

次にQuestManagementスクリプトをコピーしQuestManagement2スクリプトを作成しQuestManagement2に取り付けます。

Startメソッドでは先ほど作成したQuestPrefabをクエストの数だけインスタンス化しデータを設定します。

上はクエストが完了したかどうかを保持しているquestIsDoneのクエスト数分の初期値を設定しリストにしています。

Enumerable.Repeatの第1引数が設定する値で、第2引数が個数です。

QuestPrefabは1個のクエスト分のUIでそれをインスタンス化したものをquestUIInstanceListに保持します。

実際のクエストのデータを保持するのはquestListです。

クエスト画面を開いた時にUpdateQuestDataメソッドを呼び出し、クエストが完了しているかどうかのデータを更新します。

QuestManagement2のインスペクタのQuestManagement2スクリプトのQuestPrefabに先ほど作ったQuestPrefabを設定します。

最後にサンプルで作ったCubeに設定したCompleteQuestスクリプトでQuestManagementの部分をQuestManagement2に変更し、インスペクタで設定をし直します。

これで改造は完了です。

QuestUIのインスペクタで名前の横のチェックを外し最初は表示しないようにします。

実際に試してみると、

上のようになります。

タイトルとURLをコピーしました