부트캠프/Unity [ 스파르타 ]

[스파르타 ][TIL] 유니티 스파르타 7기 59일차 - Condition분리

맏난거 2025. 5. 2. 22:09

public class ExplosiveCondition<T> : UniTaskHandler, IConditionable where T : EntityController
{
    private Coroutine dotCor;
    private EnemyController enemyCtrl;
    private MyUnitController myunitCtrl;

    private float attackerDamage;
    private float victimDefence;

    private bool canHit = true;
    private float coolDown = 0.0f;
    private float time = 0.0f;

    public ExplosiveCondition(T ctrl)
    {
        if (typeof(T) == typeof(EnemyController))
            this.enemyCtrl = ctrl as EnemyController;
        else
            this.myunitCtrl = ctrl as MyUnitController;
    }

    /// <summary>
    /// 나중에 저장을 추가하면, 참조 값이라 값타입이나 타워에서 디폴트 참조타입이 아닌 변하는 타입을 가져와야됨
    /// </summary>
    /// <param name="attackerDamage"></param>
    /// <param name="values"></param>
    public void Execute(float attackerDamage, AbilityDefaultValue values) 
    {
        TokenDisable();
        TokenEnable();

        time = values.AbilityDuration;
        coolDown = 0f;

        if (typeof(T) == typeof(EnemyController))
            victimDefence = enemyCtrl.Status.Defence.GetValue();
        else
            victimDefence = myunitCtrl.MyUnitStatus.Defence.GetValue();

        OnDotDamage(values.AbilityValue, values.AbilityDuration, values.AbilityCooldown).Forget();
    }

    public void Init()
    {
        Init();
    }


    async UniTaskVoid OnDotDamage(float abilityValue, float abilityDuration, float abilityCooldown)
    {
        while (time > 0)
        {
            time -= Time.deltaTime;

            if (canHit)
            {
                AddHealth(-abilityValue);
                // 0초라서 수정해야됨 최소한 0.2초가 적당한듯?
                coolDown = 0.2f;
                canHit = false;
            }
            else if (coolDown <= 0.0f)
            {
                canHit = true;
            }

            coolDown -= Time.deltaTime;
            await UniTask.NextFrame(disableCancellation.Token);
        }

    }

    private void AddHealth(float damage)
    {
        if (typeof(T) == typeof(EnemyController))
        {
            enemyCtrl.Status.AddHealth(damage, enemyCtrl.ConditionHandlers[(int)AbilityType.Explosive].Attacker.gameObject);
            enemyCtrl.Fx.StartBlinkRed();
        }
/*        else
            myunitCtrl.MyUnitStatus.AddHealth(damage, enemyCtrl.ConditionHandlers[(int)AbilityType.Explosive].Attacker.gameObject);*/
    }

    // 나중에 공통적인건 묶어줄 필요가 있음
    // 공통적으로 묶어주면 기본 베이스에만 접근해두 되기때문에 if체크할 필요가 없어진다
    private Coroutine StartCoroutine(IEnumerator coroutine)
    {
        if (typeof(T) == typeof(EnemyController))
        {
            return enemyCtrl.StartCoroutine(coroutine);
        }

        return myunitCtrl.StartCoroutine(coroutine);
    }
}

 

int iCondition = (int)condition; // Enum타입을 int형으로
if(Times.ContainsKey(iCondition)) // 현재 컨디션이 있는지 체크
{
    if (Times[iCondition] <= 0f) // 현재 컨디션 적용 시킬 수 있는지 체크
    {
        Times[iCondition] = ConditionHandlers[iCondition].CoolDown;
        ConditionHandlers[iCondition].Attacker = go.transform;

        if (Conditions.ContainsKey(iCondition)) // 컨디션이 있는지 체크
            Conditions[iCondition].Execute(incomingDamage, values);
        else // 없으면 추가 하라는 경고문구
            Util.LogWarning($"{enemyName}에 현재 키로된 Conditions가 없습니다.");
    }
}
else
{
    // 실수 방지 경고로그
    if (Conditions.ContainsKey(iCondition))
        Util.LogWarning($"{enemyName} 바디에 {condition}키를 추가해주세요");
}

 

자주 코루틴스타트를 호출해야되니 부담이 될꺼같아

UniTask를 이용했습니다.  현재 만드는 프로젝트에 새로운 컨디션을 추가할때마다 if else문이 아닌 클래스로 추가를 할 수 있게 만들어보았습니다.