using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace BNG { /// /// Shows a ring at the grab point of a grabbable if within a certain distance /// public class RingHelper : MonoBehaviour { [Tooltip("The Grabbable Object to Observe")] public Grabbable grabbable; [Tooltip("(Optional) If specified, the ring helper will only be valid if this Grabpoint is the nearest on the the grabbable object")] public GrabPoint Grabpoint; [Tooltip("Default Color of the ring")] public Color RingColor = Color.white; /// /// Color to use if selected by primary controller /// [Tooltip("Color to use if selected by primary controller")] public Color RingSelectedColor = Color.white; /// /// Color to use if selected by secondary controller /// [Tooltip("Color to use if selected by secondary controller")] public Color RingSecondarySelectedColor = Color.white; public float ringSizeInRange = 1500f; public float ringSizeGrabbable = 1100f; // Lower pixel size the bigger the font /// /// Don't show grab rings if left and right controllers / grabbers are holding something /// [Tooltip("Don't show grab rings if left and right controllers / grabbers are holding something")] public bool HideIfHandsAreFull = true; /// /// How fast to lerp the opacity if being hidden / shown /// [Tooltip("How fast to lerp the opacity if being hidden / shown")] public float RingFadeSpeed = 5; Canvas canvas; Text text; CanvasScaler scaler; /// /// Used to determine if hands are full /// Grabber leftGrabber; Grabber rightGrabber; Grabber closestGrabber; bool handsFull = false; // Animate opacity private float _initalOpacity; private float _currentOpacity; Transform mainCam; void Start() { AssignCamera(); if (grabbable == null) { grabbable = transform.parent.GetComponent(); } canvas = GetComponent(); scaler = GetComponent(); text = GetComponent(); if(text == null) { Debug.LogWarning("No Text Component Found on RingHelper"); return; } _initalOpacity = text.color.a; _currentOpacity = _initalOpacity; AssignGrabbers(); } void Update() { // Double check for mainCam AssignCamera(); // Bail if Text Component was removed or doesn't exist if (text == null || mainCam == null || grabbable == null) { return; } bool grabbersExist = leftGrabber != null && rightGrabber != null; // Holding Item handsFull = grabbersExist && leftGrabber.HoldingItem && rightGrabber.HoldingItem; // Not a valid Grab if(grabbersExist && grabbable.GrabButton == GrabButton.Grip && !leftGrabber.FreshGrip && !rightGrabber.FreshGrip) { handsFull = true; } bool showRings = handsFull; // If being held or not active, immediately hide the ring if (grabbable.BeingHeld || !grabbable.isActiveAndEnabled) { canvas.enabled = false; return; } // Requires another Grabbable to be held. Can exit immediately if(grabbable.OtherGrabbableMustBeGrabbed != null && grabbable.OtherGrabbableMustBeGrabbed.BeingHeld == false) { canvas.enabled = false; return; } // Show if within range float currentDistance = Vector3.Distance(transform.position, mainCam.position); if(!handsFull && currentDistance <= grabbable.RemoteGrabDistance) { showRings = true; } else { showRings = false; } // Animate ring opacity in / out if(showRings) { canvas.enabled = true; canvas.transform.LookAt(mainCam); // Resetting the text refreshes the render text.text = "o"; bool isClosest = grabbable.GetClosestGrabber() != null && grabbable.IsGrabbable(); // Check if grabpoint was specified if(Grabpoint != null) { } // If a valid grabbable, increase size a bit if (isClosest) { scaler.dynamicPixelsPerUnit = ringSizeGrabbable; text.color = getSelectedColor(); } else { scaler.dynamicPixelsPerUnit = ringSizeInRange; text.color = RingColor; } _currentOpacity += Time.deltaTime * RingFadeSpeed; if (_currentOpacity > _initalOpacity) { _currentOpacity = _initalOpacity; } Color colorCurrent = text.color; colorCurrent.a = _currentOpacity; text.color = colorCurrent; } else { _currentOpacity -= Time.deltaTime * RingFadeSpeed; if (_currentOpacity <= 0) { _currentOpacity = 0; canvas.enabled = false; } else { canvas.enabled = true; Color colorCurrent = text.color; colorCurrent.a = _currentOpacity; text.color = colorCurrent; } } } public virtual void AssignCamera() { if (mainCam == null) { // Find By Tag instead of Camera.main as the camera could be disabled if(GameObject.FindGameObjectWithTag("MainCamera") != null) { mainCam = GameObject.FindGameObjectWithTag("MainCamera").transform; } } } public virtual void AssignGrabbers() { // Assign left / right grabbers Grabber[] grabs; GameObject player = GameObject.FindGameObjectWithTag("Player"); if (player) { grabs = player.GetComponentsInChildren(); } else { // Fall back to all grabbers grabs = FindObjectsOfType(); } // Check grabber assignment for (int x = 0; x < grabs.Length; x++) { Grabber g = grabs[x]; if (g.HandSide == ControllerHand.Left) { leftGrabber = g; } else if (g.HandSide == ControllerHand.Right) { rightGrabber = g; } } } Color getSelectedColor() { // Use secondary color if closest grabber is on the left hand closestGrabber = grabbable.GetClosestGrabber(); if (grabbable != null && closestGrabber != null) { if (closestGrabber.HandSide == ControllerHand.Left) { return RingSecondarySelectedColor; } } return RingSelectedColor; } } }