ユニットに指示を出すー実装【UnityでRTSを作る 14】
今回は前回の「仕様の決定」に続いて、その実装を行います。
mackysoft.hatenablog.com
HPBarを改良
こちらの記事で紹介したHPBarを改良して、
ユニットが選択されているかどうかを可視化します。
mackysoft.hatenablog.com
今回からはHPBarはHP以外の情報も扱うようになるのでStatusGUIに名称変更します。
CKWBehaviour.csに変更を加えます。
protected HPBar hpBar = null;
から
protected StatusGUI status = null;
に名前を変更します。
レイアウトに変更を加える
HPBarに矢印を付け加えました。
この矢印の色を変化させて「無所属・味方・敵・選択中の味方」を判別します。
StatusGUI.cs
StatusGUIを制御するStatusGUI.csを用意します。
HPBar.csの名前を変更したものに、いろいろ手を加えました。
StatusGUI.cs
using System; using UnityEngine; using UnityEngine.UI; [RequireComponent(typeof(UIFollowTarget))] public class StatusGUI : MonoBehaviour { #region Variables private static StatusGUI _Prefab = null; private static Canvas _Canvas = null; [Header("References")] public Image hpBar; public Image arrow; [Header("Color")] public bool colorChange = true; public Color safetyColor = Color.blue; public Color warningColor = Color.yellow; public Color dangerColor = Color.red; private RectTransform hpBarTr; private UIFollowTarget uft; #endregion #region Properties public static StatusGUI Prefab { get { return _Prefab ? _Prefab : (_Prefab = Resources.Load<StatusGUI>("Prefabs/UI/StatusGUI")); } } public static Canvas Canvas { get { return _Canvas ? _Canvas : (_Canvas = FindObjectOfType<Canvas>()); } set { _Canvas = value; } } public CKWBehaviour Behaviour { get; private set; } #endregion public static StatusGUI Instantiate (CKWBehaviour behaviour) { var ins = Instantiate(Prefab,Canvas.transform); ins.Initialize(behaviour); return ins; } private void Awake () { hpBarTr = hpBar.GetComponent<RectTransform>(); uft = GetComponent<UIFollowTarget>(); } public void Initialize (CKWBehaviour behaviour) { if (Behaviour) Disable(); Behaviour = behaviour; uft.target = Behaviour.Tr; Behaviour.Health.onValueChanged.AddListener(OnHealthValueChanged); UpdateArrowColor(); gameObject.SetActive(true); } public void Disable () { if (!Behaviour) throw new NullReferenceException(); Behaviour.Health.onValueChanged.RemoveListener(OnHealthValueChanged); Behaviour = null; gameObject.SetActive(false); } public void UpdateArrowColor () { if (!Behaviour) throw new NullReferenceException(); switch (Behaviour.Team) { case Team.Independent: arrow.color = Color.white; break; case Team.Ally: arrow.color = Color.blue; break; case Team.Enemy: arrow.color = Color.red; break; } } private void OnHealthValueChanged (Health health) { float p = (float)health.Value / (float)health.Max; hpBarTr.localScale = new Vector3(p,1,1); if (colorChange) { if (p > 0.5f) hpBar.color = safetyColor; else if (p > 0.25f) hpBar.color = warningColor; else hpBar.color = dangerColor; } } }
名前 | 説明 |
---|---|
arrow | 矢印UIの参照。 |
UpdateArrowColor | 矢印の色を更新します。 |
インスペクターではこのように設定します。
ユニットを選択
ここからユニットへの指示を実装します。
準備
まず最初にプレイヤーに笛の当たり判定を用意します。
(ピクミンを参考にしているので「笛」です)
この笛の当たり判定に当たった味方が選択状態になります。
コライダーのisTriggerにはチェックを入れます。
本当はパーティクルを使って範囲を表現したいのですが、
今はめんどくさいのでSphereメッシュで済ませます。
選択処理
NPCに選択・選択解除を実装しました。
NPC.cs(重要部分を抜粋)
private Player player; public void Select (Player player) { this.player = player; player.selectingList.Add(this); status.arrow.color = Color.green; } public void Deselect () { player.selectingList.Remove(this); status.UpdateArrowColor(); player = null; }
名前 | 説明 |
---|---|
player | 自身を選択しているPlayerの参照。 |
Select | 指定したPlayerで自身を選択する。 StatusGUIの矢印を緑色にする。 |
Deselect | 自身の選択を外す。 |
笛の制御
笛の大きさの制御や当たったときの処理を実装します。
Player.cs(重要部分を抜粋)
public class Player : CubeKun { public float whistleRange = 1; public List<NPC> selectingList = new List<NPC>(); private Transform whistle; public bool IsWhistling { get; private set; } protected override void Awake () { whistle = Tr.FindChild("Whistle"); whistle.localScale = Vector3.zero; } protected override void Update () { if (Input.GetMouseButtonDown(0)) { if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),out hit)) { IsWhistling = hit.collider.GetComponentInParent<Player>() == this; } } Mover.canMove = Input.GetMouseButton(0); Mover.canSearch = Mover.canMove; GameManager.Clock.paused = !Mover.canMove; IsWhistling = IsWhistling && Mover.canMove; if (IsWhistling) { whistle.localScale = Vector3.one * whistleRange; } else { whistle.localScale = Vector3.zero; } if (Mover.canMove && Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),out hit)) { Pointer.position = hit.point; Mover.Move(); RotateArm(); } } protected virtual void OnTriggerEnter (Collider other) { if (IsWhistling) { var npc = other.GetComponentInParent<NPC>(); if (npc && GetTeamRelative(npc) == Team.Ally && !selectingList.Contains(npc)) { selectingList.Add(npc); npc.Select(this); } } } }
名前 | 説明 |
---|---|
whistleRange | 笛の当たり判定の大きさ。 |
selectingList | 選択中のNPCのリスト。 |
whistle | 笛の当たり判定の参照。 |
IsWhistling | 笛を鳴らしているかどうか。 |
目標設定
良いアイデアがなかったので今回は
「選択したユニットはプレイヤーと同じ目標を狙い続ける」
という形で仮実装しました。
イメージ
地味ですが選択したユニットの矢印が緑色に変化します。
すごい地味だけどユニットの選択を実装した。 pic.twitter.com/rdT3fFm5hq
— Macky (@macky_soft) 2017年5月15日