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;
}
}