using System; using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI; namespace Beyond { public class Compass : MonoBehaviour { [Serializable] class CompassItem { public RectTransform m_Icon; public Vector3 m_location; public Transform m_transform; public TextMeshProUGUI m_distanceTxt; [Tooltip("Is true if location vector represents direction, false for position")] public bool m_locationIsDirection; public float m_range = float.PositiveInfinity; public float m_minDistance = 0f; public NavigationIndicator m_indicator; } public bool m_onlyIndicator = true; public NavigationIndicator m_indicatorPrefab; [Tooltip("Where is north on the game map? (angle from Z axis)")] public float m_northAngle = 0f; List m_CompassItems; public RectTransform m_NIcon; public RectTransform m_SIcon; public RectTransform m_WIcon; public RectTransform m_EIcon; public RectTransform m_NEIcon; public RectTransform m_NWIcon; public RectTransform m_SEIcon; public RectTransform m_SWIcon; public GameObject m_Divider; public RectTransform m_QuestMarkers; public float m_minPos = -600f; public float m_maxPos = 600f; public bool m_keepVisible = true; public GameObject m_root; public GameObject m_testObject; //public Sprite m_defaultMarkerSprite; Vector3 m_NVector; Vector3 m_SVector; Vector3 m_WVector; Vector3 m_EVector; Camera m_camera; // Start is called before the first frame update private static Compass s_instance = null; public static Compass Instance { get { return s_instance; } } private void Awake() { TryInitialize(); } public void TryInitialize() { if (s_instance == null) { s_instance = this; } else { Debug.LogError("Compass intance already exists!"); Destroy(gameObject); } m_CompassItems = new List(); if (m_NIcon == null) Debug.LogError("Compass: 'N' Icon not set"); if (m_SIcon == null) Debug.LogError("Compass: 'S' Icon not set"); if (m_WIcon == null) Debug.LogError("Compass: 'W' Icon not set"); if (m_EIcon == null) Debug.LogError("Compass: 'E' Icon not set"); m_camera = Camera.main; if (m_camera == null) { Debug.LogError("Compass: Camera not found!"); enabled = false; return; } if (m_onlyIndicator) { /* m_NIcon.enabled = false; m_SIcon.enabled = false; m_WIcon.enabled = false; m_EIcon.enabled = false; m_NEIcon.enabled = false; m_NWIcon.enabled = false; m_SEIcon.enabled = false; m_SWIcon.enabled = false; */ //Show(false); return; } //m_NVector = new Vector3(1f, 0f, 0f); m_NVector = new Vector3(0f, 0f, 1f); float angle; for (int i = 0; i < 24; i++) { Quaternion r = Quaternion.AngleAxis(i * -15f, Vector3.up); CompassItem it = new CompassItem(); if (i % 3 > 0) { var go = Instantiate(m_Divider, m_Divider.transform.parent); it.m_Icon = go.GetComponent(); it.m_Icon.position = m_Divider.transform.position; } // it.m_Icon = m_NIcon; angle = (m_northAngle + i * -15f) * Mathf.Deg2Rad; it.m_location = r * m_NVector; it.m_location.x = Mathf.Cos(angle); it.m_location.z = -Mathf.Sin(angle); it.m_locationIsDirection = true; //if (m_) m_CompassItems.Add(it); } m_CompassItems[0].m_Icon = m_NIcon; m_CompassItems[3].m_Icon = m_NWIcon; m_CompassItems[6].m_Icon = m_WIcon; m_CompassItems[9].m_Icon = m_SWIcon; m_CompassItems[12].m_Icon = m_SIcon; m_CompassItems[15].m_Icon = m_SEIcon; m_CompassItems[18].m_Icon = m_EIcon; m_CompassItems[21].m_Icon = m_NEIcon; m_Divider.SetActive(false); } void Start() { if (m_testObject != null) AddQuestMarker(m_testObject.transform, null); if (m_onlyIndicator) { Show(false); } } public void AddQuestMarker(Transform q, Sprite icon, float minDistance = 0f) { CompassItem item = new CompassItem(); if (!m_onlyIndicator) { if (m_QuestMarkers == null) { Debug.LogError("Compass: Quest marker prefab is null"); return; } var qo = GameObject.Instantiate(m_QuestMarkers, m_Divider.transform.parent); if (icon != null) { var img = qo.GetComponent(); img.sprite = icon; } qo.gameObject.SetActive(true); item.m_Icon = qo; item.m_distanceTxt = qo.gameObject.FindComponentDownHierarchy(); } //var ind = GameObject.Instantiate(m_indicatorPrefab, transform); var ind = GameObject.Instantiate(m_indicatorPrefab, transform.parent); ind.SetTargetTransform(q); //if (icon == null) // icon = m_defaultMarkerSprite; item.m_transform = q; item.m_location = q.position; item.m_locationIsDirection = false; item.m_minDistance = minDistance; item.m_indicator = ind; m_CompassItems.Add(item); } public Transform FindClosestIndicator(Transform t) { Transform result = null; float dist = Single.MaxValue; for (int i = 24; i < m_CompassItems.Count; i++) { var d = (m_CompassItems[i].m_transform.position - t.position).magnitude; if (dist > d) { dist = d; result = m_CompassItems[i].m_transform; } } return result; } public void SetQuestMarkerDistance(Transform q, float dist) { var ci = m_CompassItems.Find(quest => quest.m_transform == q); if (ci != null) { ci.m_minDistance = dist; } } public void RemoveQuestMarker(Transform q) { var ci = m_CompassItems.Find(quest => quest.m_transform == q); if (ci != null) { if (ci.m_Icon && ci.m_Icon.gameObject) Destroy(ci.m_Icon.gameObject); if (ci.m_indicator && ci.m_indicator.gameObject) Destroy(ci.m_indicator.gameObject); m_CompassItems.Remove(ci); } } public void Show(bool flag) { if (m_root) m_root.SetActive(flag); else { gameObject.SetActive(false); } } // Update is called once per frame void Update() { if (m_onlyIndicator) return; Vector3 pos = Player.Instance != null ? Player.Instance.transform.position : m_camera.transform.position; foreach (var ci in m_CompassItems) { Vector3 wordPos; float distance = float.PositiveInfinity; if (ci.m_locationIsDirection) wordPos = ci.m_location * m_camera.farClipPlane + pos; else { if (ci.m_transform != null) ci.m_location = ci.m_transform.position; wordPos = ci.m_location; var diff = wordPos - pos; diff.y = 0; distance = diff.magnitude; if (ci.m_distanceTxt != null) { ci.m_distanceTxt.text = distance.ToString("F0")+"m"; } } Vector3 screenPos;// = m_NIcon.position; Vector3 viewPortPos = m_camera.WorldToViewportPoint(wordPos); screenPos = m_camera.WorldToScreenPoint(wordPos); //check conditions to skip/disable if (ci.m_locationIsDirection) { if (screenPos.z < 0) { ci.m_Icon.gameObject.SetActive(false); continue; } } else { if (ci.m_range < distance || distance < ci.m_minDistance) { ci.m_Icon.gameObject.SetActive(false); continue; } } ci.m_Icon.gameObject.SetActive(true); if (!ci.m_locationIsDirection) //is it a point or direction? { //keep oryginal y position /* if (screenPos.z < 0) { screenPos.x *= -1f; } screenPos.y = ci.m_Icon.position.y; screenPos.z = ci.m_Icon.position.z; ci.m_Icon.position = screenPos; var lpos = ci.m_Icon.localPosition; lpos.x = Math.Min(lpos.x, m_maxPos); lpos.x = Math.Max(lpos.x, m_minPos); ci.m_Icon.localPosition = lpos; */ screenPos.y = ci.m_Icon.position.y; screenPos.z = ci.m_Icon.position.z; ci.m_Icon.position = screenPos; var lpos = ci.m_Icon.localPosition; //keep oryginal y position if (viewPortPos.z >= 0) { // screenPos.x *= -1f; lpos.x = Math.Min(lpos.x, m_maxPos); lpos.x = Math.Max(lpos.x, m_minPos); } else { if (lpos.x > 0) { lpos.x = m_minPos; } else { lpos.x = m_maxPos; // lpos.x = m_minPos; } } // lpos.x = Math.Min(lpos.x, m_maxPos); // lpos.x = Math.Max(lpos.x, m_minPos); ci.m_Icon.localPosition = lpos; } else { screenPos.y = ci.m_Icon.position.y; screenPos.z = ci.m_Icon.position.z; ci.m_Icon.position = screenPos; ci.m_Icon.position = screenPos; } } } } };