| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- using UnityEngine;
- using System.Collections.Generic;
- using System.Linq;
- /// <summary>
- /// Tracks active fights between runners and monsters
- /// Provides fight data for UI display and camera zoom operations
- /// </summary>
- public class FightTracker : MonoBehaviour
- {
- [SerializeField] private float fightDisplayDuration = 3f; // How long to display fights after they end
- // Internal fight tracking structure
- private class ActiveFight
- {
- public AIAgent runner;
- public Monster monster;
- public MazeRoom room;
- public float startTime;
- public float endTime = float.MaxValue; // While fighting, this is MaxValue
- public bool isActive => endTime == float.MaxValue;
- }
- private List<ActiveFight> activeFights = new();
- private Dictionary<(AIAgent, Monster), ActiveFight> fightLookup = new();
- private static FightTracker instance;
- public static FightTracker Instance
- {
- get
- {
- if (instance == null)
- {
- var go = new GameObject("FightTracker");
- instance = go.AddComponent<FightTracker>();
- }
- return instance;
- }
- }
- /// <summary>
- /// Called when a runner starts fighting a monster
- /// </summary>
- public void StartFight(AIAgent runner, Monster monster)
- {
- if (runner == null || monster == null) return;
- if (runner.IsDead || monster.IsDead) return;
- var key = (runner, monster);
- if (fightLookup.ContainsKey(key)) return; // Already tracking this fight
- var fight = new ActiveFight
- {
- runner = runner,
- monster = monster,
- room = monster.HomeRoom,
- startTime = Time.time
- };
- activeFights.Add(fight);
- fightLookup[key] = fight;
- }
- /// <summary>
- /// Called when a fight ends (runner or monster dies, or they separate)
- /// </summary>
- public void EndFight(AIAgent runner, Monster monster)
- {
- if (runner == null || monster == null) return;
- var key = (runner, monster);
- if (fightLookup.TryGetValue(key, out var fight))
- {
- fight.endTime = Time.time;
- fightLookup.Remove(key);
- }
- }
- /// <summary>
- /// Gets all fights that should currently be displayed (active + recent)
- /// </summary>
- public List<FightData> GetDisplayFights()
- {
- var displayFights = new List<FightData>();
- // Clean up old completed fights and null entries
- activeFights.RemoveAll(f =>
- {
- // Remove if either fighter was destroyed
- if (f.runner == null || f.monster == null)
- return true;
- float timeSinceEnd = Time.time - f.endTime;
- return !f.isActive && timeSinceEnd > fightDisplayDuration;
- });
- // Convert to display format and sort
- foreach (var fight in activeFights)
- {
- // Skip if either fighter is null (shouldn't happen due to RemoveAll, but safe)
- if (fight.runner == null || fight.monster == null)
- continue;
- displayFights.Add(new FightData
- {
- runnerName = fight.runner.AgentName,
- runnerId = fight.runner.AgentId,
- monsterType = $"Monster_{fight.monster.GetHashCode()}",
- room = fight.room,
- isActive = fight.isActive,
- timeSinceEnd = fight.isActive ? 0f : Time.time - fight.endTime,
- runner = fight.runner,
- monster = fight.monster
- });
- }
- // Sort by number of participants in same room (descending), then by active status
- displayFights = displayFights
- .OrderByDescending(f => CountFightsInRoom(f.room))
- .ThenByDescending(f => f.isActive)
- .ToList();
- return displayFights;
- }
- /// <summary>
- /// Count how many fights are happening in a specific room
- /// </summary>
- private int CountFightsInRoom(MazeRoom room)
- {
- return activeFights.Count(f => f.room.Id == room.Id);
- }
- /// <summary>
- /// Gets total number of fighters in a room (runners + monsters)
- /// </summary>
- public int GetFighterCountInRoom(MazeRoom room)
- {
- var fightersInRoom = activeFights.Where(f => f.room.Id == room.Id).ToList();
- var uniqueRunners = new HashSet<AIAgent>(fightersInRoom.Select(f => f.runner));
- var uniqueMonsters = new HashSet<Monster>(fightersInRoom.Select(f => f.monster));
- return uniqueRunners.Count + uniqueMonsters.Count;
- }
- void Awake()
- {
- if (instance == null)
- {
- instance = this;
- DontDestroyOnLoad(gameObject);
- }
- else if (instance != this)
- {
- Destroy(gameObject);
- }
- }
- void Update()
- {
- // Periodically clean up dead fighters
- activeFights.RemoveAll(f => f.runner == null || f.runner.IsDead || f.monster == null || f.monster.IsDead);
- }
- }
- /// <summary>
- /// Display-friendly fight data
- /// </summary>
- public struct FightData
- {
- public string runnerName;
- public int runnerId;
- public string monsterType;
- public MazeRoom room;
- public bool isActive;
- public float timeSinceEnd;
- public AIAgent runner;
- public Monster monster;
- public string GetDisplayText()
- {
- return $"{runnerName} vs {monsterType}";
- }
- public string GetRoomInfo()
- {
- return $"Room {room.Id}";
- }
- }
|