BattleItemSelector.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. using UnityEngine;
  2. using UnityEngine.UIElements;
  3. using System.Collections.Generic;
  4. using System;
  5. /// <summary>
  6. /// UI Toolkit-based item selection UI for battle
  7. /// </summary>
  8. public class BattleItemSelector : MonoBehaviour
  9. {
  10. [Header("UI References")]
  11. public UIDocument uiDocument;
  12. [Header("Settings")]
  13. public int maxItemsToShow = 10;
  14. private Character currentCharacter;
  15. private VisualElement rootElement;
  16. private VisualElement container;
  17. private VisualElement itemList;
  18. private Label titleLabel;
  19. private Label characterLabel;
  20. private VisualElement noItemsContainer;
  21. private Button cancelButton;
  22. private Button closeButton;
  23. // Events
  24. public event Action<string, int> OnItemSelected;
  25. public event Action OnSelectionCancelled;
  26. void Awake()
  27. {
  28. if (uiDocument == null)
  29. uiDocument = GetComponent<UIDocument>();
  30. if (uiDocument == null)
  31. {
  32. // Create UIDocument if it doesn't exist
  33. uiDocument = gameObject.AddComponent<UIDocument>();
  34. }
  35. }
  36. void Start()
  37. {
  38. InitializeUI();
  39. SetVisible(false);
  40. }
  41. void Update()
  42. {
  43. if (container != null && container.style.display == DisplayStyle.Flex)
  44. {
  45. if (Input.GetKeyDown(KeyCode.Escape))
  46. {
  47. OnSelectionCancelled?.Invoke();
  48. HideSelection();
  49. }
  50. }
  51. }
  52. private void InitializeUI()
  53. {
  54. // Load UXML and USS
  55. var visualTreeAsset = Resources.Load<VisualTreeAsset>("UI/ItemSelectionUI");
  56. var styleSheet = Resources.Load<StyleSheet>("UI/ItemSelectionUI");
  57. Debug.Log($"🔍 Loading UXML: {(visualTreeAsset != null ? "✅ Found" : "❌ Not Found")}");
  58. Debug.Log($"🔍 Loading USS: {(styleSheet != null ? "✅ Found" : "❌ Not Found")}");
  59. // Try simple version if main version fails
  60. if (visualTreeAsset == null)
  61. {
  62. Debug.LogWarning("Main UXML failed, trying simple version...");
  63. visualTreeAsset = Resources.Load<VisualTreeAsset>("UI/ItemSelectionUI_Simple");
  64. Debug.Log($"🔍 Loading Simple UXML: {(visualTreeAsset != null ? "✅ Found" : "❌ Not Found")}");
  65. }
  66. if (visualTreeAsset == null)
  67. {
  68. Debug.LogError("Could not load any ItemSelectionUI.uxml from Resources/UI/");
  69. CreateFallbackUI();
  70. return;
  71. }
  72. rootElement = uiDocument.rootVisualElement;
  73. rootElement.Clear();
  74. // Clone the visual tree
  75. var clonedTree = visualTreeAsset.CloneTree();
  76. rootElement.Add(clonedTree);
  77. // Apply styles
  78. if (styleSheet != null)
  79. {
  80. rootElement.styleSheets.Add(styleSheet);
  81. }
  82. // Get UI elements
  83. container = rootElement.Q<VisualElement>("ItemSelectionContainer");
  84. itemList = rootElement.Q<VisualElement>("ItemList");
  85. titleLabel = rootElement.Q<Label>("TitleLabel");
  86. characterLabel = rootElement.Q<Label>("CharacterLabel");
  87. noItemsContainer = rootElement.Q<VisualElement>("NoItemsContainer");
  88. cancelButton = rootElement.Q<Button>("CancelButton");
  89. closeButton = rootElement.Q<Button>("CloseButton");
  90. // Debug element finding
  91. Debug.Log($"🔍 Elements found:");
  92. Debug.Log($" - container: {(container != null ? "✅" : "❌")}");
  93. Debug.Log($" - itemList: {(itemList != null ? "✅" : "❌")}");
  94. Debug.Log($" - titleLabel: {(titleLabel != null ? "✅" : "❌")}");
  95. Debug.Log($" - characterLabel: {(characterLabel != null ? "✅" : "❌")}");
  96. Debug.Log($" - noItemsContainer: {(noItemsContainer != null ? "✅" : "❌")}");
  97. Debug.Log($" - cancelButton: {(cancelButton != null ? "✅" : "❌")}");
  98. Debug.Log($" - closeButton: {(closeButton != null ? "✅" : "❌")}");
  99. // Setup event handlers
  100. if (cancelButton != null)
  101. {
  102. cancelButton.clicked += () =>
  103. {
  104. OnSelectionCancelled?.Invoke();
  105. HideSelection();
  106. };
  107. }
  108. if (closeButton != null)
  109. {
  110. closeButton.clicked += () =>
  111. {
  112. OnSelectionCancelled?.Invoke();
  113. HideSelection();
  114. };
  115. }
  116. Debug.Log("✅ BattleItemSelector initialized with UI Toolkit");
  117. }
  118. private void CreateFallbackUI()
  119. {
  120. Debug.LogWarning("Creating fallback BattleItemSelector UI");
  121. rootElement = uiDocument.rootVisualElement;
  122. rootElement.Clear();
  123. // Create basic container
  124. container = new VisualElement();
  125. container.name = "ItemSelectionContainer";
  126. container.style.position = Position.Absolute;
  127. container.style.top = 0;
  128. container.style.left = 0;
  129. container.style.right = 0;
  130. container.style.bottom = 0;
  131. container.style.backgroundColor = new Color(0, 0, 0, 0.7f);
  132. container.style.alignItems = Align.Center;
  133. container.style.justifyContent = Justify.Center;
  134. // Create modal
  135. var modal = new VisualElement();
  136. modal.style.backgroundColor = new Color(0.18f, 0.18f, 0.18f, 1f);
  137. modal.style.borderTopWidth = modal.style.borderBottomWidth = modal.style.borderLeftWidth = modal.style.borderRightWidth = 2;
  138. modal.style.borderTopColor = modal.style.borderBottomColor = modal.style.borderLeftColor = modal.style.borderRightColor = Color.gray;
  139. modal.style.borderTopLeftRadius = modal.style.borderTopRightRadius = modal.style.borderBottomLeftRadius = modal.style.borderBottomRightRadius = 8;
  140. modal.style.width = 400;
  141. modal.style.height = 500;
  142. modal.style.paddingTop = modal.style.paddingBottom = modal.style.paddingLeft = modal.style.paddingRight = 15;
  143. // Title
  144. titleLabel = new Label("Select Item");
  145. titleLabel.style.fontSize = 18;
  146. titleLabel.style.color = Color.white;
  147. titleLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
  148. titleLabel.style.marginBottom = 10;
  149. titleLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
  150. // Character label
  151. characterLabel = new Label();
  152. characterLabel.style.fontSize = 16;
  153. characterLabel.style.color = new Color(1f, 0.86f, 0.39f);
  154. characterLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
  155. characterLabel.style.marginBottom = 15;
  156. characterLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
  157. // Item list
  158. var scrollView = new ScrollView();
  159. scrollView.style.flexGrow = 1;
  160. scrollView.style.marginBottom = 15;
  161. itemList = new VisualElement();
  162. scrollView.Add(itemList);
  163. Debug.Log("🔧 Fallback UI: itemList created successfully");
  164. // No items message
  165. noItemsContainer = new VisualElement();
  166. noItemsContainer.style.alignItems = Align.Center;
  167. noItemsContainer.style.justifyContent = Justify.Center;
  168. noItemsContainer.style.flexGrow = 1;
  169. noItemsContainer.style.display = DisplayStyle.None;
  170. var noItemsLabel = new Label("No usable items available");
  171. noItemsLabel.style.color = new Color(0.6f, 0.6f, 0.6f);
  172. noItemsContainer.Add(noItemsLabel);
  173. // Cancel button
  174. cancelButton = new Button(() =>
  175. {
  176. OnSelectionCancelled?.Invoke();
  177. HideSelection();
  178. });
  179. cancelButton.text = "Cancel";
  180. cancelButton.style.paddingTop = cancelButton.style.paddingBottom = 8;
  181. cancelButton.style.paddingLeft = cancelButton.style.paddingRight = 16;
  182. // Assemble UI
  183. modal.Add(titleLabel);
  184. modal.Add(characterLabel);
  185. modal.Add(scrollView);
  186. modal.Add(noItemsContainer);
  187. modal.Add(cancelButton);
  188. container.Add(modal);
  189. rootElement.Add(container);
  190. }
  191. public void ShowItemSelection(Character character)
  192. {
  193. Debug.Log($"📦 ShowItemSelection called for {character.CharacterName}");
  194. Debug.Log($"📦 UI State - itemList: {(itemList != null ? "✅" : "❌")}, container: {(container != null ? "✅" : "❌")}");
  195. if (itemList == null)
  196. {
  197. Debug.LogError("❌ itemList is null - reinitializing UI");
  198. InitializeUI();
  199. }
  200. currentCharacter = character;
  201. if (characterLabel != null)
  202. characterLabel.text = $"{character.CharacterName}";
  203. if (titleLabel != null)
  204. titleLabel.text = "Select Item";
  205. PopulateItemList();
  206. SetVisible(true);
  207. Debug.Log($"📦 Item selection shown for {character.CharacterName}");
  208. }
  209. public void HideSelection()
  210. {
  211. SetVisible(false);
  212. ClearItemList();
  213. currentCharacter = null;
  214. Debug.Log("📦 Item selection hidden");
  215. }
  216. private void SetVisible(bool visible)
  217. {
  218. if (container != null)
  219. {
  220. container.style.display = visible ? DisplayStyle.Flex : DisplayStyle.None;
  221. }
  222. }
  223. private void PopulateItemList()
  224. {
  225. Debug.Log($"📦 PopulateItemList called - itemList null: {itemList == null}");
  226. ClearItemList();
  227. var items = GetCharacterItems();
  228. Debug.Log($"📦 Found {items.Count} items to display");
  229. if (items.Count == 0)
  230. {
  231. if (noItemsContainer != null)
  232. noItemsContainer.style.display = DisplayStyle.Flex;
  233. return;
  234. }
  235. if (noItemsContainer != null)
  236. noItemsContainer.style.display = DisplayStyle.None;
  237. for (int i = 0; i < items.Count && i < maxItemsToShow; i++)
  238. {
  239. CreateItemButton(items[i], i);
  240. }
  241. }
  242. private void CreateItemButton(ItemData item, int index)
  243. {
  244. // Safety check to prevent NullReferenceException
  245. if (itemList == null)
  246. {
  247. Debug.LogError("❌ itemList is null! UI initialization may have failed.");
  248. return;
  249. }
  250. var button = new Button();
  251. button.AddToClassList("item-button");
  252. // Item name
  253. var nameLabel = new Label(item.name);
  254. nameLabel.AddToClassList("item-name");
  255. // Item description
  256. var descLabel = new Label(item.description);
  257. descLabel.AddToClassList("item-description");
  258. button.Add(nameLabel);
  259. button.Add(descLabel);
  260. button.clicked += () =>
  261. {
  262. OnItemSelected?.Invoke(item.name, index);
  263. HideSelection();
  264. };
  265. itemList.Add(button);
  266. }
  267. private void ClearItemList()
  268. {
  269. if (itemList != null)
  270. {
  271. itemList.Clear();
  272. }
  273. }
  274. private List<ItemData> GetCharacterItems()
  275. {
  276. // Placeholder implementation - return sample items
  277. // TODO: Get actual items from character's inventory
  278. return new List<ItemData>
  279. {
  280. new ItemData { name = "Health Potion", description = "Restores 50 HP" },
  281. new ItemData { name = "Mana Potion", description = "Restores 30 MP" },
  282. new ItemData { name = "Antidote", description = "Cures poison" },
  283. new ItemData { name = "Strength Elixir", description = "+3 Str for 5 rounds" },
  284. new ItemData { name = "Magic Scroll", description = "Casts Magic Missile" }
  285. };
  286. }
  287. [System.Serializable]
  288. public class ItemData
  289. {
  290. public string name;
  291. public string description;
  292. public int quantity = 1;
  293. public bool isUsable = true;
  294. }
  295. void OnDestroy()
  296. {
  297. OnItemSelected = null;
  298. OnSelectionCancelled = null;
  299. }
  300. }