using UnityEngine; using UnityEngine.UIElements; using System.Collections.Generic; using System; /// /// Modern UI Toolkit-based action wheel for battle actions /// Uses UI Builder and USS for styling instead of legacy Canvas components /// public class UIToolkitActionWheel : MonoBehaviour { [Header("Settings")] public float wheelRadius = 150f; public float buttonSize = 80f; public KeyCode toggleKey = KeyCode.Q; private UIDocument uiDocument; private VisualElement root; private VisualElement wheelContainer; private List actionButtons = new List(); private Character currentCharacter; private bool isVisible = false; // Events public event Action OnActionSelected; public event Action OnWheelClosed; private class ActionButtonElement { public VisualElement element; public BattleActionType actionType; public bool isEnabled = true; public ActionButtonElement(VisualElement element, BattleActionType actionType) { this.element = element; this.actionType = actionType; } } void Awake() { // Get or create UIDocument uiDocument = GetComponent(); if (uiDocument == null) { uiDocument = gameObject.AddComponent(); } CreateActionWheelUI(); } void Start() { SetVisible(false); } void Update() { if (Input.GetKeyDown(toggleKey)) { if (isVisible) { HideWheel(); } else { // Find selected character var selectedCharacter = FindSelectedCharacter(); if (selectedCharacter != null) { ShowWheelForCharacter(selectedCharacter); } } } if (isVisible && Input.GetKeyDown(KeyCode.Escape)) { HideWheel(); } } private void CreateActionWheelUI() { // Create the root UI structure programmatically root = new VisualElement(); root.name = "ActionWheelRoot"; root.style.position = Position.Absolute; root.style.width = Length.Percent(100); root.style.height = Length.Percent(100); root.style.justifyContent = Justify.Center; root.style.alignItems = Align.Center; // Create wheel container wheelContainer = new VisualElement(); wheelContainer.name = "WheelContainer"; wheelContainer.style.width = wheelRadius * 2; wheelContainer.style.height = wheelRadius * 2; wheelContainer.style.position = Position.Relative; // Add background circle var background = new VisualElement(); background.name = "WheelBackground"; background.style.width = Length.Percent(100); background.style.height = Length.Percent(100); background.style.borderTopLeftRadius = wheelRadius; background.style.borderTopRightRadius = wheelRadius; background.style.borderBottomLeftRadius = wheelRadius; background.style.borderBottomRightRadius = wheelRadius; background.style.backgroundColor = new Color(0, 0, 0, 0.3f); background.style.borderBottomColor = Color.white; background.style.borderBottomWidth = 2; background.style.borderTopColor = Color.white; background.style.borderTopWidth = 2; background.style.borderLeftColor = Color.white; background.style.borderLeftWidth = 2; background.style.borderRightColor = Color.white; background.style.borderRightWidth = 2; wheelContainer.Add(background); // Create action buttons CreateActionButtons(); root.Add(wheelContainer); // Set the visual tree if (uiDocument.visualTreeAsset == null) { uiDocument.rootVisualElement.Add(root); } } private void CreateActionButtons() { var actionDefinitions = new[] { new { type = BattleActionType.Attack, label = "โš”๏ธ\nAttack", color = new Color(1f, 0.3f, 0.3f) }, new { type = BattleActionType.Move, label = "๐Ÿ‘Ÿ\nMove", color = new Color(0.3f, 1f, 0.3f) }, new { type = BattleActionType.UseItem, label = "๐Ÿงช\nItem", color = new Color(0.3f, 0.3f, 1f) }, new { type = BattleActionType.CastSpell, label = "โœจ\nSpell", color = new Color(1f, 0.3f, 1f) }, new { type = BattleActionType.Defend, label = "๐Ÿ›ก๏ธ\nDefend", color = new Color(0.8f, 0.8f, 0.3f) }, new { type = BattleActionType.RunAway, label = "๐Ÿ’จ\nRun", color = new Color(0.6f, 0.6f, 0.6f) } }; int actionCount = actionDefinitions.Length; float angleStep = 360f / actionCount; for (int i = 0; i < actionCount; i++) { var actionDef = actionDefinitions[i]; float angle = i * angleStep - 90f; // Start from top CreateActionButton(actionDef.type, actionDef.label, actionDef.color, angle); } } private void CreateActionButton(BattleActionType actionType, string label, Color color, float angle) { var button = new Button(); button.name = $"ActionButton_{actionType}"; button.text = label; // Calculate position on circle float radian = angle * Mathf.Deg2Rad; float x = Mathf.Cos(radian) * (wheelRadius * 0.7f); float y = Mathf.Sin(radian) * (wheelRadius * 0.7f); // Style the button button.style.position = Position.Absolute; button.style.width = buttonSize; button.style.height = buttonSize; button.style.left = wheelRadius + x - buttonSize / 2; button.style.top = wheelRadius + y - buttonSize / 2; button.style.borderTopLeftRadius = buttonSize / 2; button.style.borderTopRightRadius = buttonSize / 2; button.style.borderBottomLeftRadius = buttonSize / 2; button.style.borderBottomRightRadius = buttonSize / 2; button.style.backgroundColor = color; button.style.color = Color.white; button.style.fontSize = 12; button.style.unityTextAlign = TextAnchor.MiddleCenter; button.style.borderBottomColor = Color.white; button.style.borderBottomWidth = 2; button.style.borderTopColor = Color.white; button.style.borderTopWidth = 2; button.style.borderLeftColor = Color.white; button.style.borderLeftWidth = 2; button.style.borderRightColor = Color.white; button.style.borderRightWidth = 2; // Add hover effects button.RegisterCallback(evt => { button.style.scale = new Scale(new Vector3(1.1f, 1.1f, 1f)); button.style.backgroundColor = Color.Lerp(color, Color.white, 0.3f); }); button.RegisterCallback(evt => { button.style.scale = new Scale(Vector3.one); button.style.backgroundColor = color; }); // Handle button click button.clicked += () => { OnActionButtonClicked(actionType); }; wheelContainer.Add(button); actionButtons.Add(new ActionButtonElement(button, actionType)); } private void OnActionButtonClicked(BattleActionType actionType) { OnActionSelected?.Invoke(actionType); HideWheel(); } public void ShowWheelForCharacter(Character character) { if (character == null) { return; } currentCharacter = character; SetVisible(true); } public void HideWheel() { SetVisible(false); OnWheelClosed?.Invoke(); } private void SetVisible(bool visible) { isVisible = visible; if (root != null) { root.style.display = visible ? DisplayStyle.Flex : DisplayStyle.None; } } private Character FindSelectedCharacter() { // Find the currently selected character // This could be done through various methods - checking what's highlighted, etc. var characters = FindObjectsByType(FindObjectsSortMode.None); foreach (var character in characters) { if (character.CompareTag("Player")) { // For now, return the first player character found // In a real implementation, you'd check which one is actually selected return character; } } return null; } void OnDestroy() { // Clean up events OnActionSelected = null; OnWheelClosed = null; } }