using UnityEngine;
using MalbersAnimations.Events;
using UnityEngine.UI;
using MalbersAnimations.Scriptables;
namespace MalbersAnimations.UI
{
/// makes an UI Object to follow a World Object
[AddComponentMenu("Malbers/UI/UI Follow Transform")]
public class UIFollowTransform : MonoBehaviour
{
[Tooltip("Reference for the Main Camera on the Scene")]
public Camera MainCamera;
[Tooltip("Which Transform to Follow and Convert to Screen Position")]
public TransformReference WorldTransform = new TransformReference();
[Tooltip("Use a child of the World Transform instead")]
public StringReference UseChild = new StringReference();
private Transform followT;
[Tooltip("If the Object is Off-Screen, disable it")]
public Behaviour HideOffScreen;
[Tooltip("Reset the World Transform to Null when this component is Disable")]
public bool ResetOnDisable = false;
[Tooltip("If the World transform is Null, hide the Behaviour [HideOffScreen]")]
public bool HideOnNull = false;
[Tooltip("Offset position for the tracked gameobject")]
public Vector3Reference Offset = new Vector3Reference( Vector3.zero);
[Tooltip("Scale of the Instantiated prefab")]
public Vector3Reference Scale = new Vector3Reference(Vector3.one);
public Vector3 ScreenCenter { get; set; }
public Vector3 DefaultScreenCenter { get; set; }
void Awake()
{
MainCamera = MTools.FindMainCamera();
ScreenCenter = transform.position;
DefaultScreenCenter = transform.position;
if (WorldTransform == null) WorldTransform = new TransformReference();
if (!WorldTransform.UseConstant && WorldTransform.Variable != null)
WorldTransform.Variable.OnValueChanged += ListenTransform;
}
private void OnDestroy()
{
if (!WorldTransform.UseConstant && WorldTransform.Variable != null)
WorldTransform.Variable.OnValueChanged -= ListenTransform;
}
private void OnEnable()
{
MainCamera = MTools.FindMainCamera();
if (HideOffScreen) HideOffScreen.transform.localScale = Scale;
if (WorldTransform.Value) Align();
//else
// Clear();
}
private void OnDisable()
{
if (ResetOnDisable) Clear();
}
public virtual void Clear()
{
WorldTransform.Value = null;
transform.position = ScreenCenter; //Reset the Screen Center Position
if (HideOffScreen) HideOffScreen.enabled = !HideOnNull;
}
public void ListenTransform(Transform newTarget)
{
enabled = newTarget != null;
FindFollow(newTarget);
Align();
}
public void SetTransform(Transform newTarget)
{
WorldTransform.Value = newTarget;
FindFollow(newTarget);
if (followT == null)
{
//Clear();
}
else
{
Align();
enabled = newTarget != null;
}
}
private void FindFollow(Transform newTarget)
{
if (newTarget != null && !string.IsNullOrEmpty(UseChild.Value))
{
followT = newTarget.FindGrandChild(UseChild);
if (followT == null) followT = newTarget;
}
else
{
followT = newTarget;
}
}
public void SetScreenCenter(Vector3 newScreenCenter)
{
ScreenCenter = newScreenCenter;
enabled = true;
}
void Update()
{
Align();
}
public void Align()
{
if (MainCamera == null || followT == null) { /*enabled = false; */return; }
var pos = MainCamera.WorldToScreenPoint(followT.position + Offset);
transform.position = pos;
if (HideOffScreen)
{
HideOffScreen.enabled = (DoHideOffScreen(pos));
}
else
{
if (pos.z < 0)
{
pos.y = pos.y > Screen.height / 2 ? 0 : Screen.height;
}
transform.position = new Vector3(
Mathf.Clamp(pos.x, 0, Screen.width),
Mathf.Clamp(pos.y, 0, Screen.height),
0);
}
}
private bool DoHideOffScreen(Vector3 position)
{
if (position.x < 0 || position.x > Screen.width) return false;
if (position.y < 0 || position.y > Screen.height) return false;
if (position.z < 0) return false;
return true;
}
#if UNITY_EDITOR
void Reset()
{
MEventListener MeventL = GetComponent();
if (MeventL == null)
{
MeventL = gameObject.AddComponent();
}
MeventL.Events = new System.Collections.Generic.List(1) { new MEventItemListener() };
var listener = MeventL.Events[0];
listener.useTransform = true;
listener.useVector3 = true;
listener.useVoid = false;
listener.Event = MTools.GetInstance("Follow UI Transform");
if (listener.Event != null)
{
UnityEditor.Events.UnityEventTools.AddPersistentListener(listener.ResponseTransform, SetTransform);
UnityEditor.Events.UnityEventTools.AddPersistentListener(listener.ResponseVector3, SetScreenCenter);
}
}
#endif
}
}