UIToolkitActionWheel.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. using UnityEngine;
  2. using UnityEngine.UIElements;
  3. using System.Collections.Generic;
  4. using System;
  5. /// <summary>
  6. /// Modern UI Toolkit-based action wheel for battle actions
  7. /// Uses UI Builder and USS for styling instead of legacy Canvas components
  8. /// </summary>
  9. public class UIToolkitActionWheel : MonoBehaviour
  10. {
  11. [Header("Settings")]
  12. public float wheelRadius = 150f;
  13. public float buttonSize = 80f;
  14. public KeyCode toggleKey = KeyCode.Q;
  15. private UIDocument uiDocument;
  16. private VisualElement root;
  17. private VisualElement wheelContainer;
  18. private List<ActionButtonElement> actionButtons = new List<ActionButtonElement>();
  19. private Character currentCharacter;
  20. private bool isVisible = false;
  21. // Events
  22. public event Action<BattleActionType> OnActionSelected;
  23. public event Action OnWheelClosed;
  24. private class ActionButtonElement
  25. {
  26. public VisualElement element;
  27. public BattleActionType actionType;
  28. public bool isEnabled = true;
  29. public ActionButtonElement(VisualElement element, BattleActionType actionType)
  30. {
  31. this.element = element;
  32. this.actionType = actionType;
  33. }
  34. }
  35. void Awake()
  36. {
  37. // Get or create UIDocument
  38. uiDocument = GetComponent<UIDocument>();
  39. if (uiDocument == null)
  40. {
  41. uiDocument = gameObject.AddComponent<UIDocument>();
  42. }
  43. CreateActionWheelUI();
  44. }
  45. void Start()
  46. {
  47. SetVisible(false);
  48. }
  49. void Update()
  50. {
  51. if (Input.GetKeyDown(toggleKey))
  52. {
  53. if (isVisible)
  54. {
  55. HideWheel();
  56. }
  57. else
  58. {
  59. // Find selected character
  60. var selectedCharacter = FindSelectedCharacter();
  61. if (selectedCharacter != null)
  62. {
  63. ShowWheelForCharacter(selectedCharacter);
  64. }
  65. else
  66. {
  67. Debug.Log("⚠️ No character selected for action wheel");
  68. }
  69. }
  70. }
  71. if (isVisible && Input.GetKeyDown(KeyCode.Escape))
  72. {
  73. HideWheel();
  74. }
  75. }
  76. private void CreateActionWheelUI()
  77. {
  78. // Create the root UI structure programmatically
  79. root = new VisualElement();
  80. root.name = "ActionWheelRoot";
  81. root.style.position = Position.Absolute;
  82. root.style.width = Length.Percent(100);
  83. root.style.height = Length.Percent(100);
  84. root.style.justifyContent = Justify.Center;
  85. root.style.alignItems = Align.Center;
  86. // Create wheel container
  87. wheelContainer = new VisualElement();
  88. wheelContainer.name = "WheelContainer";
  89. wheelContainer.style.width = wheelRadius * 2;
  90. wheelContainer.style.height = wheelRadius * 2;
  91. wheelContainer.style.position = Position.Relative;
  92. // Add background circle
  93. var background = new VisualElement();
  94. background.name = "WheelBackground";
  95. background.style.width = Length.Percent(100);
  96. background.style.height = Length.Percent(100);
  97. background.style.borderTopLeftRadius = wheelRadius;
  98. background.style.borderTopRightRadius = wheelRadius;
  99. background.style.borderBottomLeftRadius = wheelRadius;
  100. background.style.borderBottomRightRadius = wheelRadius;
  101. background.style.backgroundColor = new Color(0, 0, 0, 0.3f);
  102. background.style.borderBottomColor = Color.white;
  103. background.style.borderBottomWidth = 2;
  104. background.style.borderTopColor = Color.white;
  105. background.style.borderTopWidth = 2;
  106. background.style.borderLeftColor = Color.white;
  107. background.style.borderLeftWidth = 2;
  108. background.style.borderRightColor = Color.white;
  109. background.style.borderRightWidth = 2;
  110. wheelContainer.Add(background);
  111. // Create action buttons
  112. CreateActionButtons();
  113. root.Add(wheelContainer);
  114. // Set the visual tree
  115. if (uiDocument.visualTreeAsset == null)
  116. {
  117. uiDocument.rootVisualElement.Add(root);
  118. }
  119. }
  120. private void CreateActionButtons()
  121. {
  122. var actionDefinitions = new[]
  123. {
  124. new { type = BattleActionType.Attack, label = "⚔️\nAttack", color = new Color(1f, 0.3f, 0.3f) },
  125. new { type = BattleActionType.Move, label = "👟\nMove", color = new Color(0.3f, 1f, 0.3f) },
  126. new { type = BattleActionType.UseItem, label = "🧪\nItem", color = new Color(0.3f, 0.3f, 1f) },
  127. new { type = BattleActionType.CastSpell, label = "✨\nSpell", color = new Color(1f, 0.3f, 1f) },
  128. new { type = BattleActionType.Defend, label = "🛡️\nDefend", color = new Color(0.8f, 0.8f, 0.3f) },
  129. new { type = BattleActionType.RunAway, label = "💨\nRun", color = new Color(0.6f, 0.6f, 0.6f) }
  130. };
  131. int actionCount = actionDefinitions.Length;
  132. float angleStep = 360f / actionCount;
  133. for (int i = 0; i < actionCount; i++)
  134. {
  135. var actionDef = actionDefinitions[i];
  136. float angle = i * angleStep - 90f; // Start from top
  137. CreateActionButton(actionDef.type, actionDef.label, actionDef.color, angle);
  138. }
  139. }
  140. private void CreateActionButton(BattleActionType actionType, string label, Color color, float angle)
  141. {
  142. var button = new Button();
  143. button.name = $"ActionButton_{actionType}";
  144. button.text = label;
  145. // Calculate position on circle
  146. float radian = angle * Mathf.Deg2Rad;
  147. float x = Mathf.Cos(radian) * (wheelRadius * 0.7f);
  148. float y = Mathf.Sin(radian) * (wheelRadius * 0.7f);
  149. // Style the button
  150. button.style.position = Position.Absolute;
  151. button.style.width = buttonSize;
  152. button.style.height = buttonSize;
  153. button.style.left = wheelRadius + x - buttonSize / 2;
  154. button.style.top = wheelRadius + y - buttonSize / 2;
  155. button.style.borderTopLeftRadius = buttonSize / 2;
  156. button.style.borderTopRightRadius = buttonSize / 2;
  157. button.style.borderBottomLeftRadius = buttonSize / 2;
  158. button.style.borderBottomRightRadius = buttonSize / 2;
  159. button.style.backgroundColor = color;
  160. button.style.color = Color.white;
  161. button.style.fontSize = 12;
  162. button.style.unityTextAlign = TextAnchor.MiddleCenter;
  163. button.style.borderBottomColor = Color.white;
  164. button.style.borderBottomWidth = 2;
  165. button.style.borderTopColor = Color.white;
  166. button.style.borderTopWidth = 2;
  167. button.style.borderLeftColor = Color.white;
  168. button.style.borderLeftWidth = 2;
  169. button.style.borderRightColor = Color.white;
  170. button.style.borderRightWidth = 2;
  171. // Add hover effects
  172. button.RegisterCallback<MouseEnterEvent>(evt =>
  173. {
  174. button.style.scale = new Scale(new Vector3(1.1f, 1.1f, 1f));
  175. button.style.backgroundColor = Color.Lerp(color, Color.white, 0.3f);
  176. });
  177. button.RegisterCallback<MouseLeaveEvent>(evt =>
  178. {
  179. button.style.scale = new Scale(Vector3.one);
  180. button.style.backgroundColor = color;
  181. });
  182. // Handle button click
  183. button.clicked += () =>
  184. {
  185. OnActionButtonClicked(actionType);
  186. };
  187. wheelContainer.Add(button);
  188. actionButtons.Add(new ActionButtonElement(button, actionType));
  189. }
  190. private void OnActionButtonClicked(BattleActionType actionType)
  191. {
  192. Debug.Log($"🎯 Action selected: {actionType}");
  193. OnActionSelected?.Invoke(actionType);
  194. HideWheel();
  195. }
  196. public void ShowWheelForCharacter(Character character)
  197. {
  198. if (character == null)
  199. {
  200. Debug.LogWarning("Cannot show action wheel: character is null");
  201. return;
  202. }
  203. currentCharacter = character;
  204. SetVisible(true);
  205. Debug.Log($"🎮 Action wheel shown for {character.CharacterName}");
  206. }
  207. public void HideWheel()
  208. {
  209. SetVisible(false);
  210. OnWheelClosed?.Invoke();
  211. Debug.Log("🎮 Action wheel hidden");
  212. }
  213. private void SetVisible(bool visible)
  214. {
  215. isVisible = visible;
  216. if (root != null)
  217. {
  218. root.style.display = visible ? DisplayStyle.Flex : DisplayStyle.None;
  219. }
  220. }
  221. private Character FindSelectedCharacter()
  222. {
  223. // Find the currently selected character
  224. // This could be done through various methods - checking what's highlighted, etc.
  225. var characters = FindObjectsByType<Character>(FindObjectsSortMode.None);
  226. foreach (var character in characters)
  227. {
  228. if (character.CompareTag("Player"))
  229. {
  230. // For now, return the first player character found
  231. // In a real implementation, you'd check which one is actually selected
  232. return character;
  233. }
  234. }
  235. return null;
  236. }
  237. void OnDestroy()
  238. {
  239. // Clean up events
  240. OnActionSelected = null;
  241. OnWheelClosed = null;
  242. }
  243. }