// Selection logic // Find the next selectable object in the specified world-space direction. public SelectableUI 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; SelectableUI bestPick = null; for (int i = 0; i < s_List.Count; ++i) { SelectableUI sel = s_List[i]; if (sel == this || sel == null) { continue; } if (!sel.IsInteractable() || sel.navigation.mode == NavigationUI.Mode.None) { continue; } 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); }
// Convenience function -- change the selection to the specified object if it's not null and happens to be active. void Navigate(AxisEventData eventData, SelectableUI sel) { if (sel != null && sel.IsActive()) { eventData.selectedObject = sel.gameObject; } }
private static void DrawNavigationArrow(Vector2 direction, SelectableUI fromObj, SelectableUI toObj) { if (fromObj == null || toObj == null) { return; } Transform fromTransform = fromObj.transform; Transform toTransform = toObj.transform; Vector2 sideDir = new Vector2(direction.y, -direction.x); Vector3 fromPoint = fromTransform.TransformPoint(GetPointOnRectEdge(fromTransform as RectTransform, direction)); Vector3 toPoint = toTransform.TransformPoint(GetPointOnRectEdge(toTransform as RectTransform, -direction)); float fromSize = HandleUtility.GetHandleSize(fromPoint) * 0.05f; float toSize = HandleUtility.GetHandleSize(toPoint) * 0.05f; fromPoint += fromTransform.TransformDirection(sideDir) * fromSize; toPoint += toTransform.TransformDirection(sideDir) * toSize; float length = Vector3.Distance(fromPoint, toPoint); Vector3 fromTangent = fromTransform.rotation * direction * length * 0.3f; Vector3 toTangent = toTransform.rotation * -direction * length * 0.3f; Handles.DrawBezier(fromPoint, toPoint, fromPoint + fromTangent, toPoint + toTangent, Handles.color, null, kArrowThickness); Handles.DrawAAPolyLine(kArrowThickness, toPoint, toPoint + toTransform.rotation * (-direction - sideDir) * toSize * kArrowHeadSize); Handles.DrawAAPolyLine(kArrowThickness, toPoint, toPoint + toTransform.rotation * (-direction + sideDir) * toSize * kArrowHeadSize); }
private static string GetSaveControllerPath(SelectableUI target) { var defaultName = target.gameObject.name; var message = string.Format("Create a new animator for the game object '{0}':", defaultName); return(EditorUtility.SaveFilePanelInProject("New Animation Contoller", defaultName, "controller", message)); }
private static void DrawNavigationForSelectable(SelectableUI sel) { if (sel == null) { return; } Transform transform = sel.transform; bool active = Selection.transforms.Any(e => e == transform); Handles.color = new Color(1.0f, 0.9f, 0.1f, active ? 1.0f : 0.4f); DrawNavigationArrow(-Vector2.right, sel, sel.FindSelectableOnLeft()); DrawNavigationArrow(Vector2.right, sel, sel.FindSelectableOnRight()); DrawNavigationArrow(Vector2.up, sel, sel.FindSelectableOnUp()); DrawNavigationArrow(-Vector2.up, sel, sel.FindSelectableOnDown()); }
private static string BuildAnimationPath(SelectableUI target) { // if no target don't hook up any curves. var highlight = target.targetGraphic; if (highlight == null) { return(string.Empty); } var startGo = highlight.gameObject; var toFindGo = target.gameObject; var pathComponents = new Stack <string>(); while (toFindGo != startGo) { pathComponents.Push(startGo.name); // didn't exist in hierarchy! if (startGo.transform.parent == null) { return(string.Empty); } startGo = startGo.transform.parent.gameObject; } // calculate path var animPath = new StringBuilder(); if (pathComponents.Count > 0) { animPath.Append(pathComponents.Pop()); } while (pathComponents.Count > 0) { animPath.Append("/").Append(pathComponents.Pop()); } return(animPath.ToString()); }
protected static UnityEditor.Animations.AnimatorController GenerateSelectableAnimatorContoller(AnimationTriggers animationTriggers, SelectableUI target) { if (target == null) { return(null); } // Where should we create the controller? var path = GetSaveControllerPath(target); if (string.IsNullOrEmpty(path)) { return(null); } // figure out clip names var normalName = string.IsNullOrEmpty(animationTriggers.normalTrigger) ? "Normal" : animationTriggers.normalTrigger; var highlightedName = string.IsNullOrEmpty(animationTriggers.highlightedTrigger) ? "Highlighted" : animationTriggers.highlightedTrigger; var pressedName = string.IsNullOrEmpty(animationTriggers.pressedTrigger) ? "Pressed" : animationTriggers.pressedTrigger; var disabledName = string.IsNullOrEmpty(animationTriggers.disabledTrigger) ? "Disabled" : animationTriggers.disabledTrigger; // Create controller and hook up transitions. var controller = UnityEditor.Animations.AnimatorController.CreateAnimatorControllerAtPath(path); GenerateTriggerableTransition(normalName, controller); GenerateTriggerableTransition(highlightedName, controller); GenerateTriggerableTransition(pressedName, controller); GenerateTriggerableTransition(disabledName, controller); AssetDatabase.ImportAsset(path); return(controller); }