Example #1
0
        // Select on enable and add to the list.
        protected virtual void OnEnable()
        {
            //Check to avoid multiple OnEnable() calls for each selectable
            if (m_EnableCalled)
            {
                return;
            }

            //base.OnEnable();

            if (s_SelectableCount == s_Selectables.Length)
            {
                InGameSelectable[] temp = new InGameSelectable[s_Selectables.Length * 2];
                Array.Copy(s_Selectables, temp, s_Selectables.Length);
                s_Selectables = temp;
            }
            m_CurrentIndex = s_SelectableCount;
            s_Selectables[m_CurrentIndex] = this;
            s_SelectableCount++;
            isPointerDown = false;
            DoStateTransition(currentSelectionState, true);

            m_EnableCalled = true;
        }
Example #2
0
        // Selection logic

        /// <summary>
        /// Finds the selectable object next to this one.
        /// </summary>
        /// <remarks>
        /// The direction is determined by a Vector3 variable.
        /// </remarks>
        /// <param name="dir">The direction in which to search for a neighbouring Selectable object.</param>
        /// <returns>The neighbouring Selectable object. Null if none found.</returns>
        /// <example>
        /// <code>
        /// using UnityEngine;
        /// using System.Collections;
        /// using UnityEngine.UI; // required when using UI elements in scripts
        ///
        /// public class ExampleClass : MonoBehaviour
        /// {
        ///     //Sets the direction as "Up" (Y is in positive).
        ///     public Vector3 direction = new Vector3(0, 1, 0);
        ///     public Button btnMain;
        ///
        ///     public void Start()
        ///     {
        ///         //Finds and assigns the selectable above the main button
        ///         Selectable newSelectable = btnMain.FindSelectable(direction);
        ///
        ///         Debug.Log(newSelectable.name);
        ///     }
        /// }
        /// </code>
        /// </example>
        public InGameSelectable FindSelectable(Vector3 dir)
        {
            dir = dir.normalized;
            Vector3          localDir = Quaternion.Inverse(transform.rotation) * dir;
            Vector3          pos      = transform.TransformPoint(GetPointOnRectEdge(transform as RectTransform, localDir));
            float            maxScore = Mathf.NegativeInfinity;
            InGameSelectable bestPick = null;

            for (int i = 0; i < s_SelectableCount; ++i)
            {
                InGameSelectable sel = s_Selectables[i];

                if (sel == this)
                {
                    continue;
                }

                if (!sel.IsInteractable() || sel.navigation.mode == Navigation.Mode.None)
                {
                    continue;
                }

#if UNITY_EDITOR
                // Apart from runtime use, FindSelectable is used by custom editors to
                // draw arrows between different selectables. For scene view cameras,
                // only selectables in the same stage should be considered.
                if (Camera.current != null && !UnityEditor.SceneManagement.StageUtility.IsGameObjectRenderedByCamera(sel.gameObject, Camera.current))
                {
                    continue;
                }
#endif

                var     selRect   = sel.transform as RectTransform;
                Vector3 selCenter = selRect != null ? (Vector3)selRect.rect.center : Vector3.zero;
                Vector3 myVector  = sel.transform.TransformPoint(selCenter) - pos;

                // Value that is the distance out along the direction.
                float dot = Vector3.Dot(dir, myVector);

                // Skip elements that are in the wrong direction or which have zero distance.
                // This also ensures that the scoring formula below will not have a division by zero error.
                if (dot <= 0)
                {
                    continue;
                }

                // This scoring function has two priorities:
                // - Score higher for positions that are closer.
                // - Score higher for positions that are located in the right direction.
                // This scoring function combines both of these criteria.
                // It can be seen as this:
                //   Dot (dir, myVector.normalized) / myVector.magnitude
                // The first part equals 1 if the direction of myVector is the same as dir, and 0 if it's orthogonal.
                // The second part scores lower the greater the distance is by dividing by the distance.
                // The formula below is equivalent but more optimized.
                //
                // If a given score is chosen, the positions that evaluate to that score will form a circle
                // that touches pos and whose center is located along dir. A way to visualize the resulting functionality is this:
                // From the position pos, blow up a circular balloon so it grows in the direction of dir.
                // The first Selectable whose center the circular balloon touches is the one that's chosen.
                float score = dot / myVector.sqrMagnitude;

                if (score > maxScore)
                {
                    maxScore = score;
                    bestPick = sel;
                }
            }
            return(bestPick);
        }