UIToolkitActionWheel.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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. }
  66. }
  67. if (isVisible && Input.GetKeyDown(KeyCode.Escape))
  68. {
  69. HideWheel();
  70. }
  71. }
  72. private void CreateActionWheelUI()
  73. {
  74. // Create the root UI structure programmatically
  75. root = new VisualElement();
  76. root.name = "ActionWheelRoot";
  77. root.style.position = Position.Absolute;
  78. root.style.width = Length.Percent(100);
  79. root.style.height = Length.Percent(100);
  80. root.style.justifyContent = Justify.Center;
  81. root.style.alignItems = Align.Center;
  82. // Create wheel container
  83. wheelContainer = new VisualElement();
  84. wheelContainer.name = "WheelContainer";
  85. wheelContainer.style.width = wheelRadius * 2;
  86. wheelContainer.style.height = wheelRadius * 2;
  87. wheelContainer.style.position = Position.Relative;
  88. // Add background circle
  89. var background = new VisualElement();
  90. background.name = "WheelBackground";
  91. background.style.width = Length.Percent(100);
  92. background.style.height = Length.Percent(100);
  93. background.style.borderTopLeftRadius = wheelRadius;
  94. background.style.borderTopRightRadius = wheelRadius;
  95. background.style.borderBottomLeftRadius = wheelRadius;
  96. background.style.borderBottomRightRadius = wheelRadius;
  97. background.style.backgroundColor = new Color(0, 0, 0, 0.3f);
  98. background.style.borderBottomColor = Color.white;
  99. background.style.borderBottomWidth = 2;
  100. background.style.borderTopColor = Color.white;
  101. background.style.borderTopWidth = 2;
  102. background.style.borderLeftColor = Color.white;
  103. background.style.borderLeftWidth = 2;
  104. background.style.borderRightColor = Color.white;
  105. background.style.borderRightWidth = 2;
  106. wheelContainer.Add(background);
  107. // Create action buttons
  108. CreateActionButtons();
  109. root.Add(wheelContainer);
  110. // Set the visual tree
  111. if (uiDocument.visualTreeAsset == null)
  112. {
  113. uiDocument.rootVisualElement.Add(root);
  114. }
  115. }
  116. private void CreateActionButtons()
  117. {
  118. var actionDefinitions = new[]
  119. {
  120. new { type = BattleActionType.Attack, label = "⚔️\nAttack", color = new Color(1f, 0.3f, 0.3f) },
  121. new { type = BattleActionType.Move, label = "👟\nMove", color = new Color(0.3f, 1f, 0.3f) },
  122. new { type = BattleActionType.UseItem, label = "🧪\nItem", color = new Color(0.3f, 0.3f, 1f) },
  123. new { type = BattleActionType.CastSpell, label = "✨\nSpell", color = new Color(1f, 0.3f, 1f) },
  124. new { type = BattleActionType.Defend, label = "🛡️\nDefend", color = new Color(0.8f, 0.8f, 0.3f) },
  125. new { type = BattleActionType.RunAway, label = "💨\nRun", color = new Color(0.6f, 0.6f, 0.6f) }
  126. };
  127. int actionCount = actionDefinitions.Length;
  128. float angleStep = 360f / actionCount;
  129. for (int i = 0; i < actionCount; i++)
  130. {
  131. var actionDef = actionDefinitions[i];
  132. float angle = i * angleStep - 90f; // Start from top
  133. CreateActionButton(actionDef.type, actionDef.label, actionDef.color, angle);
  134. }
  135. }
  136. private void CreateActionButton(BattleActionType actionType, string label, Color color, float angle)
  137. {
  138. var button = new Button();
  139. button.name = $"ActionButton_{actionType}";
  140. button.text = label;
  141. // Calculate position on circle
  142. float radian = angle * Mathf.Deg2Rad;
  143. float x = Mathf.Cos(radian) * (wheelRadius * 0.7f);
  144. float y = Mathf.Sin(radian) * (wheelRadius * 0.7f);
  145. // Style the button
  146. button.style.position = Position.Absolute;
  147. button.style.width = buttonSize;
  148. button.style.height = buttonSize;
  149. button.style.left = wheelRadius + x - buttonSize / 2;
  150. button.style.top = wheelRadius + y - buttonSize / 2;
  151. button.style.borderTopLeftRadius = buttonSize / 2;
  152. button.style.borderTopRightRadius = buttonSize / 2;
  153. button.style.borderBottomLeftRadius = buttonSize / 2;
  154. button.style.borderBottomRightRadius = buttonSize / 2;
  155. button.style.backgroundColor = color;
  156. button.style.color = Color.white;
  157. button.style.fontSize = 12;
  158. button.style.unityTextAlign = TextAnchor.MiddleCenter;
  159. button.style.borderBottomColor = Color.white;
  160. button.style.borderBottomWidth = 2;
  161. button.style.borderTopColor = Color.white;
  162. button.style.borderTopWidth = 2;
  163. button.style.borderLeftColor = Color.white;
  164. button.style.borderLeftWidth = 2;
  165. button.style.borderRightColor = Color.white;
  166. button.style.borderRightWidth = 2;
  167. // Add hover effects
  168. button.RegisterCallback<MouseEnterEvent>(evt =>
  169. {
  170. button.style.scale = new Scale(new Vector3(1.1f, 1.1f, 1f));
  171. button.style.backgroundColor = Color.Lerp(color, Color.white, 0.3f);
  172. });
  173. button.RegisterCallback<MouseLeaveEvent>(evt =>
  174. {
  175. button.style.scale = new Scale(Vector3.one);
  176. button.style.backgroundColor = color;
  177. });
  178. // Handle button click
  179. button.clicked += () =>
  180. {
  181. OnActionButtonClicked(actionType);
  182. };
  183. wheelContainer.Add(button);
  184. actionButtons.Add(new ActionButtonElement(button, actionType));
  185. }
  186. private void OnActionButtonClicked(BattleActionType actionType)
  187. {
  188. OnActionSelected?.Invoke(actionType);
  189. HideWheel();
  190. }
  191. public void ShowWheelForCharacter(Character character)
  192. {
  193. if (character == null)
  194. {
  195. return;
  196. }
  197. currentCharacter = character;
  198. SetVisible(true);
  199. }
  200. public void HideWheel()
  201. {
  202. SetVisible(false);
  203. OnWheelClosed?.Invoke();
  204. }
  205. private void SetVisible(bool visible)
  206. {
  207. isVisible = visible;
  208. if (root != null)
  209. {
  210. root.style.display = visible ? DisplayStyle.Flex : DisplayStyle.None;
  211. }
  212. }
  213. private Character FindSelectedCharacter()
  214. {
  215. // Find the currently selected character
  216. // This could be done through various methods - checking what's highlighted, etc.
  217. var characters = FindObjectsByType<Character>(FindObjectsSortMode.None);
  218. foreach (var character in characters)
  219. {
  220. if (character.CompareTag("Player"))
  221. {
  222. // For now, return the first player character found
  223. // In a real implementation, you'd check which one is actually selected
  224. return character;
  225. }
  226. }
  227. return null;
  228. }
  229. void OnDestroy()
  230. {
  231. // Clean up events
  232. OnActionSelected = null;
  233. OnWheelClosed = null;
  234. }
  235. }