今回はユニティちゃんが動いていない状態の時に画面の右下にパーティーのHPやMPを表示したパネルを開き、移動キーやボタンを押した時にそのパネルを閉じるようにします。
前回はコマンド画面等でのボタン選択の速度を上げる設定をしました。
ユニティちゃんのRPGを作ってみようの他の記事は
から見ることが出来ます。
パーティーのHPやMPを表示するUIの作成
まずはパーティーのHPやMPを表示するUIを作成していきます。
Villageシーンのヒエラルキーで右クリックからUI→Canvasを選択し、名前をCharacterStatusとします。
CharacterStatusのインスペクタのCanvas Scalerの設定を変更します。
UI Scale ModeをScale With Screen Sizeにして画面サイズに応じてUIのScaleを変更します。
Referrece Resolutionには基本となるスクリーンサイズを指定します。
Screen Match ModeはExpandにし、画面サイズに応じて広がるようにします。
CharacterStatusを選択した状態で右クリックからUI→Panelを選択し、名前をCharacterStatusPanelとします。
シーンビューでCharacterStatusPanelのサイズを調整し、右下に表示されるようにします。
CharacterStatusPanelを選択し、インスペクタのAdd ComponentからLayout→Vertical Layout Groupを選択し取り付け、以下のように設定します。
Imageのチェックを外しておきます。
Control Child SizeのWidthにチェックを入れ、横幅のサイズをこのパネルの幅に応じてコントロールします。
Child Force ExpandのWidthにチェックを入れ、パネルのサイズに応じて横幅が広がるようにします。
CharacterStatusPanelを選択した状態で右クリックからUI→Panelを選択し、名前をCharacterPanelとします。
CharacterPanelのAnchor Presetsをleft topにし、Heightを50にします。
またインスペクタのAdd ComponentからLayout→Horizontal Layout Groupを選択し取り付けます。
Child AlignmentをUpper Centerにします。
Child Force ExpandのWidthとHeightにチェックを入れます。
またImageは使わないのでチェックを外します。
これでCharacterPanelの子要素が横一列に整列します。
CharacterPanelを選択した状態で右クリックからUI→Textを3回選択し、名前をCharacterName、HPTitle、MPTitleとします。
それぞれのインスペクタのAlignmentで真ん中中央にし、それぞれのRect Transformで
CharacterNameのWidthは250、Heightは50
HPTitle、MPTitleのWidthとHeightは50
とします。
CharacterNameのTextにはユニティちゃん、HPTitleのTextにはHP、MPTitleのTextにはMPという文字列を入力しておきます。
それぞれのTextのFont Sizeは25、Colorは白色にしました。
CharacterPanelを選択した状態で右クリックからUI→Sliderを2回選択し、名前をHPSlider、MPSliderとします。
HPSliderとMPSliderの子要素のHandle Slide Areaは使わないので削除します。
HPSliderとMPSlider子要素のFill AreaのRect Transformを変更します。
これはスライダーの値の最小値と最大値になった時にメーターを完全に0にしたり、完全に満たす為です。
またHPSlider、MPSliderの子要素のFill Area→FillのインスペクタのRect Transformも同じように変更し、ImageのColorを青色にします。
それぞれRect TransformのWidthは100、Heightは50とします。
HPSliderとMPSliderの子要素にTextを作成し、それぞれの名前をHPText、MPTextとします。
Anchor Presetsでstretch stretchにします。
HPText、MPTextのAlignmentは左寄せの真ん中表示にします。
HPText、MPTextのFont Sizeも25、Colorは白色にしました。
ステータスの順番をゲームオブジェクトをドラッグして並べ替えて、CharacterPanelの階層の順番を
CharacterName→HPTitle→HPSlider→MPTitle→MPSlider
の順番にします。
CharacterPanelの階層は以下のようになります。
キャラクターのHPを数値とスライダーで表示し一目見てどの程度HPやMPが残っているかがわかるようにします。
CharacterPanelの子要素の幅や高さなどはCharacterStatusPanelのサイズによって変わってきますので調整してください。
ここまで出来たらCharacterPanelをAssets/RPG/Prefabs/UI/Commmandフォルダにドラッグ&ドロップしてプレハブにし、ヒエラルキー上のCharacterPanelは削除します。
CharacterPanelが一人のキャラクターの名前、HP、MPを表示しますので、スクリプトからCharacterPanelプレハブをインスタンス化しパーティー全員のステータスを表示します。
これでUIが出来ました。
パーティーステータスを表示するスクリプトの作成
次にパーティーステータスを表示する為のスクリプトを作成していきます。
Assets/RPG/Scriptsフォルダ内に新しくIdleCommandScriptという名前のスクリプトを作成し、CharacterStatusゲームオブジェクトに取り付けます。
スクリプトが少し長いので、分けて説明します。
フィールド宣言部とAwakeメソッド、Startメソッド
まずはフィールド宣言部とAwakeメソッド、Startメソッドを作成します。
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 | using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class IdleCommandScript : MonoBehaviour { // パーティーステータス [SerializeField] private PartyStatus partyStatus = null; // どれだけ操作をしていなければ表示するか [SerializeField] private float idleTime = 5f; // どれだけ操作をしていないか private float elapsedTime; // 現在キャラクターステータスパネルを開いているかどうか private bool isOpenCharacterStatusPanel; // キャラクター毎のステータスパネルプレハブ [SerializeField] private GameObject characterPanelPrefab = null; // キャラクターステータスパネル private GameObject characterStatusPanel; // SceneManager private LoadSceneManager sceneManager = null; // UnityChanScript [SerializeField] private UnityChanScript unityChanScript = null; private void Awake() { characterStatusPanel = transform.Find("CharacterStatusPanel").gameObject; } private void Start() { sceneManager = GameObject.Find("SceneManager").GetComponent<LoadSceneManager>(); } } |
partyStatusにはAssets/RPG/Data/StatusのPartyStatusアセットファイルをインスペクタで設定します。
idleTimeはどれだけユニティちゃんを動かしたりボタンを押したりしていなければCharacterStatusPanelを表示するかの秒数を設定します。
elapsedTimeはキーやボタンを押さなくなってからどれだけ時間が経ったかを入れます。
isOpenCharacterStatusPanelは現在CharacterStatusPanelを開いているかどうかのフラグです。
characterPanelPrefabには先ほどプレハブにしたCharacterPanelをインスペクタで設定します。
characterStatusPanelはCharacterStatusPanelを取得し設定します。
sceneManagerにはシーン切り替えを行っているLoadSceneManagerを取得し設定します。
unityChanScriptはインスペクタでそれぞれのシーンのUnityChanをドラッグ&ドロップしUnityChanScriptを設定します。
Awakeメソッドでは子要素のCharacterStatusPanelゲームオブジェクトを取得しています。
Startメソッドではヒエラルキー全体からSceneManagerゲームオブジェクトを探し、設定されているLoadSceneManagerスクリプトを取得しています。
Updateメソッド
Updateメソッドで実際のパーティーのステータスを表示する処理をしています。
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 | // Update is called once per frame void Update() { // シーン遷移途中とユニティちゃんの状態によっては表示しない if (sceneManager.IsTransition() || unityChanScript.GetState() == UnityChanScript.State.Talk || unityChanScript.GetState() == UnityChanScript.State.Command ) { elapsedTime = 0f; characterStatusPanel.SetActive(false); return; } // 何らかのキーが押された時 if (Input.anyKeyDown || !Mathf.Approximately(Input.GetAxis("Horizontal"), 0f) || !Mathf.Approximately(Input.GetAxis("Vertical"), 0f) ) { elapsedTime = 0f; // キャラクターステータスパネルの子要素があれば削除する for (int i = characterStatusPanel.transform.childCount - 1; i >= 0; i--) { Destroy(characterStatusPanel.transform.GetChild(i).gameObject); } characterStatusPanel.SetActive(false); isOpenCharacterStatusPanel = false; // キャラクターステータスパネルを開いていない時だけ } else if (!isOpenCharacterStatusPanel) { elapsedTime += Time.deltaTime; // 経過時間が一定時間を越えたらキャラクターステータスパネルを表示 if (elapsedTime >= idleTime) { GameObject characterPanel; // パーティーメンバー分のステータスを作成 foreach (var member in partyStatus.GetAllyStatus()) { characterPanel = Instantiate<GameObject>(characterPanelPrefab, characterStatusPanel.transform); characterPanel.transform.Find("CharacterName").GetComponent<Text>().text = member.GetCharacterName(); characterPanel.transform.Find("HPSlider").GetComponent<Slider>().value = (float)member.GetHp() / member.GetMaxHp(); characterPanel.transform.Find("HPSlider/HPText").GetComponent<Text>().text = member.GetHp().ToString(); characterPanel.transform.Find("MPSlider").GetComponent<Slider>().value = (float)member.GetMp() / member.GetMaxMp(); characterPanel.transform.Find("MPSlider/MPText").GetComponent<Text>().text = member.GetMp().ToString(); } characterStatusPanel.SetActive(true); elapsedTime = 0f; isOpenCharacterStatusPanel = true; } } } |
シーン遷移途中、ユニティちゃんの状態が会話中やコマンド実行中の場合はelapsedTime(何も押さなくなってからの時間)を0にし、CharacterStatusPanelを非表示にし、returnでその後の処理は行いません。
それ以外の時でInput.anyKeyDownで何らかのキーやボタンが押されたかどうか、Mathf.ApproximatelyでInput.GetAxis(“Horizontal”)と0のfloatの比較、Input.GetAxis(“Vertical”)と0のfloatの比較をして移動の入力がほぼ0であるかを比較し、!を付けてその反転、つまり何らかの移動がされている場合はelapsedTimeを0にし、CharacterStatusPanelの子要素のCharacterPanel群を全部削除します。
これは何らかの行動を起こしたのでCharacterStatusPanelを非表示にしたということになります。
else ifで何らかのキーを押していない時でCharacterStatusPanelを開いていない時はelapsedTimeにTime.deltaTimeを足して何もしていない時間の計測を行います。
経過時間がidleTime以上になったらパーティーメンバー分のCharacterPanelプレハブをインスタンス化し、階層を辿ってTextコンポーネントやSliderを取得し、そこにパーティーのステータスデータを設定します。
これらの処理は以前作成したアイテムコマンドの処理と同じ感じなので問題はないと思います。
Sliderの値はデフォルトでは0~1の間で指定することになっているので(SliderのMin ValueとMax Valueで変更することも可能)、HPではmember.GetHp()で得られた値を(float)でfloat型にキャストした後member.GetMaxHP()で割って0~1の間の値にしています。
MPも同じようにして求めています。
CharacterPanelをインスタンス化したらCharacterStatusPanelを表示しています。
CharacterStatusの子要素のCharacterStatusPanelのインスペクタで名前の横のチェックを外し最初はパネルが表示されないようにしておきます。
これで機能が完成しました。
VillageシーンのCharacterStatusを選択した状態でCtrl+Dキーを押して複製し、WorldMapシーンにドラッグ&ドロップして移動し、名前をCharacterStatusに変更します。
WorldMapシーンのCharacterStatusのIdleCommandScriptのunityChanScriptにはWorldMapシーンのUnityChanゲームオブジェクトをドラッグ&ドロップしUnityChanScriptを設定します。
パーティーステータスが表示されるか確認する
機能が完成したのでUnityを実行し、何もキーやボタンを押さない時にパーティーステータスが表示されるかを確認してみましょう。
上のようになりました。
終わりに
簡易的なパーティー全体のステータスを確認出来る機能ですがあると便利ですよね。
この作品はユニティちゃんライセンス条項の元に提供されています