using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; /// <summary> /// This class handles displaying Fact tooltips, when hovering over a fact in the Gameworld /// </summary> public class WorldFactInteraction : MonoBehaviour { public LayerMask factLayerMask; public Transform HidingCanvas; private GameObject currentDisplay; private Transform lastHit = null; void LateUpdate() { if (currentDisplay != null && currentDisplay.GetComponent<DragHandling>().dragged) { // currently dragging -> remove transparency to indicate dragging and let DragHandling.cs take over ChangeImageAlpha(currentDisplay.GetComponent<Image>(), 1); return; } UpdateDisplay(); } private void UpdateDisplay() { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); // if no fact was hit or pointer was over other UI if (!Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, factLayerMask) || WasOtherUIHit()) { // destroy currentDisplay if it exists lastHit = null; Destroy(currentDisplay); return; } FactObject factObj = hit.transform.gameObject.GetComponentInChildren<FactObject>(); if (factObj == null) { // should never happen, if the layerMask is set up correctly //Debug.LogError("WorldFactInteraction Raycast collided with object in factLayerMask, that did not contain a FactObject script: " + hit.transform.gameObject.name); lastHit = null; Destroy(currentDisplay); return; } if (hit.transform != lastHit) // a fact has been hit for the first time -> delete old display and instantiate new one { InstantiateNewDisplay(factObj); } currentDisplay.transform.position = Input.mousePosition; // move currentDisplay to mousePosition ChangeImageAlpha(currentDisplay.GetComponent<Image>(), 0.5f); // ensure that image alpha is correct, since it could have changed due to dragging lastHit = hit.transform; } private void InstantiateNewDisplay(FactObject factObj) { if (currentDisplay) Destroy(currentDisplay); Fact fact = StageStatic.stage.factState[factObj.URI]; // TODO: this link to DisplayFacts is not ideal: maybe refactor to SciptableObject or such currentDisplay = fact.instantiateDisplay(DisplayFacts.prefabDictionary[fact.GetType()], HidingCanvas); } #region Helper private static void ChangeImageAlpha(Image img, float alpha) { img.color = new Color(img.color.r, img.color.g, img.color.b, alpha); } /// <summary> /// Returns true if any UI other than currentDisplay was hit /// </summary> /// <returns></returns> private bool WasOtherUIHit() { PointerEventData pointerData = new(EventSystem.current) { position = Input.mousePosition }; List<RaycastResult> results = new(); EventSystem.current.RaycastAll(pointerData, results); foreach (var res in results) if (currentDisplay == null || !res.gameObject.transform.IsChildOf(currentDisplay.transform)) return true; return false; } #endregion Helper }