925 lines
35 KiB
C#
925 lines
35 KiB
C#
|
using UnityEngine;
|
||
|
using UnityEngine.UI;
|
||
|
using TMPro;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Collections;
|
||
|
|
||
|
namespace BulletHellTemplate
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Manages the user interface during gameplay, including player stats, skills, and input handling for both mobile and PC platforms.
|
||
|
/// </summary>
|
||
|
public class UIGameplay : MonoBehaviour
|
||
|
{
|
||
|
#region Mobile Controls
|
||
|
|
||
|
[Header("Mobile Controls")]
|
||
|
[Tooltip("Reference to the Joystick for mobile movement")]
|
||
|
public Joystick joystick; // Reference to the Joystick for mobile movement
|
||
|
|
||
|
[Header("Mobile Skill Joysticks")]
|
||
|
[Tooltip("Array to hold skill joysticks for mobile")]
|
||
|
public SkillJoystick[] skillJoysticks; // Array to hold skill joysticks for mobile
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region PC Controls
|
||
|
|
||
|
[Header("PC Controls")]
|
||
|
[Tooltip("Reference to the PC Input Controller")]
|
||
|
public PCInputController pcInputController; // Reference to the PC Input Controller
|
||
|
|
||
|
[Tooltip("Reference to the PC Skill Controller")]
|
||
|
public PCSkillController pcSkillController; // Reference to the PC Skill Controller
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
[Header("Skill Icons")]
|
||
|
[Tooltip("Array to hold skill images")]
|
||
|
public SkillImage[] skillImages;
|
||
|
|
||
|
[Header("Final Boss")]
|
||
|
[Tooltip("Final boss message GameObject")]
|
||
|
public GameObject finalBossMessage;
|
||
|
private MonsterEntity finalBossEntity;
|
||
|
private bool showBossHP;
|
||
|
[Tooltip("Time to close the final boss message")]
|
||
|
public float timeToCloseMessage = 3f;
|
||
|
|
||
|
[Header("Gameplay Rules Info")]
|
||
|
[Tooltip("Timer text")]
|
||
|
public TextMeshProUGUI timer;
|
||
|
[Tooltip("Monsters killed text")]
|
||
|
public TextMeshProUGUI monstersKilled;
|
||
|
[Tooltip("Gold gain text")]
|
||
|
public TextMeshProUGUI goldGain;
|
||
|
[Tooltip("Insufficient MP text")]
|
||
|
public TextMeshProUGUI insufficientMPText;
|
||
|
[Tooltip("Pause menu GameObject")]
|
||
|
public GameObject pauseMenu;
|
||
|
|
||
|
public Image minimapImage;
|
||
|
|
||
|
[Header("Upgrade Infos")]
|
||
|
[Tooltip("Perk entry prefab")]
|
||
|
public PerkEntry perkEntryPrefab;
|
||
|
[Tooltip("Perk container transform")]
|
||
|
public Transform perkContainer;
|
||
|
|
||
|
public Button openUpgradesButton;
|
||
|
public GameObject updateAvailable;
|
||
|
[Header("Skill Perk Images")]
|
||
|
[Tooltip("Array to hold skill perk images")]
|
||
|
public SkillsPerkImage[] skillPerkImages; // Array to hold skill perk images
|
||
|
|
||
|
[Header("Stat Perk Images")]
|
||
|
[Tooltip("Array to hold stat perk images")]
|
||
|
public StatPerkImage[] statPerkImages; // Array to hold stat perk images
|
||
|
|
||
|
[Header("Boss HP Bar")]
|
||
|
[Tooltip("Boss HP bar Image")]
|
||
|
public Image bossHpBar;
|
||
|
[Tooltip("Boss HP container GameObject")]
|
||
|
public GameObject bossHpContainer;
|
||
|
[Tooltip("Timer container GameObject")]
|
||
|
public GameObject timerContainer;
|
||
|
|
||
|
|
||
|
[Header("End Game Screen")]
|
||
|
[Tooltip("End game screen GameObject")]
|
||
|
public GameObject endGameScreen;
|
||
|
[Tooltip("End game message text")]
|
||
|
public TextMeshProUGUI endGameMessage;
|
||
|
[Tooltip("Victory objects to activate")]
|
||
|
public GameObject[] VictoryObjects;
|
||
|
[Tooltip("Defeat objects to activate")]
|
||
|
public GameObject[] DefeatObjects;
|
||
|
[Tooltip("Victory audio clip")]
|
||
|
public AudioClip VictoryAudio;
|
||
|
[Tooltip("Defeat audio clip")]
|
||
|
public AudioClip DefeatAudio;
|
||
|
|
||
|
[Header("Locked Perk Sprites")]
|
||
|
[Tooltip("Sprite for locked skills")]
|
||
|
public Sprite lockedSkillSprite;
|
||
|
[Tooltip("Sprite for locked stats")]
|
||
|
public Sprite lockedStatSprite;
|
||
|
[Tooltip("Sprite for unlocked slots")]
|
||
|
public Sprite unlockedSprite;
|
||
|
|
||
|
|
||
|
|
||
|
[Header("UI Character Info")]
|
||
|
public Image characterIcon;
|
||
|
[Tooltip("Health bar Image")]
|
||
|
public Image hpBar;
|
||
|
[Tooltip("Mana bar Image")]
|
||
|
public Image mpBar;
|
||
|
[Tooltip("Experience bar Image")]
|
||
|
public Image xpBar;
|
||
|
[Tooltip("Current text")]
|
||
|
public TextMeshProUGUI hpCurrent;
|
||
|
public TextMeshProUGUI energyCurrent;
|
||
|
public TextMeshProUGUI xpCurrent;
|
||
|
|
||
|
[Tooltip("Level text")]
|
||
|
public TextMeshProUGUI level;
|
||
|
[Tooltip("Health text")]
|
||
|
public TextMeshProUGUI hpText;
|
||
|
[Tooltip("Health regeneration text")]
|
||
|
public TextMeshProUGUI hpRegenText;
|
||
|
[Tooltip("Health leech text")]
|
||
|
public TextMeshProUGUI hpLeechText;
|
||
|
[Tooltip("Mana text")]
|
||
|
public TextMeshProUGUI mpText;
|
||
|
[Tooltip("Mana regeneration text")]
|
||
|
public TextMeshProUGUI mpRegenText;
|
||
|
[Tooltip("Damage text")]
|
||
|
public TextMeshProUGUI damageText;
|
||
|
[Tooltip("Attack speed text")]
|
||
|
public TextMeshProUGUI attackSpeedText;
|
||
|
[Tooltip("Cooldown reduction text")]
|
||
|
public TextMeshProUGUI cooldownReductionText;
|
||
|
[Tooltip("Critical rate text")]
|
||
|
public TextMeshProUGUI criticalRateText;
|
||
|
[Tooltip("Critical damage multiplier text")]
|
||
|
public TextMeshProUGUI criticalDamageMultiplierText;
|
||
|
[Tooltip("Defense text")]
|
||
|
public TextMeshProUGUI defenseText;
|
||
|
[Tooltip("Shield text")]
|
||
|
public TextMeshProUGUI shieldText;
|
||
|
[Tooltip("Move speed text")]
|
||
|
public TextMeshProUGUI moveSpeedText;
|
||
|
[Tooltip("Collect range text")]
|
||
|
public TextMeshProUGUI collectRangeText;
|
||
|
|
||
|
private CharacterEntity characterEntity;
|
||
|
private float currentHp;
|
||
|
private bool isUpdatingHpBar = false;
|
||
|
private int upgradeAmount = 0;
|
||
|
|
||
|
public static UIGameplay Singleton { get; private set; } // Singleton instance
|
||
|
|
||
|
private void Awake()
|
||
|
{
|
||
|
// Implement singleton pattern
|
||
|
if (Singleton == null)
|
||
|
{
|
||
|
Singleton = this;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Destroy(gameObject);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void Start()
|
||
|
{
|
||
|
StartCoroutine(InitializeUpgradeButton());
|
||
|
StartCoroutine(BlinkGameObjectWhileUpgrading(updateAvailable));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Attempts to initialize the upgrade button when GameplayManager is ready.
|
||
|
/// </summary>
|
||
|
private IEnumerator InitializeUpgradeButton()
|
||
|
{
|
||
|
// Keep trying until GameplayManager is available
|
||
|
while (GameplayManager.Singleton == null)
|
||
|
{
|
||
|
yield return null; // Wait for the next frame
|
||
|
}
|
||
|
|
||
|
// Check the upgrade mode and set up the button accordingly
|
||
|
if (openUpgradesButton != null && GameplayManager.Singleton.upgradeMode == GameplayManager.UpgradeMode.UpgradeOnButtonClick)
|
||
|
{
|
||
|
openUpgradesButton.interactable = false;
|
||
|
openUpgradesButton.onClick.AddListener(OnClickToChoicePowerUp);
|
||
|
}
|
||
|
else if (openUpgradesButton != null)
|
||
|
{
|
||
|
openUpgradesButton.gameObject.SetActive(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Update()
|
||
|
{
|
||
|
if (characterEntity != null)
|
||
|
{
|
||
|
// Mobile movement using joystick
|
||
|
if (joystick != null)
|
||
|
{
|
||
|
Vector3 direction = new Vector3(joystick.Horizontal, 0, joystick.Vertical);
|
||
|
characterEntity.Move(direction); // Pass the joystick direction
|
||
|
}
|
||
|
|
||
|
|
||
|
UpdateUI(); // Update the UI with the latest character stats
|
||
|
}
|
||
|
|
||
|
// Update timer and other UI elements
|
||
|
timer.text = GameplayManager.Singleton.GetFormattedTime();
|
||
|
monstersKilled.text = GameplayManager.Singleton.GetMonstersKilled().ToString();
|
||
|
goldGain.text = GameplayManager.Singleton.GetGainGold().ToString();
|
||
|
|
||
|
// Update skill cooldowns
|
||
|
UpdateSkillCooldowns();
|
||
|
|
||
|
if (characterEntity != null)
|
||
|
{
|
||
|
// Mobile aiming with skill joysticks
|
||
|
if (skillJoysticks != null)
|
||
|
{
|
||
|
foreach (var skillJoystick in skillJoysticks)
|
||
|
{
|
||
|
if (skillJoystick != null)
|
||
|
{
|
||
|
Vector3 direction = new Vector3(skillJoystick.Horizontal, 0, skillJoystick.Vertical);
|
||
|
characterEntity.UpdateDirectionalAim(new Vector2(direction.x, direction.z),skillJoystick.skillIndex);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (showBossHP)
|
||
|
{
|
||
|
if (finalBossEntity != null)
|
||
|
{
|
||
|
bossHpBar.fillAmount = finalBossEntity.GetCurrentHP() / finalBossEntity.GetMaxHP();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bossHpBar.fillAmount = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Shows the final boss message and triggers camera shake.
|
||
|
/// </summary>
|
||
|
public void ShowFinalBossMessage()
|
||
|
{
|
||
|
if (finalBossMessage != null)
|
||
|
{
|
||
|
finalBossMessage.SetActive(true);
|
||
|
StartCoroutine(HideFinalBossMessageAfterDelay(timeToCloseMessage));
|
||
|
if (TopDownCameraController.Singleton != null)
|
||
|
{
|
||
|
TopDownCameraController.Singleton.TriggerCameraShake();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
private IEnumerator HideFinalBossMessageAfterDelay(float delay)
|
||
|
{
|
||
|
yield return new WaitForSeconds(delay);
|
||
|
finalBossMessage.SetActive(false);
|
||
|
timerContainer.SetActive(false);
|
||
|
showBossHP = true;
|
||
|
bossHpContainer.SetActive(true);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Displays the power-up choices when leveling up.
|
||
|
/// </summary>
|
||
|
public void OnLevelUpChoicePowerUp()
|
||
|
{
|
||
|
foreach (Transform child in perkContainer)
|
||
|
{
|
||
|
Destroy(child.gameObject);
|
||
|
}
|
||
|
|
||
|
List<object> perks = GameplayManager.Singleton.GetRandomPerks();
|
||
|
|
||
|
foreach (var perk in perks)
|
||
|
{
|
||
|
PerkEntry perkEntry = Instantiate(perkEntryPrefab, perkContainer);
|
||
|
|
||
|
if (perk is SkillPerkData skillPerk)
|
||
|
{
|
||
|
perkEntry.SetupEntry(skillPerk);
|
||
|
}
|
||
|
else if (perk is StatPerkData statPerk)
|
||
|
{
|
||
|
perkEntry.SetupEntry(statPerk);
|
||
|
}
|
||
|
else if (perk is SkillData baseSkill)
|
||
|
{
|
||
|
perkEntry.SetupEntry(baseSkill);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pauseMenu.SetActive(true);
|
||
|
}
|
||
|
public void AddUpgradePoints()
|
||
|
{
|
||
|
upgradeAmount++;
|
||
|
openUpgradesButton.interactable = true;
|
||
|
}
|
||
|
public void OnClickToChoicePowerUp()
|
||
|
{
|
||
|
|
||
|
if (upgradeAmount > 0)
|
||
|
{
|
||
|
GameplayManager.Singleton.TogglePause();
|
||
|
OnLevelUpChoicePowerUp();
|
||
|
upgradeAmount--;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.Log("No upgrades available to choose.");
|
||
|
CloseChoicePowerUp();
|
||
|
}
|
||
|
}
|
||
|
/// <summary>
|
||
|
/// Continuously checks upgradeAmount and makes a GameObject blink when upgradeAmount is greater than 0.
|
||
|
/// </summary>
|
||
|
/// <param name="targetObject">The GameObject to blink.</param>
|
||
|
public IEnumerator BlinkGameObjectWhileUpgrading(GameObject targetObject)
|
||
|
{
|
||
|
if (targetObject == null)
|
||
|
{
|
||
|
Debug.LogWarning("Target GameObject is null. Cannot blink.");
|
||
|
yield break;
|
||
|
}
|
||
|
bool initialActiveState = targetObject.activeSelf;
|
||
|
|
||
|
while (true) // Loop for the duration of the game
|
||
|
{
|
||
|
if (upgradeAmount > 0)
|
||
|
{
|
||
|
targetObject.SetActive(!targetObject.activeSelf);
|
||
|
yield return new WaitForSeconds(0.5f);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!targetObject.activeSelf != initialActiveState)
|
||
|
{
|
||
|
targetObject.SetActive(initialActiveState);
|
||
|
}
|
||
|
yield return null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Automatically selects a random power-up for the player.
|
||
|
/// </summary>
|
||
|
public void OnRandomChoicePowerUp()
|
||
|
{
|
||
|
// Get shuffled perks
|
||
|
List<object> perks = GameplayManager.Singleton.GetRandomPerks();
|
||
|
|
||
|
if (perks.Count > 0)
|
||
|
{
|
||
|
// Choose a random perk
|
||
|
object randomPerk = perks[Random.Range(0, perks.Count)];
|
||
|
|
||
|
// Apply the chosen perk
|
||
|
if (randomPerk is SkillPerkData skillPerk)
|
||
|
{
|
||
|
int currentLevel = GameplayManager.Singleton.GetSkillLevel(skillPerk);
|
||
|
if (currentLevel < skillPerk.maxLevel)
|
||
|
{
|
||
|
GameplayManager.Singleton.SetPerkLevel(skillPerk); // Set the new level
|
||
|
characterEntity.ApplySkillPerk(skillPerk); // Apply the perk
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning($"SkillPerk {skillPerk.name} is already at max level.");
|
||
|
}
|
||
|
}
|
||
|
else if (randomPerk is StatPerkData statPerk)
|
||
|
{
|
||
|
int currentLevel = GameplayManager.Singleton.GetPerkLevel(statPerk);
|
||
|
if (currentLevel < GameplayManager.Singleton.maxLevelStatPerks)
|
||
|
{
|
||
|
GameplayManager.Singleton.SetPerkLevel(statPerk); // Set the new level
|
||
|
characterEntity.ApplyStatPerk(statPerk, currentLevel + 1); // Apply the stat perk
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning($"StatPerk {statPerk.statType} is already at max level.");
|
||
|
}
|
||
|
}
|
||
|
else if (randomPerk is SkillData baseSkill)
|
||
|
{
|
||
|
int currentLevel = GameplayManager.Singleton.GetBaseSkillLevel(baseSkill);
|
||
|
if (currentLevel < baseSkill.skillLevels.Count - 1)
|
||
|
{
|
||
|
GameplayManager.Singleton.LevelUpBaseSkill(baseSkill); // Level up the base skill
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning($"BaseSkill {baseSkill.skillName} is already at max level.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Update UI
|
||
|
UpdateSkillPerkUI();
|
||
|
UpdateStatPerkUI();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning("No perks available to choose from.");
|
||
|
}
|
||
|
|
||
|
CloseChoicePowerUp();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Closes the power-up choice menu and re-enables the button if there are remaining upgrades.
|
||
|
/// </summary>
|
||
|
public void CloseChoicePowerUp()
|
||
|
{
|
||
|
// Clear existing perks in the UI
|
||
|
foreach (Transform child in perkContainer)
|
||
|
{
|
||
|
Destroy(child.gameObject);
|
||
|
}
|
||
|
|
||
|
// Handle button interaction for UpgradeOnButtonClick mode
|
||
|
if (GameplayManager.Singleton.upgradeMode == GameplayManager.UpgradeMode.UpgradeOnButtonClick)
|
||
|
{
|
||
|
openUpgradesButton.interactable = upgradeAmount > 0; // Enable if upgrades remain, disable otherwise
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
openUpgradesButton.interactable = false; // Always disable in other modes
|
||
|
}
|
||
|
|
||
|
// Handle pause logic for UpgradeOnLevelUp mode
|
||
|
if (GameplayManager.Singleton.upgradeMode == GameplayManager.UpgradeMode.UpgradeOnLevelUp || GameplayManager.Singleton.upgradeMode == GameplayManager.UpgradeMode.UpgradeOnButtonClick)
|
||
|
{
|
||
|
GameplayManager.Singleton.TogglePause();
|
||
|
}
|
||
|
|
||
|
// Hide the pause menu
|
||
|
pauseMenu.SetActive(false);
|
||
|
|
||
|
// Update the UI
|
||
|
UpdateSkillPerkUI();
|
||
|
UpdateSkillIcons();
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// Sets the final boss entity for HP tracking.
|
||
|
/// </summary>
|
||
|
/// <param name="boss">The final boss monster entity.</param>
|
||
|
public void SetFinalBoss(MonsterEntity boss)
|
||
|
{
|
||
|
finalBossEntity = boss;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Updates the skill perk UI elements.
|
||
|
/// </summary>
|
||
|
public void UpdateSkillPerkUI()
|
||
|
{
|
||
|
if (characterEntity != null && skillPerkImages != null)
|
||
|
{
|
||
|
for (int i = 0; i < skillPerkImages.Length; i++)
|
||
|
{
|
||
|
SkillsPerkImage perkImage = skillPerkImages[i];
|
||
|
|
||
|
if (i < characterEntity.GetSkillsPerkData().Count)
|
||
|
{
|
||
|
// Display active skill perks
|
||
|
SkillPerkData skillPerk = characterEntity.GetSkillsPerkData()[i];
|
||
|
int perkLevel = GameplayManager.Singleton.GetSkillLevel(skillPerk);
|
||
|
|
||
|
// Set the perk icon
|
||
|
perkImage.perkIcon.sprite = skillPerk.icon;
|
||
|
perkImage.perkLevel.text = perkLevel.ToString();
|
||
|
|
||
|
// Activate max level icon if the skill perk is evolved
|
||
|
bool isEvolved = (perkLevel >= skillPerk.maxLevel) && skillPerk.hasEvolution && characterEntity.HasStatPerk(skillPerk.perkRequireToEvolveSkill);
|
||
|
perkImage.maxLevelPerkIcon.gameObject.SetActive(isEvolved);
|
||
|
}
|
||
|
else if (i < GameplayManager.Singleton.maxSkills)
|
||
|
{
|
||
|
// Available slot but no skill assigned
|
||
|
perkImage.perkIcon.sprite = unlockedSprite;
|
||
|
perkImage.perkLevel.text = "";
|
||
|
perkImage.maxLevelPerkIcon.gameObject.SetActive(false);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Locked slots
|
||
|
perkImage.perkIcon.sprite = lockedSkillSprite;
|
||
|
perkImage.perkLevel.text = "";
|
||
|
perkImage.maxLevelPerkIcon.gameObject.SetActive(false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// Updates the stat perk UI elements.
|
||
|
/// </summary>
|
||
|
public void UpdateStatPerkUI()
|
||
|
{
|
||
|
if (characterEntity != null && statPerkImages != null)
|
||
|
{
|
||
|
for (int i = 0; i < statPerkImages.Length; i++)
|
||
|
{
|
||
|
StatPerkImage statPerkImage = statPerkImages[i];
|
||
|
|
||
|
if (i < characterEntity.GetStatsPerkData().Count)
|
||
|
{
|
||
|
// Display active stat perks
|
||
|
StatPerkData statPerk = characterEntity.GetStatsPerkData()[i];
|
||
|
int perkLevel = GameplayManager.Singleton.GetPerkLevel(statPerk);
|
||
|
|
||
|
// Set the stat perk icon
|
||
|
statPerkImage.perkIcon.sprite = statPerk.icon;
|
||
|
statPerkImage.perkLevel.text = perkLevel.ToString();
|
||
|
|
||
|
// Activate max level icon if the stat perk reaches max level
|
||
|
bool isMaxLevel = perkLevel >= GameplayManager.Singleton.maxLevelStatPerks;
|
||
|
statPerkImage.maxLevelStatIcon.gameObject.SetActive(isMaxLevel);
|
||
|
}
|
||
|
else if (i < GameplayManager.Singleton.maxStats)
|
||
|
{
|
||
|
// Available slot but no stat assigned
|
||
|
statPerkImage.perkIcon.sprite = unlockedSprite;
|
||
|
statPerkImage.perkLevel.text = "";
|
||
|
statPerkImage.maxLevelStatIcon.gameObject.SetActive(false);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Locked slots
|
||
|
statPerkImage.perkIcon.sprite = lockedStatSprite;
|
||
|
statPerkImage.perkLevel.text = "";
|
||
|
statPerkImage.maxLevelStatIcon.gameObject.SetActive(false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// Sets the character entity and initializes related components.
|
||
|
/// </summary>
|
||
|
/// <param name="entity">The character entity to set.</param>
|
||
|
public void SetCharacterEntity(CharacterEntity entity)
|
||
|
{
|
||
|
characterEntity = entity;
|
||
|
|
||
|
if (skillJoysticks != null)
|
||
|
{
|
||
|
foreach (SkillJoystick skillJoystick in skillJoysticks)
|
||
|
{
|
||
|
skillJoystick.Setup(characterEntity);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pcSkillController != null)
|
||
|
{
|
||
|
pcSkillController.Setup(characterEntity);
|
||
|
}
|
||
|
|
||
|
// Initialize current HP
|
||
|
currentHp = characterEntity.GetCurrentHP();
|
||
|
characterIcon.sprite = characterEntity.GetCharacterData().icon;
|
||
|
// Update skill icons
|
||
|
UpdateSkillIcons();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Toggles the pause menu and game state.
|
||
|
/// </summary>
|
||
|
public void OnClickTogglePauseGame()
|
||
|
{
|
||
|
if (GameplayManager.Singleton == null)
|
||
|
{
|
||
|
Debug.LogError("GameplayManager Singleton is not available.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GameplayManager.Singleton.TogglePause();
|
||
|
|
||
|
if (pauseMenu == null)
|
||
|
{
|
||
|
Debug.LogError("Pause menu GameObject is not assigned.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pauseMenu.SetActive(!pauseMenu.activeSelf);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Updates the user interface elements with the latest character stats.
|
||
|
/// </summary>
|
||
|
private void UpdateUI()
|
||
|
{
|
||
|
if (characterEntity != null)
|
||
|
{
|
||
|
float newHp = characterEntity.GetCurrentHP();
|
||
|
if (newHp != currentHp && !isUpdatingHpBar)
|
||
|
{
|
||
|
StartCoroutine(UpdateHpBar(currentHp, newHp));
|
||
|
currentHp = newHp;
|
||
|
}
|
||
|
|
||
|
hpText.text = $"HP: {Mathf.CeilToInt(characterEntity.GetCurrentHP())} / {Mathf.CeilToInt(characterEntity.GetMaxHP())}";
|
||
|
hpRegenText.text = $"HP Regen: {Mathf.CeilToInt(characterEntity.GetCurrentHPRegen())}";
|
||
|
hpLeechText.text = $"HP Leech: {characterEntity.GetCurrentHPLeech():F2}%";
|
||
|
mpText.text = $"MP: {Mathf.CeilToInt(characterEntity.GetCurrentMP())} / {Mathf.CeilToInt(characterEntity.GetMaxMP())}";
|
||
|
mpRegenText.text = $"MP Regen: {Mathf.CeilToInt(characterEntity.GetCurrentMPRegen())}";
|
||
|
damageText.text = $"Damage: {Mathf.CeilToInt(characterEntity.GetCurrentDamage())}";
|
||
|
attackSpeedText.text = $"Attack Speed: {characterEntity.GetCurrentAttackSpeed():F2}";
|
||
|
cooldownReductionText.text = $"Cooldown Reduction: {characterEntity.GetCurrentCooldownReduction():F2}%";
|
||
|
criticalRateText.text = $"Critical Rate: {characterEntity.GetCurrentCriticalRate():F2}%";
|
||
|
criticalDamageMultiplierText.text = $"Critical Damage Multiplier: x{Mathf.CeilToInt(characterEntity.GetCurrentCriticalDamageMultiplier())}";
|
||
|
defenseText.text = $"Defense: {Mathf.CeilToInt(characterEntity.GetCurrentDefense())}";
|
||
|
shieldText.text = $"Shield: {Mathf.CeilToInt(characterEntity.GetCurrentShield())}";
|
||
|
moveSpeedText.text = $"Move Speed: {characterEntity.GetCurrentMoveSpeed():F2}";
|
||
|
collectRangeText.text = $"Collect Range: {Mathf.CeilToInt(characterEntity.GetCurrentCollectRange())}";
|
||
|
float maxMP = characterEntity.GetMaxMP();
|
||
|
float currentMP = characterEntity.GetCurrentMP();
|
||
|
mpBar.fillAmount = (float)currentMP / maxMP;
|
||
|
int currentXP = characterEntity.GetCurrentXP();
|
||
|
int xpToNextLevel = characterEntity.GetXPToNextLevel();
|
||
|
int currentLevel = characterEntity.GetCurrentLevel();
|
||
|
xpBar.fillAmount = (float)currentXP / xpToNextLevel;
|
||
|
|
||
|
hpCurrent.text = $"{Mathf.CeilToInt(characterEntity.GetCurrentHP())} / {Mathf.CeilToInt(characterEntity.GetMaxHP())}";
|
||
|
energyCurrent.text = $"{Mathf.CeilToInt(characterEntity.GetCurrentMP())} / {Mathf.CeilToInt(characterEntity.GetMaxMP())}";
|
||
|
xpCurrent.text = $"{Mathf.CeilToInt(currentXP)} / {Mathf.CeilToInt(xpToNextLevel)}";
|
||
|
level.text = $"Level: {currentLevel}";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private IEnumerator UpdateHpBar(float startHp, float endHp)
|
||
|
{
|
||
|
isUpdatingHpBar = true;
|
||
|
float startFillAmount = startHp / characterEntity.GetMaxHP();
|
||
|
float endFillAmount = endHp / characterEntity.GetMaxHP();
|
||
|
float elapsedTime = 0f;
|
||
|
float duration = 0.5f; // Duration for the flash effect
|
||
|
|
||
|
while (elapsedTime < duration)
|
||
|
{
|
||
|
float t = elapsedTime / duration;
|
||
|
hpBar.fillAmount = Mathf.Lerp(startFillAmount, endFillAmount, t);
|
||
|
elapsedTime += Time.deltaTime;
|
||
|
yield return null;
|
||
|
}
|
||
|
|
||
|
hpBar.fillAmount = endFillAmount;
|
||
|
isUpdatingHpBar = false;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Updates the skill icons in the UI.
|
||
|
/// </summary>
|
||
|
private void UpdateSkillIcons()
|
||
|
{
|
||
|
if (skillImages != null && characterEntity != null)
|
||
|
{
|
||
|
for (int i = 0; i < skillImages.Length; i++)
|
||
|
{
|
||
|
SkillImage skillImage = skillImages[i];
|
||
|
if (skillImage.ImageComponent != null)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
Sprite skillIcon = characterEntity.GetSkillIcon(skillImage.Index);
|
||
|
skillImage.ImageComponent.sprite = skillIcon;
|
||
|
|
||
|
// Get skill data
|
||
|
SkillData skillData = characterEntity.GetSkillData(skillImage.Index);
|
||
|
int currentLevel = GameplayManager.Singleton.GetBaseSkillLevel(skillData);
|
||
|
int maxLevelIndex = skillData.skillLevels.Count - 1;
|
||
|
bool isEvolved = skillData.skillLevels[currentLevel].isEvolved;
|
||
|
|
||
|
// Activate max level icon if the skill is evolved
|
||
|
skillImage.maxLevelSkillIcon.gameObject.SetActive(isEvolved);
|
||
|
|
||
|
skillImage.CooldownImage.fillAmount = 0;
|
||
|
skillImage.CooldownText.text = "";
|
||
|
}
|
||
|
catch (System.Exception ex)
|
||
|
{
|
||
|
Debug.Log($"Error fetching skill icon for index {skillImage.Index}: {ex.Message}");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogError($"ImageComponent of SkillImage at index {i} is null.");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void UpdateSkillCooldowns()
|
||
|
{
|
||
|
if (characterEntity != null)
|
||
|
{
|
||
|
PlatformType currentPlatform = GameInstance.Singleton.GetCurrentPlatform();
|
||
|
|
||
|
if (currentPlatform == PlatformType.PC && pcSkillController != null)
|
||
|
{
|
||
|
for (int i = 0; i < skillImages.Length; i++)
|
||
|
{
|
||
|
SkillImage skillImage = skillImages[i];
|
||
|
|
||
|
if (skillImage.ImageComponent != null)
|
||
|
{
|
||
|
float cooldown = pcSkillController.GetCurrentCooldown(skillImage.Index);
|
||
|
float maxCooldown = pcSkillController.GetCooldownTime(skillImage.Index);
|
||
|
|
||
|
if (cooldown > 0 && maxCooldown > 0)
|
||
|
{
|
||
|
skillImage.CooldownImage.fillAmount = cooldown / maxCooldown;
|
||
|
skillImage.CooldownText.text = Mathf.Ceil(cooldown).ToString();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
skillImage.CooldownImage.fillAmount = 0;
|
||
|
skillImage.CooldownText.text = "";
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning($"SkillImage at index {i} has no ImageComponent.");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (currentPlatform == PlatformType.Mobile && skillJoysticks != null && skillJoysticks.Length > 0)
|
||
|
{
|
||
|
for (int i = 0; i < skillImages.Length; i++)
|
||
|
{
|
||
|
SkillImage skillImage = skillImages[i];
|
||
|
|
||
|
if (skillImage.ImageComponent != null)
|
||
|
{
|
||
|
SkillJoystick skillJoystick = null;
|
||
|
if (i < skillJoysticks.Length)
|
||
|
skillJoystick = skillJoysticks[i];
|
||
|
|
||
|
if (skillJoystick != null)
|
||
|
{
|
||
|
float cooldown = skillJoystick.GetCurrentCooldown();
|
||
|
float maxCooldown = skillJoystick.GetCooldownTime();
|
||
|
|
||
|
if (cooldown > 0 && maxCooldown > 0)
|
||
|
{
|
||
|
skillImage.CooldownImage.fillAmount = cooldown / maxCooldown;
|
||
|
skillImage.CooldownText.text = Mathf.Ceil(cooldown).ToString();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
skillImage.CooldownImage.fillAmount = 0;
|
||
|
skillImage.CooldownText.text = "";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning($"SkillImage at index {i} has no ImageComponent.");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public void Revive()
|
||
|
{
|
||
|
endGameScreen.SetActive( false );
|
||
|
GameplayManager.Singleton.ResumeGame();
|
||
|
characterEntity.Revive();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Displays the end game screen, showing victory or defeat based on the result.
|
||
|
/// </summary>
|
||
|
/// <param name="won">Set to true if the player won the game, false if they lost.</param>
|
||
|
public void DisplayEndGameScreen(bool won)
|
||
|
{
|
||
|
// Show the end game screen
|
||
|
endGameScreen.SetActive(true);
|
||
|
|
||
|
// Set the end game message text and color based on whether the player won or lost
|
||
|
endGameMessage.text = won ? "You Win!" : "You Lose!";
|
||
|
endGameMessage.color = won ? Color.green : Color.red;
|
||
|
|
||
|
// Activate objects and play audio based on victory or defeat
|
||
|
if (won)
|
||
|
{
|
||
|
// Activate Victory objects
|
||
|
ActivateObjects(VictoryObjects);
|
||
|
// Play Victory audio
|
||
|
AudioManager.Singleton.PlayAudio(VictoryAudio, "master");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Activate Defeat objects
|
||
|
ActivateObjects(DefeatObjects);
|
||
|
// Play Defeat audio
|
||
|
AudioManager.Singleton.PlayAudio(DefeatAudio, "master");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Activates all the objects in the given array.
|
||
|
/// </summary>
|
||
|
/// <param name="objects">Array of GameObjects to activate.</param>
|
||
|
private void ActivateObjects(GameObject[] objects)
|
||
|
{
|
||
|
foreach (GameObject obj in objects)
|
||
|
{
|
||
|
if (obj != null)
|
||
|
{
|
||
|
obj.SetActive(true);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns to the main menu.
|
||
|
/// </summary>
|
||
|
public void ReturnToMainMenu()
|
||
|
{
|
||
|
GameManager.Singleton.ReturnToMainMenu();
|
||
|
}
|
||
|
|
||
|
public CharacterEntity GetCharacterEntity()
|
||
|
{
|
||
|
return characterEntity;
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <summary>
|
||
|
/// Displays a status message with the specified color.
|
||
|
/// </summary>
|
||
|
/// <param name="message">The message to display.</param>
|
||
|
/// <param name="color">The color of the message text.</param>
|
||
|
public void DisplayMPInsufficientMessage(string message)
|
||
|
{
|
||
|
insufficientMPText.text = message;
|
||
|
StartCoroutine(HideStatusMessageAfterDelay(insufficientMPText, 2f)); // Hide message after delay
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Coroutine to hide the status message after a delay.
|
||
|
/// </summary>
|
||
|
/// <param name="statusText">The TextMeshProUGUI component displaying the status message.</param>
|
||
|
/// <param name="delay">The delay in seconds before hiding the message.</param>
|
||
|
private IEnumerator HideStatusMessageAfterDelay(TextMeshProUGUI _insufficientMPText, float delay)
|
||
|
{
|
||
|
yield return new WaitForSeconds(delay);
|
||
|
_insufficientMPText.text = string.Empty;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Struct to hold skill image components for the UI.
|
||
|
/// </summary>
|
||
|
[System.Serializable]
|
||
|
public struct SkillImage
|
||
|
{
|
||
|
[Tooltip("Image component to show the skill icon")]
|
||
|
public Image ImageComponent; // Image component to show the skill icon
|
||
|
[Tooltip("Image to show cooldown progress")]
|
||
|
public Image CooldownImage; // Image to show cooldown progress
|
||
|
[Tooltip("Text to show remaining cooldown time")]
|
||
|
public TextMeshProUGUI CooldownText; // Text to show remaining cooldown time
|
||
|
public Image maxLevelSkillIcon; // Image to activate when skill is evolved
|
||
|
[Tooltip("Index of the skill in the character's skill list")]
|
||
|
public int Index; // Index of the skill in the character's skill list
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Struct to hold skill perk images for the UI.
|
||
|
/// </summary>
|
||
|
[System.Serializable]
|
||
|
public struct SkillsPerkImage
|
||
|
{
|
||
|
[Tooltip("Image component to show the skill perk icon")]
|
||
|
public Image perkIcon;
|
||
|
public Image maxLevelPerkIcon;
|
||
|
[Tooltip("Text to show the current level of the skill perk")]
|
||
|
public TextMeshProUGUI perkLevel;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Struct to hold stat perk images for the UI.
|
||
|
/// </summary>
|
||
|
[System.Serializable]
|
||
|
public struct StatPerkImage
|
||
|
{
|
||
|
[Tooltip("Image component to show the stat perk icon")]
|
||
|
public Image perkIcon; // Image component to show the stat perk icon
|
||
|
[Tooltip("Text to show the current level of the stat perk")]
|
||
|
public TextMeshProUGUI perkLevel; // Text to show the current level of the stat perk
|
||
|
public Image maxLevelStatIcon;
|
||
|
}
|
||
|
}
|