|
|
@@ -0,0 +1,214 @@
|
|
|
+using UnityEngine;
|
|
|
+using UnityEngine.UIElements;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+
|
|
|
+/// <summary>
|
|
|
+/// Displays active fights in the UI with zoom buttons
|
|
|
+/// Shows runner vs monster fights, sorted by fight intensity (participants in room)
|
|
|
+/// </summary>
|
|
|
+public class ActiveFightsUIPanel : MonoBehaviour
|
|
|
+{
|
|
|
+ [Header("Settings")]
|
|
|
+ [SerializeField] private float updateInterval = 0.5f;
|
|
|
+
|
|
|
+ private VisualElement root;
|
|
|
+ private VisualElement fightsList;
|
|
|
+ private Dictionary<string, VisualElement> fightEntries = new();
|
|
|
+ private float lastUpdateTime = 0f;
|
|
|
+
|
|
|
+ void Start()
|
|
|
+ {
|
|
|
+ InitializeUI();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void InitializeUI()
|
|
|
+ {
|
|
|
+ // Find or create UIDocument
|
|
|
+ var uiDocument = FindAnyObjectByType<UIDocument>();
|
|
|
+ if (uiDocument == null)
|
|
|
+ {
|
|
|
+ var docGO = new GameObject("UIDocument");
|
|
|
+ uiDocument = docGO.AddComponent<UIDocument>();
|
|
|
+ }
|
|
|
+
|
|
|
+ root = uiDocument.rootVisualElement;
|
|
|
+
|
|
|
+ // Create the fights panel container
|
|
|
+ var panelContainer = new VisualElement();
|
|
|
+ panelContainer.name = "ActiveFightsPanel";
|
|
|
+ panelContainer.style.position = Position.Absolute;
|
|
|
+ panelContainer.style.left = 20; // Left side instead of right
|
|
|
+ panelContainer.style.top = 20;
|
|
|
+ panelContainer.style.width = 350;
|
|
|
+ // Limit height so the list scrolls instead of growing off-screen
|
|
|
+ panelContainer.style.maxHeight = new StyleLength(new Length(85, LengthUnit.Percent));
|
|
|
+ panelContainer.style.backgroundColor = new Color(0.1f, 0.1f, 0.1f, 0.8f);
|
|
|
+ panelContainer.style.borderBottomLeftRadius = 5;
|
|
|
+ panelContainer.style.borderBottomRightRadius = 5;
|
|
|
+ panelContainer.style.borderTopLeftRadius = 5;
|
|
|
+ panelContainer.style.borderTopRightRadius = 5;
|
|
|
+ panelContainer.style.paddingBottom = 10;
|
|
|
+ panelContainer.style.paddingTop = 10;
|
|
|
+ panelContainer.style.paddingLeft = 10;
|
|
|
+ panelContainer.style.paddingRight = 10;
|
|
|
+ panelContainer.style.flexDirection = FlexDirection.Column;
|
|
|
+
|
|
|
+ // Title
|
|
|
+ var title = new Label("Active Fights");
|
|
|
+ title.style.fontSize = 16;
|
|
|
+ title.style.color = Color.white;
|
|
|
+ title.style.marginBottom = 10;
|
|
|
+ title.style.unityFontStyleAndWeight = FontStyle.Bold;
|
|
|
+ title.style.flexShrink = 0;
|
|
|
+ panelContainer.Add(title);
|
|
|
+
|
|
|
+ // Scrollable container so the list doesn't overflow the screen
|
|
|
+ var scrollView = new ScrollView(ScrollViewMode.Vertical);
|
|
|
+ scrollView.name = "FightsScrollView";
|
|
|
+ scrollView.style.flexGrow = 1;
|
|
|
+ scrollView.style.flexShrink = 1;
|
|
|
+ scrollView.horizontalScrollerVisibility = ScrollerVisibility.Hidden;
|
|
|
+ scrollView.verticalScrollerVisibility = ScrollerVisibility.Auto;
|
|
|
+
|
|
|
+ // Fights list container (lives inside the ScrollView)
|
|
|
+ fightsList = new VisualElement();
|
|
|
+ fightsList.name = "FightsList";
|
|
|
+ fightsList.style.flexDirection = FlexDirection.Column;
|
|
|
+ scrollView.Add(fightsList);
|
|
|
+
|
|
|
+ panelContainer.Add(scrollView);
|
|
|
+
|
|
|
+ root.Add(panelContainer);
|
|
|
+ }
|
|
|
+
|
|
|
+ void Update()
|
|
|
+ {
|
|
|
+ if (FightTracker.Instance == null) return;
|
|
|
+ if (fightsList == null) return;
|
|
|
+ if (Time.time - lastUpdateTime < updateInterval) return;
|
|
|
+ lastUpdateTime = Time.time;
|
|
|
+
|
|
|
+ RefreshFightsList();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Updates the list of displayed fights
|
|
|
+ /// </summary>
|
|
|
+ private void RefreshFightsList()
|
|
|
+ {
|
|
|
+ var fights = FightTracker.Instance.GetDisplayFights();
|
|
|
+ var currentFightIds = new HashSet<string>();
|
|
|
+
|
|
|
+ // Update or create entries for current fights
|
|
|
+ foreach (var fight in fights)
|
|
|
+ {
|
|
|
+ string fightId = $"{fight.runnerId}_{fight.monster.GetHashCode()}";
|
|
|
+ currentFightIds.Add(fightId);
|
|
|
+
|
|
|
+ if (fightEntries.ContainsKey(fightId))
|
|
|
+ {
|
|
|
+ // Update existing entry
|
|
|
+ UpdateFightEntry(fightEntries[fightId], fight);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Create new entry
|
|
|
+ var entryElement = CreateFightEntry(fight, fightId);
|
|
|
+ fightEntries[fightId] = entryElement;
|
|
|
+ fightsList.Add(entryElement);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Remove entries for fights that are no longer active
|
|
|
+ var entriesToRemove = fightEntries.Keys.Where(id => !currentFightIds.Contains(id)).ToList();
|
|
|
+ foreach (var id in entriesToRemove)
|
|
|
+ {
|
|
|
+ if (fightEntries[id] != null)
|
|
|
+ {
|
|
|
+ fightEntries[id].RemoveFromHierarchy();
|
|
|
+ }
|
|
|
+ fightEntries.Remove(id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Creates a single fight entry UI element
|
|
|
+ /// </summary>
|
|
|
+ private VisualElement CreateFightEntry(FightData fight, string fightId)
|
|
|
+ {
|
|
|
+ var entryContainer = new VisualElement();
|
|
|
+ entryContainer.name = $"FightEntry_{fightId}";
|
|
|
+ entryContainer.style.flexDirection = FlexDirection.Row;
|
|
|
+ entryContainer.style.backgroundColor = new Color(0.2f, 0.2f, 0.2f, 0.9f);
|
|
|
+ entryContainer.style.borderBottomLeftRadius = 3;
|
|
|
+ entryContainer.style.borderBottomRightRadius = 3;
|
|
|
+ entryContainer.style.borderTopLeftRadius = 3;
|
|
|
+ entryContainer.style.borderTopRightRadius = 3;
|
|
|
+ entryContainer.style.paddingBottom = 5;
|
|
|
+ entryContainer.style.paddingTop = 5;
|
|
|
+ entryContainer.style.paddingLeft = 8;
|
|
|
+ entryContainer.style.paddingRight = 8;
|
|
|
+ entryContainer.style.marginBottom = 5;
|
|
|
+ entryContainer.style.alignItems = Align.Center;
|
|
|
+
|
|
|
+ // Status indicator
|
|
|
+ var statusDot = new VisualElement();
|
|
|
+ statusDot.style.width = 12;
|
|
|
+ statusDot.style.height = 12;
|
|
|
+ statusDot.style.borderBottomLeftRadius = 6;
|
|
|
+ statusDot.style.borderBottomRightRadius = 6;
|
|
|
+ statusDot.style.borderTopLeftRadius = 6;
|
|
|
+ statusDot.style.borderTopRightRadius = 6;
|
|
|
+ statusDot.style.backgroundColor = fight.isActive ? Color.red : new Color(1f, 0.5f, 0f);
|
|
|
+ statusDot.style.marginRight = 8;
|
|
|
+ entryContainer.Add(statusDot);
|
|
|
+
|
|
|
+ // Fight text
|
|
|
+ var fightText = new Label(fight.GetDisplayText());
|
|
|
+ fightText.style.color = Color.white;
|
|
|
+ fightText.style.fontSize = 12;
|
|
|
+ fightText.style.flexGrow = 1;
|
|
|
+ entryContainer.Add(fightText);
|
|
|
+
|
|
|
+ // Zoom button
|
|
|
+ var zoomButton = new Button(() => ZoomToFight(fight));
|
|
|
+ zoomButton.text = "Zoom";
|
|
|
+ zoomButton.style.width = 60;
|
|
|
+ zoomButton.style.height = 25;
|
|
|
+ zoomButton.style.backgroundColor = new Color(0.2f, 0.5f, 0.9f, 0.9f);
|
|
|
+ zoomButton.style.color = Color.white;
|
|
|
+ zoomButton.style.fontSize = 11;
|
|
|
+ zoomButton.style.marginLeft = 8;
|
|
|
+ entryContainer.Add(zoomButton);
|
|
|
+
|
|
|
+ return entryContainer;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Updates an existing fight entry
|
|
|
+ /// </summary>
|
|
|
+ private void UpdateFightEntry(VisualElement entryElement, FightData fight)
|
|
|
+ {
|
|
|
+ if (entryElement == null) return;
|
|
|
+
|
|
|
+ // Update status dot color
|
|
|
+ var statusDot = entryElement.Q<VisualElement>(null, "unity-content-container")?.Children().FirstOrDefault() as VisualElement;
|
|
|
+ if (statusDot != null)
|
|
|
+ {
|
|
|
+ statusDot.style.backgroundColor = fight.isActive ? Color.red : new Color(1f, 0.5f, 0f);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Zooms the camera to the room where the fight is happening
|
|
|
+ /// </summary>
|
|
|
+ private void ZoomToFight(FightData fight)
|
|
|
+ {
|
|
|
+ var cameraController = FindAnyObjectByType<MazeCameraController>();
|
|
|
+ if (cameraController != null)
|
|
|
+ {
|
|
|
+ cameraController.ZoomToRoom(fight.room, 1.3f, 0.5f);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|