| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656 |
- using UnityEngine;
- using UnityEngine.UIElements;
- using System.Collections.Generic;
- using System.Linq;
- #if UNITY_EDITOR
- using UnityEditor;
- #endif
- /// <summary>
- /// Manages the Game Over screen with statistics and final results using UI Toolkit
- /// Shows when all player characters die
- /// </summary>
- public class GameOverScreen : MonoBehaviour
- {
- [Header("UI Toolkit Settings")]
- public UIDocument uiDocument;
- public VisualTreeAsset gameOverTemplate;
- public PanelSettings panelSettings;
- [Header("Statistics Settings")]
- public bool showDetailedStats = true;
- [Header("Audio")]
- public AudioClip gameOverMusic;
- public AudioClip defeatSound;
- private GameStatistics gameStats;
- private VisualElement rootElement;
- [System.Serializable]
- public class GameStatistics
- {
- [Header("Time & Travel")]
- public float totalPlayTime = 0f;
- public float totalTravelTime = 0f;
- public int daysTravaeled = 0;
- public int locationsVisited = 0;
- [Header("Combat")]
- public int battlesWon = 0;
- public int battlesLost = 0;
- public int enemiesSlain = 0;
- public int totalDamageDealt = 0;
- public int totalDamageTaken = 0;
- [Header("Social & Quests")]
- public int peopleHelped = 0;
- public int peopleSaved = 0;
- public int questsCompleted = 0;
- public int questsFailed = 0;
- [Header("Character Development")]
- public int finalFameLevel = 0;
- public int totalExperienceGained = 0;
- public int levelsGained = 0;
- [Header("Economic")]
- public int totalGoldEarned = 0;
- public int totalGoldSpent = 0;
- public int itemsBought = 0;
- public int itemsSold = 0;
- [Header("Survival")]
- public int charactersLost = 0;
- public int timesRested = 0;
- public int healthPotionsUsed = 0;
- public GameStatistics()
- {
- // Initialize with default values
- }
- /// <summary>
- /// Calculate derived statistics
- /// </summary>
- public int GetTotalBattles() => battlesWon + battlesLost;
- public float GetWinRate() => GetTotalBattles() > 0 ? (float)battlesWon / GetTotalBattles() * 100f : 0f;
- public int GetNetGold() => totalGoldEarned - totalGoldSpent;
- public float GetDamageRatio() => totalDamageTaken > 0 ? (float)totalDamageDealt / totalDamageTaken : 0f;
- }
- void Awake()
- {
- // Initialize game statistics
- gameStats = new GameStatistics();
- // Set up UI Document component
- SetupUIDocument();
- if (uiDocument != null && uiDocument.visualTreeAsset != null)
- {
- rootElement = uiDocument.rootVisualElement;
- // Hide game over panel initially
- if (rootElement != null)
- rootElement.style.display = DisplayStyle.None;
- // Set up button events
- SetupUICallbacks();
- }
- }
- /// <summary>
- /// Set up the UIDocument component with proper references
- /// </summary>
- private void SetupUIDocument()
- {
- // Get or create UIDocument component
- if (uiDocument == null)
- uiDocument = GetComponent<UIDocument>();
- if (uiDocument == null)
- uiDocument = gameObject.AddComponent<UIDocument>();
- // Load the UXML template if not assigned
- if (gameOverTemplate == null)
- {
- gameOverTemplate = Resources.Load<VisualTreeAsset>("UI/BattleSceneUI/GameOverScreen");
- if (gameOverTemplate == null)
- {
- #if UNITY_EDITOR
- // Try alternative path in editor
- gameOverTemplate = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/UI/BattleSceneUI/GameOverScreen.uxml");
- #endif
- }
- }
- // Load panel settings if not assigned
- if (panelSettings == null)
- {
- panelSettings = Resources.Load<PanelSettings>("MainSettings");
- if (panelSettings == null)
- {
- // Try alternative panel settings
- panelSettings = Resources.Load<PanelSettings>("UI/TravelPanelSettings");
- if (panelSettings == null)
- {
- // Try to find any PanelSettings in the project
- var allPanelSettings = Resources.FindObjectsOfTypeAll<PanelSettings>();
- if (allPanelSettings.Length > 0)
- panelSettings = allPanelSettings[0];
- }
- }
- }
- // Configure the UIDocument
- if (uiDocument != null)
- {
- uiDocument.visualTreeAsset = gameOverTemplate;
- uiDocument.panelSettings = panelSettings;
- // Load and apply stylesheet
- var stylesheet = Resources.Load<StyleSheet>("UI/BattleSceneUI/GameOverScreen");
- if (stylesheet == null)
- {
- #if UNITY_EDITOR
- stylesheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/UI/BattleSceneUI/GameOverScreen.uss");
- #endif
- }
- if (stylesheet != null && uiDocument.rootVisualElement != null)
- {
- uiDocument.rootVisualElement.styleSheets.Add(stylesheet);
- }
- if (gameOverTemplate == null)
- {
- Debug.LogError("GameOverScreen: Could not load GameOverScreen.uxml template!");
- }
- if (panelSettings == null)
- {
- Debug.LogWarning("GameOverScreen: No PanelSettings found. UI may not display correctly.");
- }
- }
- }
- /// <summary>
- /// Set up UI element callbacks for the game over interface
- /// </summary>
- private void SetupUICallbacks()
- {
- if (rootElement == null) return;
- // Set up Restart Game button
- var restartButton = rootElement.Q<Button>("RestartButton");
- if (restartButton != null)
- {
- restartButton.clicked += RestartGame;
- }
- // Set up Main Menu button
- var mainMenuButton = rootElement.Q<Button>("MainMenuButton");
- if (mainMenuButton != null)
- {
- mainMenuButton.clicked += ReturnToMainMenu;
- }
- // Set up keyboard input for space key (restart)
- rootElement.RegisterCallback<KeyDownEvent>(OnKeyDown);
- // Make sure the root element can receive focus for keyboard events
- rootElement.focusable = true;
- }
- /// <summary>
- /// Handle keyboard input for the game over UI
- /// </summary>
- private void OnKeyDown(KeyDownEvent evt)
- {
- if (evt.keyCode == KeyCode.Space || evt.keyCode == KeyCode.Return)
- {
- RestartGame();
- }
- else if (evt.keyCode == KeyCode.Escape)
- {
- ReturnToMainMenu();
- }
- }
- /// <summary>
- /// Show the game over screen with current statistics
- /// </summary>
- public void ShowGameOver(List<GameObject> defeatedPlayers = null)
- {
- // Calculate final statistics
- CalculateFinalStatistics(defeatedPlayers);
- // Show the panel
- if (rootElement != null)
- {
- rootElement.style.display = DisplayStyle.Flex;
- rootElement.Focus(); // Allow keyboard input
- Time.timeScale = 0f; // Pause the game
- }
- // Update UI elements
- UpdateGameOverUI();
- // Play audio
- PlayGameOverAudio();
- Debug.Log("💀 Game Over screen displayed");
- }
- /// <summary>
- /// Calculate final statistics before showing game over
- /// </summary>
- private void CalculateFinalStatistics(List<GameObject> defeatedPlayers)
- {
- // Calculate total play time
- gameStats.totalPlayTime = Time.time;
- // Calculate characters lost
- if (defeatedPlayers != null)
- {
- gameStats.charactersLost = defeatedPlayers.Count;
- }
- // Try to get additional stats from game systems
- GatherStatisticsFromSystems();
- Debug.Log($"💀 Final statistics calculated - {gameStats.enemiesSlain} enemies slain, {gameStats.battlesWon} battles won");
- }
- /// <summary>
- /// Gather statistics from various game systems
- /// </summary>
- private void GatherStatisticsFromSystems()
- {
- // Try to get stats from GameManager if available
- var gameManager = GameManager.Instance;
- if (gameManager != null)
- {
- // Count enemies slain (this battle)
- var allEnemies = gameManager.enemyCharacters;
- gameStats.enemiesSlain += allEnemies.Count(enemy =>
- {
- var character = enemy?.GetComponent<Character>();
- return character != null && character.IsDead;
- });
- }
- // Try to get travel statistics
- GatherTravelStatistics();
- // Try to get combat statistics
- GatherCombatStatistics();
- // Try to get social statistics
- GatherSocialStatistics();
- }
- /// <summary>
- /// Gather travel-related statistics
- /// </summary>
- private void GatherTravelStatistics()
- {
- // TODO: Integrate with travel system when available
- // For now, use placeholder values
- gameStats.daysTravaeled = Mathf.RoundToInt(gameStats.totalPlayTime / 60f); // Rough estimate
- gameStats.locationsVisited = Random.Range(5, 15); // Placeholder
- }
- /// <summary>
- /// Gather combat-related statistics
- /// </summary>
- private void GatherCombatStatistics()
- {
- // TODO: Integrate with combat statistics system when available
- // For now, estimate based on current battle
- gameStats.battlesLost = 1; // This battle was lost
- gameStats.totalDamageDealt = Random.Range(50, 200); // Placeholder
- gameStats.totalDamageTaken = Random.Range(100, 300); // Placeholder
- }
- /// <summary>
- /// Gather social and quest statistics
- /// </summary>
- private void GatherSocialStatistics()
- {
- // TODO: Integrate with quest and social systems when available
- gameStats.peopleHelped = Random.Range(0, 5); // Placeholder
- gameStats.questsCompleted = Random.Range(0, 3); // Placeholder
- gameStats.questsFailed = Random.Range(0, 2); // Placeholder
- gameStats.finalFameLevel = Random.Range(1, 5); // Placeholder
- }
- /// <summary>
- /// Update the game over UI with statistics using UI Toolkit
- /// </summary>
- private void UpdateGameOverUI()
- {
- if (rootElement == null) return;
- // Update title
- var titleLabel = rootElement.Q<Label>("GameOverTitle");
- if (titleLabel != null)
- {
- titleLabel.text = "GAME OVER";
- }
- // Populate statistics sections
- PopulateStatisticsUI();
- }
- /// <summary>
- /// Populate all statistics sections in the UI
- /// </summary>
- private void PopulateStatisticsUI()
- {
- // Time & Travel Statistics
- PopulateTimeAndTravelStats();
- // Combat Statistics
- PopulateCombatStats();
- // Social & Quest Statistics
- PopulateSocialStats();
- // Assessment
- PopulateAssessment();
- }
- /// <summary>
- /// Populate time and travel statistics
- /// </summary>
- private void PopulateTimeAndTravelStats()
- {
- var playTimeLabel = rootElement.Q<Label>("PlayTimeValue");
- if (playTimeLabel != null)
- playTimeLabel.text = FormatTime(gameStats.totalPlayTime);
- var daysLabel = rootElement.Q<Label>("DaysTraveledValue");
- if (daysLabel != null)
- daysLabel.text = gameStats.daysTravaeled.ToString();
- var locationsLabel = rootElement.Q<Label>("LocationsVisitedValue");
- if (locationsLabel != null)
- locationsLabel.text = gameStats.locationsVisited.ToString();
- }
- /// <summary>
- /// Populate combat statistics
- /// </summary>
- private void PopulateCombatStats()
- {
- var battlesWonLabel = rootElement.Q<Label>("BattlesWonValue");
- if (battlesWonLabel != null)
- battlesWonLabel.text = gameStats.battlesWon.ToString();
- var battlesLostLabel = rootElement.Q<Label>("BattlesLostValue");
- if (battlesLostLabel != null)
- battlesLostLabel.text = gameStats.battlesLost.ToString();
- var winRateLabel = rootElement.Q<Label>("WinRateValue");
- if (winRateLabel != null)
- winRateLabel.text = $"{gameStats.GetWinRate():F1}%";
- var enemiesSlainLabel = rootElement.Q<Label>("EnemiesSlainValue");
- if (enemiesSlainLabel != null)
- enemiesSlainLabel.text = gameStats.enemiesSlain.ToString();
- var damageDealtLabel = rootElement.Q<Label>("DamageDealtValue");
- if (damageDealtLabel != null)
- damageDealtLabel.text = gameStats.totalDamageDealt.ToString();
- var damageTakenLabel = rootElement.Q<Label>("DamageTakenValue");
- if (damageTakenLabel != null)
- damageTakenLabel.text = gameStats.totalDamageTaken.ToString();
- var charactersLostLabel = rootElement.Q<Label>("CharactersLostValue");
- if (charactersLostLabel != null)
- charactersLostLabel.text = gameStats.charactersLost.ToString();
- }
- /// <summary>
- /// Populate social and quest statistics
- /// </summary>
- private void PopulateSocialStats()
- {
- var peopleHelpedLabel = rootElement.Q<Label>("PeopleHelpedValue");
- if (peopleHelpedLabel != null)
- peopleHelpedLabel.text = gameStats.peopleHelped.ToString();
- var livesSavedLabel = rootElement.Q<Label>("LivesSavedValue");
- if (livesSavedLabel != null)
- livesSavedLabel.text = gameStats.peopleSaved.ToString();
- var questsCompletedLabel = rootElement.Q<Label>("QuestsCompletedValue");
- if (questsCompletedLabel != null)
- questsCompletedLabel.text = gameStats.questsCompleted.ToString();
- var questsFailedLabel = rootElement.Q<Label>("QuestsFailedValue");
- if (questsFailedLabel != null)
- questsFailedLabel.text = gameStats.questsFailed.ToString();
- var fameLevelLabel = rootElement.Q<Label>("FameLevelValue");
- if (fameLevelLabel != null)
- fameLevelLabel.text = gameStats.finalFameLevel.ToString();
- var goldEarnedLabel = rootElement.Q<Label>("GoldEarnedValue");
- if (goldEarnedLabel != null)
- goldEarnedLabel.text = gameStats.totalGoldEarned.ToString();
- var goldSpentLabel = rootElement.Q<Label>("GoldSpentValue");
- if (goldSpentLabel != null)
- goldSpentLabel.text = gameStats.totalGoldSpent.ToString();
- var netWorthLabel = rootElement.Q<Label>("NetWorthValue");
- if (netWorthLabel != null)
- netWorthLabel.text = gameStats.GetNetGold().ToString();
- }
- /// <summary>
- /// Populate the final assessment section
- /// </summary>
- private void PopulateAssessment()
- {
- var assessmentLabel = rootElement.Q<Label>("AssessmentText");
- if (assessmentLabel != null)
- assessmentLabel.text = GetFinalMessage();
- }
- /// <summary>
- /// Generate the statistics text for display
- /// </summary>
- private string GenerateStatisticsText()
- {
- var stats = new System.Text.StringBuilder();
- stats.AppendLine("=== FINAL STATISTICS ===\n");
- // Time & Travel
- stats.AppendLine("📅 JOURNEY SUMMARY");
- stats.AppendLine($"Total Play Time: {FormatTime(gameStats.totalPlayTime)}");
- stats.AppendLine($"Days Traveled: {gameStats.daysTravaeled}");
- stats.AppendLine($"Locations Visited: {gameStats.locationsVisited}");
- stats.AppendLine();
- // Combat
- stats.AppendLine("⚔️ COMBAT RECORD");
- stats.AppendLine($"Battles Won: {gameStats.battlesWon}");
- stats.AppendLine($"Battles Lost: {gameStats.battlesLost}");
- stats.AppendLine($"Win Rate: {gameStats.GetWinRate():F1}%");
- stats.AppendLine($"Enemies Slain: {gameStats.enemiesSlain}");
- if (showDetailedStats)
- {
- stats.AppendLine($"Damage Dealt: {gameStats.totalDamageDealt}");
- stats.AppendLine($"Damage Taken: {gameStats.totalDamageTaken}");
- }
- stats.AppendLine();
- // Social & Quests
- stats.AppendLine("🤝 SOCIAL IMPACT");
- stats.AppendLine($"People Helped: {gameStats.peopleHelped}");
- stats.AppendLine($"Lives Saved: {gameStats.peopleSaved}");
- stats.AppendLine($"Quests Completed: {gameStats.questsCompleted}");
- stats.AppendLine($"Quests Failed: {gameStats.questsFailed}");
- stats.AppendLine($"Final Fame Level: {gameStats.finalFameLevel}");
- stats.AppendLine();
- // Character Development
- if (showDetailedStats)
- {
- stats.AppendLine("📈 CHARACTER GROWTH");
- stats.AppendLine($"Experience Gained: {gameStats.totalExperienceGained}");
- stats.AppendLine($"Levels Gained: {gameStats.levelsGained}");
- stats.AppendLine($"Characters Lost: {gameStats.charactersLost}");
- stats.AppendLine();
- }
- // Economic
- stats.AppendLine("💰 ECONOMIC SUMMARY");
- stats.AppendLine($"Gold Earned: {gameStats.totalGoldEarned}");
- stats.AppendLine($"Gold Spent: {gameStats.totalGoldSpent}");
- stats.AppendLine($"Net Worth: {gameStats.GetNetGold()}");
- // Final message
- stats.AppendLine();
- stats.AppendLine(GetFinalMessage());
- return stats.ToString();
- }
- /// <summary>
- /// Get a final message based on performance
- /// </summary>
- private string GetFinalMessage()
- {
- float winRate = gameStats.GetWinRate();
- int heroicScore = gameStats.peopleHelped + gameStats.peopleSaved + gameStats.questsCompleted;
- if (winRate >= 80f && heroicScore >= 10)
- return "You died as a legendary hero, remembered for ages!";
- else if (winRate >= 60f && heroicScore >= 5)
- return "You fought valiantly and helped many before falling.";
- else if (gameStats.enemiesSlain >= 10)
- return "Though you fell, your enemies remember your fierce combat.";
- else if (heroicScore >= 3)
- return "Your kind deeds will be remembered by those you helped.";
- else if (gameStats.daysTravaeled >= 10)
- return "You traveled far but met an unfortunate end.";
- else
- return "Your adventure was brief but not without purpose.";
- }
- /// <summary>
- /// Format time in minutes and seconds
- /// </summary>
- private string FormatTime(float timeInSeconds)
- {
- int minutes = Mathf.FloorToInt(timeInSeconds / 60f);
- int seconds = Mathf.FloorToInt(timeInSeconds % 60f);
- return $"{minutes:D2}:{seconds:D2}";
- }
- /// <summary>
- /// Play game over audio
- /// </summary>
- private void PlayGameOverAudio()
- {
- var audioSource = GetComponent<AudioSource>();
- if (audioSource != null)
- {
- if (defeatSound != null)
- {
- audioSource.PlayOneShot(defeatSound);
- }
- if (gameOverMusic != null)
- {
- audioSource.clip = gameOverMusic;
- audioSource.loop = true;
- audioSource.Play();
- }
- }
- }
- /// <summary>
- /// Restart the game
- /// </summary>
- private void RestartGame()
- {
- Time.timeScale = 1f; // Resume time
- Debug.Log("💀 Restarting game...");
- // TODO: Implement proper game restart logic
- // For now, reload the current scene
- UnityEngine.SceneManagement.SceneManager.LoadScene(
- UnityEngine.SceneManagement.SceneManager.GetActiveScene().name
- );
- }
- /// <summary>
- /// Return to main menu
- /// </summary>
- private void ReturnToMainMenu()
- {
- Time.timeScale = 1f; // Resume time
- Debug.Log("💀 Returning to main menu...");
- // TODO: Load main menu scene
- // For now, just hide the game over screen
- if (rootElement != null)
- rootElement.style.display = DisplayStyle.None;
- }
- /// <summary>
- /// Hide the game over screen (for testing)
- /// </summary>
- public void HideGameOver()
- {
- if (rootElement != null)
- rootElement.style.display = DisplayStyle.None;
- Time.timeScale = 1f;
- }
- /// <summary>
- /// Update a specific statistic
- /// </summary>
- public void UpdateStatistic(string statName, int value)
- {
- switch (statName.ToLower())
- {
- case "enemiesslain":
- gameStats.enemiesSlain += value;
- break;
- case "battlewon":
- gameStats.battlesWon += value;
- break;
- case "battleslost":
- gameStats.battlesLost += value;
- break;
- case "peoplehelped":
- gameStats.peopleHelped += value;
- break;
- case "questscompleted":
- gameStats.questsCompleted += value;
- break;
- case "goldearned":
- gameStats.totalGoldEarned += value;
- break;
- default:
- Debug.LogWarning($"Unknown statistic: {statName}");
- break;
- }
- }
- /// <summary>
- /// Get current statistics (for external access)
- /// </summary>
- public GameStatistics GetStatistics()
- {
- return gameStats;
- }
- }
|