Last active
October 21, 2020 09:38
-
-
Save frarees/1e5ba5202f1e51f33456 to your computer and use it in GitHub Desktop.
Follow a (Rect)Transform
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
public class Follow : MonoBehaviour | |
{ | |
[SerializeField] Camera m_Camera; | |
[SerializeField] Transform m_Target; | |
[SerializeField] Vector3 m_WorldOffset; | |
[SerializeField] Vector3 m_ScreenOffset; | |
[SerializeField, Tooltip ("Will not update depth/Z")] bool m_KeepDepth; | |
[SerializeField, Tooltip ("Won't work if Keep Depth is ON")] float m_DepthOffset; | |
Canvas m_Canvas; | |
/// <remarks> | |
/// Note that if target reparents and its canvas gets changed | |
/// this script won't notice and could stop positioning properly. | |
/// </remarks> | |
Canvas m_TargetCanvas; | |
Vector3 m_ScreenPos; | |
Vector3 m_WorldPos; | |
public Transform target { | |
get { | |
return m_Target; | |
} set { | |
m_Target = value; | |
UpdateTargetCanvas (); | |
} | |
} | |
new public Camera camera { | |
get { | |
return m_Camera ? m_Camera : Camera.main; | |
} set { | |
m_Camera = value; | |
} | |
} | |
public Vector3 worldOffset { | |
get { | |
return m_WorldOffset; | |
} set { | |
m_WorldOffset = value; | |
} | |
} | |
public Vector2 screenOffset { | |
get { | |
return m_ScreenOffset; | |
} set { | |
m_ScreenOffset = value; | |
} | |
} | |
void UpdateCanvas () | |
{ | |
m_Canvas = GetComponentInParent<Canvas> (); | |
} | |
void UpdateTargetCanvas () | |
{ | |
m_TargetCanvas = m_Target ? m_Target.GetComponentInParent<Canvas> () : null; | |
} | |
void Awake () | |
{ | |
UpdateCanvas (); | |
UpdateTargetCanvas (); | |
} | |
void OnValidate () | |
{ | |
UpdateTargetCanvas (); | |
} | |
void OnTransformParentChanged () | |
{ | |
UpdateCanvas (); | |
} | |
void OnEnable () | |
{ | |
Update (); | |
} | |
void Update () | |
{ | |
if (!camera) | |
return; | |
if (!m_Target) | |
return; | |
Vector3 pos = transform.position; | |
if (m_TargetCanvas) { | |
m_ScreenPos = RectTransformUtility.WorldToScreenPoint (GetCanvasCamera (m_TargetCanvas), m_Target.position + m_WorldOffset); | |
m_ScreenPos += m_ScreenOffset; | |
if (RectTransformUtility.ScreenPointToWorldPointInRectangle ( | |
m_TargetCanvas.transform as RectTransform, | |
m_ScreenPos, | |
GetCanvasCamera (m_TargetCanvas), | |
out m_WorldPos)) { | |
if (m_KeepDepth) | |
m_WorldPos.z = pos.z; | |
else | |
m_WorldPos.z = m_Target.position.z + m_DepthOffset; | |
transform.position = m_WorldPos; | |
} | |
} else if (m_Canvas) { | |
m_ScreenPos = RectTransformUtility.WorldToScreenPoint (camera, m_Target.position + m_WorldOffset); | |
m_ScreenPos += m_ScreenOffset; | |
if (RectTransformUtility.ScreenPointToWorldPointInRectangle ( | |
m_Canvas.transform as RectTransform, | |
m_ScreenPos, | |
GetCanvasCamera (m_Canvas), | |
out m_WorldPos)) { | |
if (m_KeepDepth) | |
m_WorldPos.z = pos.z; | |
else | |
m_WorldPos.z = m_Target.position.z + m_DepthOffset; | |
transform.position = m_WorldPos; | |
} | |
} else { | |
m_ScreenPos = camera.WorldToScreenPoint (m_Target.position + m_WorldOffset); | |
m_ScreenPos += m_ScreenOffset; | |
m_WorldPos = camera.ScreenToWorldPoint (m_ScreenPos); | |
if (m_KeepDepth) | |
m_WorldPos.z = pos.z; | |
else | |
m_WorldPos.z = m_Target.position.z + m_DepthOffset; | |
transform.position = camera.ScreenToWorldPoint (m_ScreenPos); | |
} | |
} | |
Camera GetCanvasCamera (Canvas canvas) { | |
if (!canvas) | |
return null; | |
switch (canvas.renderMode) { | |
case RenderMode.ScreenSpaceOverlay: | |
return null; | |
case RenderMode.ScreenSpaceCamera: | |
case RenderMode.WorldSpace: | |
return canvas.worldCamera; | |
default: | |
return null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment