UnityGameProjectsCode / DiceAndMenGame / BattleControl.cs
BattleControl.cs
Raw
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class BattleControl : MonoBehaviour
{
    public static BattleControl Instance;

    public Slider unitHealthSlider, enemyUnitHealthSlider, actionTimerSlider;
    [SerializeField] private Button attackButton, defendButton, healButton, retreatButton;
    [SerializeField] private TextMeshProUGUI unitHealthText, enemyUnitHealthText,
        combinedATKText, combinedDEFText, combinedMedText,
        combinedEnemyATKText, combinedEnemyDEFText, combinedEnemyMedText;
    [Space]

    [SerializeField] private Animator playerUnitAnim, enemyUnitAnim, overlayAnim;
    [Space]

    [SerializeField] private float enemyAttackWaitTime, enemyAttackWaitVariance, playerAttackWaitTime;
    [Space]

    [SerializeField] AudioSource unitAttackHitAudio, unitHealAudio, unitBlockAudio;


    private int playerAttackDamage = 1, enemyAttackDamage = 1, playerHealthMax = 10, playerMedicalMax = 1, enemyHealthMax = 10, playerDefense = 0, enemyDefense = 0;
    private float playerTimeWaited;
    private bool playerActionsDisabled, enemyAttackBlocked;
    private bool battleOver;

    private Coroutine enemyAttacked = null;

    public bool BattleOver { get => battleOver; set => battleOver = value; }

    private void Awake()
    {
        Instance = this;

        enemyUnitHealthText.text = enemyUnitHealthSlider.value + " / " + enemyHealthMax;
        unitHealthText.text = unitHealthSlider.value + " / " + playerHealthMax;

        actionTimerSlider.maxValue = playerAttackWaitTime;
    }

    private void Update()
    {
        if(playerActionsDisabled)
        {
            playerTimeWaited += Time.deltaTime;

            actionTimerSlider.value = playerTimeWaited;

            if(playerTimeWaited >= playerAttackWaitTime)
            {
                EnableOrDisableAllButtons(true);
                playerTimeWaited = 0;
                playerActionsDisabled = false;
            }
        }

        if(unitHealthSlider.value <= 0)
        {
            battleOver = true;

            if(overlayAnim.GetCurrentAnimatorStateInfo(0).IsName("Idle"))
                overlayAnim.Play("Defeat Fade");

            if (enemyAttacked != null)
                StopCoroutine(enemyAttacked);
        }

        if(enemyAttacked == null && enemyUnitHealthSlider.value > 0)
            enemyAttacked = StartCoroutine(WaitForEnemyAttack());

        if (battleOver)
            StartCoroutine(WaitToUnloadBattle());
    }

    public void OnAttack()
    {
        enemyUnitHealthSlider.value -= determineDamageOnPlayerAttack();
        enemyUnitHealthText.text = enemyUnitHealthSlider.value + " / " + enemyHealthMax;

        playerUnitAnim.Play("Unit_Attack_Anim");
        enemyUnitAnim.Play("Enemy_Unit_Hit_Anim");
        unitAttackHitAudio.Play();

        if (enemyAttacked != null && enemyUnitHealthSlider.value <= 0)
        {
            StopCoroutine(enemyAttacked);
            overlayAnim.Play("Victory Fade");
            battleOver = true;
        }


        EnableOrDisableAllButtons(false);
        playerActionsDisabled = true;
    }

    public void OnDefend()
    {
        enemyAttackBlocked = true;

        EnableOrDisableAllButtons(false);
        playerActionsDisabled = true;
    }

    public void OnHeal()
    {
        unitHealthSlider.value += playerMedicalMax;
        unitHealthText.text = unitHealthSlider.value + " / " + playerHealthMax;

        playerUnitAnim.Play("Unit_Heal");
        unitHealAudio.Play();

        EnableOrDisableAllButtons(false);
        playerActionsDisabled = true;
    }

    public void OnRetreat()
    {
        //leave the battle
        StopCoroutine(enemyAttacked);

        playerUnitAnim.Play("Unit_Retreat");
        overlayAnim.Play("Retreat Fade");
        battleOver = true;
    }

    private int determineDamageOnPlayerAttack()
    {
        int damage = playerAttackDamage - enemyDefense;

        if (damage <= 0)
            damage = 1;

        return damage;
    }

    private int determineDamageOnEnemyAttack()
    {
        int damage = enemyAttackDamage - playerDefense;

        if (damage <= 0)
            damage = 1;

        return damage;
    }

    private void EnableOrDisableAllButtons(bool newState)
    {
        attackButton.interactable = newState;
        defendButton.interactable = newState;
        healButton.interactable = newState;
        retreatButton.interactable = newState;
    }

    public IEnumerator WaitForEnemyAttack()
    {
        yield return new WaitForSecondsRealtime(enemyAttackWaitTime + Random.Range(-enemyAttackWaitVariance, enemyAttackWaitVariance));

        if(!enemyAttackBlocked)
        {
            unitHealthSlider.value -= determineDamageOnEnemyAttack();
            unitHealthText.text = unitHealthSlider.value + " / " + playerHealthMax;

            playerUnitAnim.Play("Unit_Hit_Anim");
            enemyUnitAnim.Play("Enemy_Unit_Attack_Anim");
            unitAttackHitAudio.Play();
        }
        else
        {
            playerUnitAnim.Play("Unit_Block");
            enemyUnitAnim.Play("Enemy_Unit_Attack_Anim");
            unitBlockAudio.Play();

            enemyAttackBlocked = false;
        }

        enemyAttacked = null;
    }

    /// <summary>
    /// Called to initialize battle sequence with aggregated stats
    /// </summary>
    /// <param name="playerRoster"></param>
    /// <param name="enemyRoster"></param>
    public void SetBattleStatsForCombat(Roster playerRoster, Roster enemyRoster, int unitHealth, int enemyHealth)
    {
        //Aggregate player stats
        playerAttackDamage = 0;       
        playerDefense = 0;
        playerHealthMax = 0;

        foreach(var unit in playerRoster.units)
        {
            playerAttackDamage += unit.attack;
            playerDefense += unit.defense;
            playerHealthMax += unit.maxHealth;
            playerMedicalMax += unit.medical;
        }

        //show player stats on battle screen
        combinedATKText.text = playerAttackDamage.ToString();
        combinedDEFText.text = playerDefense.ToString();
        combinedMedText.text = playerMedicalMax.ToString();

        //Aggregate enemy stats
        enemyAttackDamage = 0;
        enemyDefense = 0;
        enemyHealthMax = 0;
        foreach (var unit in enemyRoster.units)
        {
            enemyAttackDamage += unit.attack;
            enemyDefense += unit.defense;
            enemyHealthMax += unit.maxHealth;
        }

        //show enemy stats on battle screen
        combinedEnemyATKText.text = enemyAttackDamage.ToString();
        combinedEnemyDEFText.text = enemyDefense.ToString();
        combinedEnemyMedText.text = enemyHealthMax.ToString();

        enemyUnitHealthSlider.maxValue = enemyHealthMax;
        enemyUnitHealthSlider.value = enemyHealth;
        enemyUnitHealthText.text = enemyUnitHealthSlider.value + " / " + enemyHealthMax;

        unitHealthSlider.maxValue = playerHealthMax;
        unitHealthSlider.value = unitHealth;
        unitHealthText.text = unitHealthSlider.value + " / " + playerHealthMax;
    }

    public static void LoadBattleScene(string scene = "Battle Scene")
    {
        Instance = null;
        SceneManager.LoadSceneAsync(scene, LoadSceneMode.Additive);
    }

    public static void UnloadBattleScene(string scene = "Battle Scene") //called instead from update to start the wait below VVVVVV
    {
        //Instance = null;
        //SceneManager.UnloadSceneAsync(scene);
    }

    public IEnumerator WaitToUnloadBattle()
    {
        yield return new WaitForSecondsRealtime(6);

        Instance = null;
        SceneManager.UnloadSceneAsync("Battle Scene");
    }
}