using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using Lean.Transition; using Lean.Common; namespace Lean.Gui { /// This component will place the current RectTransform above the currently selected object. [RequireComponent(typeof(RectTransform))] [HelpURL(LeanGui.HelpUrlPrefix + "LeanSelectionHighlight")] [AddComponentMenu(LeanGui.ComponentMenuPrefix + "Selection Highlight")] public class LeanSelectionHighlight : MonoBehaviour { /// The camera rendering the target transform/position. /// None = MainCamera. public Camera WorldCamera { set { worldCamera = value; } get { return worldCamera; } } [SerializeField] private Camera worldCamera; /// This allows you to perform a transition when the highlight begins. /// You can create a new transition GameObject by right clicking the transition name, and selecting Create. /// For example, the Graphic.color Transition (LeanGraphicColor) component can be used to change the color. /// NOTE: Any transitions you perform here must be reverted in the Hide Transitions setting using a matching transition component. public LeanPlayer ShowTransitions { get { if (showTransitions == null) showTransitions = new LeanPlayer(); return showTransitions; } } [SerializeField] private LeanPlayer showTransitions; /// This allows you to perform a transition when the highlight ends. /// You can create a new transition GameObject by right clicking the transition name, and selecting Create. /// For example, the Graphic.color Transition (LeanGraphicColor) component can be used to change the color. /// NOTE: Any transitions you perform here must be reverted in the Show Transitions setting using a matching transition component. public LeanPlayer HideTransitions { get { if (hideTransitions == null) hideTransitions = new LeanPlayer(); return hideTransitions; } } [SerializeField] private LeanPlayer hideTransitions; /// This allows you to perform an action when the highlight starts. public UnityEvent OnShow { get { if (onShow == null) onShow = new UnityEvent(); return onShow; } } [SerializeField] private UnityEvent onShow; /// This allows you to perform an action when the highlight ends. public UnityEvent OnHide { get { if (onHide == null) onHide = new UnityEvent(); return onHide; } } [SerializeField] private UnityEvent onHide; [SerializeField] private bool showing; [System.NonSerialized] protected RectTransform rectTransform; [System.NonSerialized] protected RectTransform canvasRectTransform; protected virtual void LateUpdate() { var eventSystem = EventSystem.current; var show = false; if (eventSystem != null) { var selected = eventSystem.currentSelectedGameObject; if (selected != null) { var selectedRect = selected.GetComponent(); if (selectedRect != null) { show = UpdateRect(selectedRect); } } } if (showing != show) { showing = show; if (showing == true) { if (showTransitions != null) { showTransitions.Begin(); } } else { if (hideTransitions != null) { hideTransitions.Begin(); } } } } private bool UpdateRect(RectTransform target) { var camera = worldCamera; if (camera == null) { camera = Camera.main; } if (camera != null) { if (rectTransform == null) { rectTransform = GetComponent(); } if (canvasRectTransform == null) { var canvas = GetComponentInParent(); if (canvas == null) { throw new System.Exception("Couldn't find attached canvas??"); } canvasRectTransform = canvas.GetComponent(); } // Calculate viewport/anchor points var min = target.rect.min; var max = target.rect.max; var targetA = target.TransformPoint(min.x, min.y, 0.0f); var targetB = target.TransformPoint(max.x, min.y, 0.0f); var targetC = target.TransformPoint(min.x, max.y, 0.0f); var targetD = target.TransformPoint(max.x, max.y, 0.0f); var worldSpace = target.GetComponentInParent().renderMode == RenderMode.WorldSpace; var viewportPointA = WorldToViewportPoint(camera, targetA, worldSpace); var viewportPointB = WorldToViewportPoint(camera, targetB, worldSpace); var viewportPointC = WorldToViewportPoint(camera, targetC, worldSpace); var viewportPointD = WorldToViewportPoint(camera, targetD, worldSpace); // If outside frustum, hide line out of view if (LeanGui.InvaidViewportPoint(camera, viewportPointA) == true || LeanGui.InvaidViewportPoint(camera, viewportPointB) == true || LeanGui.InvaidViewportPoint(camera, viewportPointC) == true || LeanGui.InvaidViewportPoint(camera, viewportPointD) == true) { viewportPointA = viewportPointB = viewportPointC = viewportPointD = new Vector3(10.0f, 10.0f); } var minX = Mathf.Min(Mathf.Min(viewportPointA.x, viewportPointB.x), Mathf.Min(viewportPointC.x, viewportPointD.x)); var minY = Mathf.Min(Mathf.Min(viewportPointA.y, viewportPointB.y), Mathf.Min(viewportPointC.y, viewportPointD.y)); var maxX = Mathf.Max(Mathf.Max(viewportPointA.x, viewportPointB.x), Mathf.Max(viewportPointC.x, viewportPointD.x)); var maxY = Mathf.Max(Mathf.Max(viewportPointA.y, viewportPointB.y), Mathf.Max(viewportPointC.y, viewportPointD.y)); // Convert viewport points to canvas points var canvasRect = canvasRectTransform.rect; var canvasXA = canvasRect.xMin + canvasRect.width * minX; var canvasYA = canvasRect.yMin + canvasRect.height * minY; var canvasXB = canvasRect.xMin + canvasRect.width * maxX; var canvasYB = canvasRect.yMin + canvasRect.height * maxY; // Find center, reset anchor, and convert canvas point to world point var canvasX = (canvasXA + canvasXB) * 0.5f; var canvasY = (canvasYA + canvasYB) * 0.5f; rectTransform.anchorMin = rectTransform.anchorMax = Vector2.zero; rectTransform.sizeDelta = new Vector2(canvasXB - canvasXA, canvasYB - canvasYA); rectTransform.position = canvasRectTransform.TransformPoint(canvasX, canvasY, 0.0f); // Get vector between points return true; } return false; } private static Vector3 WorldToViewportPoint(Camera camera, Vector3 point, bool worldSpace) { if (worldSpace == false) { point = RectTransformUtility.WorldToScreenPoint(null, point); point.z = 0.5f; return camera.ScreenToViewportPoint(point); } return camera.WorldToViewportPoint(point); } } } #if UNITY_EDITOR namespace Lean.Gui.Editor { using TARGET = LeanSelectionHighlight; [UnityEditor.CanEditMultipleObjects] [UnityEditor.CustomEditor(typeof(TARGET))] public class LeanSelectionHighlight_Editor : LeanEditor { protected override void OnInspector() { TARGET tgt; TARGET[] tgts; GetTargets(out tgt, out tgts); Draw("worldCamera", "The camera rendering the target transform/position.\nNone = MainCamera."); Separator(); Draw("showTransitions", "This allows you to perform a transition when the highlight begins. You can create a new transition GameObject by right clicking the transition name, and selecting Create. For example, the Graphic.color Transition (LeanGraphicColor) component can be used to change the color.\n\nNOTE: Any transitions you perform here must be reverted in the Hide Transitions setting using a matching transition component."); Draw("hideTransitions", "This allows you to perform a transition when the highlight ends. You can create a new transition GameObject by right clicking the transition name, and selecting Create. For example, the Graphic.color Transition (LeanGraphicColor) component can be used to change the color.\n\nNOTE: Any transitions you perform here must be reverted in the Show Transitions setting using a matching transition component."); Separator(); Draw("onShow", "This allows you to perform an action when the highlight starts."); Draw("onHide", "This allows you to perform an action when the highlight ends."); } } } #endif