EventMarkerTooltip.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using TMPro;
  4. /// <summary>
  5. /// Handles mouse hover tooltips for event markers
  6. /// Shows event information when hovering over red event markers
  7. /// </summary>
  8. public class EventMarkerTooltip : MonoBehaviour
  9. {
  10. [Header("Tooltip Settings")]
  11. [SerializeField] private GameObject tooltipPrefab;
  12. [SerializeField] private Canvas tooltipCanvas;
  13. [SerializeField] private float showDelay = 0.5f;
  14. [SerializeField] private Vector2 tooltipOffset = new Vector2(10f, 10f);
  15. // References
  16. private TravelEvent associatedEvent;
  17. private GameObject tooltipInstance;
  18. private Camera mainCamera;
  19. private bool isHovering = false;
  20. private float hoverStartTime;
  21. // Static tooltip management (only one tooltip at a time)
  22. private static EventMarkerTooltip currentTooltipShowing;
  23. void Start()
  24. {
  25. mainCamera = Camera.main;
  26. if (mainCamera == null)
  27. mainCamera = FindFirstObjectByType<Camera>();
  28. // Find or create tooltip canvas
  29. SetupTooltipCanvas();
  30. }
  31. void Update()
  32. {
  33. // Handle mouse hover detection
  34. if (isHovering && tooltipInstance == null && Time.time - hoverStartTime >= showDelay)
  35. {
  36. ShowTooltip();
  37. }
  38. // Update tooltip position if showing
  39. if (tooltipInstance != null && isHovering)
  40. {
  41. UpdateTooltipPosition();
  42. }
  43. }
  44. /// <summary>
  45. /// Initialize this tooltip with event data
  46. /// </summary>
  47. /// <param name="travelEvent">The event this marker represents</param>
  48. public void Initialize(TravelEvent travelEvent)
  49. {
  50. associatedEvent = travelEvent;
  51. // Add collider for mouse detection if not present
  52. if (GetComponent<Collider>() == null)
  53. {
  54. var collider = gameObject.AddComponent<SphereCollider>();
  55. collider.radius = 1.5f; // Larger area for easier hovering when zoomed out
  56. collider.isTrigger = true;
  57. }
  58. }
  59. void OnMouseEnter()
  60. {
  61. if (associatedEvent == null) return;
  62. isHovering = true;
  63. hoverStartTime = Time.time;
  64. // Hide any other tooltips
  65. if (currentTooltipShowing != null && currentTooltipShowing != this)
  66. {
  67. currentTooltipShowing.HideTooltip();
  68. }
  69. }
  70. void OnMouseExit()
  71. {
  72. isHovering = false;
  73. HideTooltip();
  74. }
  75. void OnDestroy()
  76. {
  77. HideTooltip();
  78. }
  79. private void SetupTooltipCanvas()
  80. {
  81. if (tooltipCanvas == null)
  82. {
  83. // Find existing UI canvas or create one
  84. tooltipCanvas = FindFirstObjectByType<Canvas>();
  85. if (tooltipCanvas == null)
  86. {
  87. // Create a new canvas for tooltips
  88. GameObject canvasObject = new GameObject("EventTooltipCanvas");
  89. tooltipCanvas = canvasObject.AddComponent<Canvas>();
  90. tooltipCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
  91. tooltipCanvas.sortingOrder = 1000; // High sorting order to appear on top
  92. // Add Canvas Scaler for responsive UI
  93. var scaler = canvasObject.AddComponent<CanvasScaler>();
  94. scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
  95. scaler.referenceResolution = new Vector2(1920, 1080);
  96. // Add GraphicRaycaster for UI interaction
  97. canvasObject.AddComponent<GraphicRaycaster>();
  98. }
  99. }
  100. }
  101. private void ShowTooltip()
  102. {
  103. if (tooltipInstance != null || associatedEvent == null) return;
  104. // Create tooltip from prefab or default
  105. if (tooltipPrefab != null)
  106. {
  107. tooltipInstance = Instantiate(tooltipPrefab, tooltipCanvas.transform);
  108. }
  109. else
  110. {
  111. tooltipInstance = CreateDefaultTooltip();
  112. }
  113. // Set tooltip content
  114. SetTooltipContent();
  115. // Position tooltip
  116. UpdateTooltipPosition();
  117. currentTooltipShowing = this;
  118. }
  119. private GameObject CreateDefaultTooltip()
  120. {
  121. // Create default tooltip UI
  122. GameObject tooltip = new GameObject("EventTooltip");
  123. tooltip.transform.SetParent(tooltipCanvas.transform, false);
  124. // Add background image
  125. var bgImage = tooltip.AddComponent<Image>();
  126. bgImage.color = new Color(0.05f, 0.05f, 0.05f, 0.95f); // Darker, more opaque background for better readability
  127. // Add subtle border/outline effect
  128. var outline = tooltip.AddComponent<Outline>();
  129. outline.effectColor = new Color(0.3f, 0.3f, 0.3f, 1f);
  130. outline.effectDistance = new Vector2(1f, 1f);
  131. // Add content layout
  132. var layoutGroup = tooltip.AddComponent<VerticalLayoutGroup>();
  133. layoutGroup.padding = new RectOffset(15, 15, 12, 12); // More padding for better spacing
  134. layoutGroup.spacing = 8f; // More spacing between elements
  135. layoutGroup.childAlignment = TextAnchor.MiddleLeft;
  136. layoutGroup.childControlWidth = true;
  137. layoutGroup.childControlHeight = true;
  138. layoutGroup.childForceExpandWidth = false;
  139. layoutGroup.childForceExpandHeight = false;
  140. // Add content size fitter
  141. var sizeFitter = tooltip.AddComponent<ContentSizeFitter>();
  142. sizeFitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
  143. sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
  144. // Create title text
  145. GameObject titleObject = new GameObject("Title");
  146. titleObject.transform.SetParent(tooltip.transform, false);
  147. var titleText = titleObject.AddComponent<TextMeshProUGUI>();
  148. titleText.text = "Event Title";
  149. titleText.fontSize = 18f; // Larger font for better readability
  150. titleText.fontWeight = FontWeight.Bold;
  151. titleText.color = Color.white;
  152. // Create description text
  153. GameObject descObject = new GameObject("Description");
  154. descObject.transform.SetParent(tooltip.transform, false);
  155. var descText = descObject.AddComponent<TextMeshProUGUI>();
  156. descText.text = "Event description...";
  157. descText.fontSize = 14f; // Larger font for better readability
  158. descText.color = new Color(0.9f, 0.9f, 0.9f, 1f); // Lighter gray for better contrast
  159. descText.textWrappingMode = TMPro.TextWrappingModes.Normal; // Updated property name
  160. // Set max width for text wrapping
  161. var titleRect = titleText.GetComponent<RectTransform>();
  162. titleRect.sizeDelta = new Vector2(350f, 0f); // Wider tooltip for better text layout
  163. var descRect = descText.GetComponent<RectTransform>();
  164. descRect.sizeDelta = new Vector2(350f, 0f);
  165. return tooltip;
  166. }
  167. private void SetTooltipContent()
  168. {
  169. if (tooltipInstance == null || associatedEvent == null) return;
  170. // Find text components
  171. var textComponents = tooltipInstance.GetComponentsInChildren<TextMeshProUGUI>();
  172. if (textComponents.Length >= 2)
  173. {
  174. // Set title
  175. textComponents[0].text = GetEventTitle();
  176. // Set description
  177. textComponents[1].text = GetEventDescription();
  178. }
  179. else
  180. {
  181. // Fallback for different tooltip structures
  182. var singleText = tooltipInstance.GetComponentInChildren<TextMeshProUGUI>();
  183. if (singleText != null)
  184. {
  185. singleText.text = $"{GetEventTitle()}\n{GetEventDescription()}";
  186. }
  187. }
  188. }
  189. private string GetEventTitle()
  190. {
  191. if (associatedEvent == null) return "Unknown Event";
  192. // Get event type icon
  193. string icon = associatedEvent.eventType switch
  194. {
  195. EventType.Combat => "⚔️",
  196. EventType.Trading => "💰",
  197. EventType.Discovery => "🔍",
  198. EventType.Social => "💬",
  199. EventType.Hazard => "⚠️",
  200. EventType.Rest => "🏕️",
  201. EventType.Mystery => "❓",
  202. _ => "📍"
  203. };
  204. return $"{icon} {associatedEvent.eventName}";
  205. }
  206. private string GetEventDescription()
  207. {
  208. if (associatedEvent == null) return "No information available.";
  209. string description = associatedEvent.eventDescription;
  210. // Add event type information
  211. string typeInfo = associatedEvent.eventType switch
  212. {
  213. EventType.Combat => "Combat encounter - approach to engage",
  214. EventType.Trading => "Trading opportunity - approach to trade",
  215. EventType.Discovery => "Something to discover - approach to investigate",
  216. EventType.Social => "Social encounter - approach to interact",
  217. EventType.Hazard => "Environmental hazard - approach with caution",
  218. EventType.Rest => "Rest opportunity - approach to recover",
  219. EventType.Mystery => "Mysterious event - approach to uncover",
  220. _ => "Unknown event type"
  221. };
  222. // Add rarity information
  223. string rarityInfo = associatedEvent.rarity switch
  224. {
  225. EventRarity.VeryCommon => "Very Common",
  226. EventRarity.Common => "Common",
  227. EventRarity.Uncommon => "Uncommon",
  228. EventRarity.Rare => "Rare",
  229. EventRarity.VeryRare => "Very Rare",
  230. EventRarity.Legendary => "Legendary",
  231. _ => "Unknown"
  232. };
  233. return $"{description}\n\nType: {typeInfo}\nRarity: {rarityInfo}\n\n<i>Move close to trigger this event</i>";
  234. }
  235. private void UpdateTooltipPosition()
  236. {
  237. if (tooltipInstance == null || mainCamera == null) return;
  238. // Get mouse position
  239. Vector3 mousePos = Input.mousePosition;
  240. // Add offset
  241. mousePos.x += tooltipOffset.x;
  242. mousePos.y += tooltipOffset.y;
  243. // Ensure tooltip stays on screen
  244. RectTransform tooltipRect = tooltipInstance.GetComponent<RectTransform>();
  245. if (tooltipRect != null)
  246. {
  247. // Get screen bounds
  248. float screenWidth = Screen.width;
  249. float screenHeight = Screen.height;
  250. // Get tooltip size
  251. Vector2 tooltipSize = tooltipRect.sizeDelta;
  252. // Adjust position to keep tooltip on screen
  253. if (mousePos.x + tooltipSize.x > screenWidth)
  254. {
  255. mousePos.x = screenWidth - tooltipSize.x - 10f;
  256. }
  257. if (mousePos.y + tooltipSize.y > screenHeight)
  258. {
  259. mousePos.y = mousePos.y - tooltipSize.y - tooltipOffset.y * 2;
  260. }
  261. // Set position
  262. tooltipRect.position = mousePos;
  263. }
  264. }
  265. private void HideTooltip()
  266. {
  267. if (tooltipInstance != null)
  268. {
  269. Destroy(tooltipInstance);
  270. tooltipInstance = null;
  271. }
  272. if (currentTooltipShowing == this)
  273. {
  274. currentTooltipShowing = null;
  275. }
  276. }
  277. }