Files
beyond/Assets/Scripts/UI/Compass.cs
2024-11-20 15:21:28 +01:00

369 lines
12 KiB
C#

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<CompassItem> 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<CompassItem>();
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<RectTransform>();
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<RectTransform>(m_QuestMarkers, m_Divider.transform.parent);
if (icon != null)
{
var img = qo.GetComponent<Image>();
img.sprite = icon;
}
qo.gameObject.SetActive(true);
item.m_Icon = qo;
item.m_distanceTxt = qo.gameObject.FindComponentDownHierarchy<TextMeshProUGUI>();
}
//var ind = GameObject.Instantiate<NavigationIndicator>(m_indicatorPrefab, transform);
var ind = GameObject.Instantiate<NavigationIndicator>(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;
}
}
}
}
};