1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
using UnityEngine;
using StatSystem;
using Core;
using CombatSystem;
 
namespace CombatSystem
{
    public static class DamageApplier
    {
        /// <summary>
        /// 주어진 공격자의 스탯 컨트롤러와 데미지 정보를 사용하여 대상에게 데미지를 적용
        /// </summary>
        /// <param name="attackerStatController">공격자의 스탯 컨트롤러</param>
        /// <param name="damageable">데미지를 받을 대상</param>
        /// <param name="rawDamage">원본 데미지 정보</param>
        public static void ApplyDamage(StatController attackerStatController, IDamageable damageable, IEnhancedDamage rawDamage)
        {
            // 데미지 타입에 따른 데미지 계산 전략을 선택
            var damageCalculationStrategy = SelectDamageStrategy(rawDamage.GetDamageType());
 
            // 최종 데미지를 계산
            int finalDamage = damageCalculationStrategy.CalculateDamage(attackerStatController, rawDamage);
            // 공격자의 크리티컬 확률을 가져옴
            float shooterCriticalChance = attackerStatController.GetStatValue("CriticalHitChance");
 
            // 공격 자체의 크리티컬 확률을 가져옴
            float totalCriticalChance = rawDamage.GetCriticalHitChance() + shooterCriticalChance;
 
            // 크리티컬 히트 여부를 결정 (무작위 값을 기반으로 크리티컬 확률이 넘으면 true)
            bool isCriticalHit = Random.Range(0f, 100f) < totalCriticalChance;
 
            if (isCriticalHit)
            {
                // 공격자의 크리티컬 배율을 가져옴
                float attackerCriticalMultiplier = attackerStatController.GetStatValue("CriticalHitMultiplier");
 
                // 최종 크리티컬 배율 계산 (공격자의 크리티컬 배율 + 공격 자체의 크리티컬 배율)
                float totalCriticalMultiplier = (rawDamage.GetCriticalDamageMultiplier() + attackerCriticalMultiplier) / 100f;
 
                // 최종 데미지에 크리티컬 배율 적용
                finalDamage = Mathf.RoundToInt(finalDamage * totalCriticalMultiplier);
            }
 
            // HealthModifier 객체를 생성하여 데미지 정보를 설정
            HealthModifier damageInfo = new HealthModifier();
            //FinalDamage 계산하는 부분은 Take 데미지와 반대여야함
            damageInfo.SetMagnitude(-finalDamage); 
            damageInfo.SetIsCriticalHit(rawDamage.GetIsCriticalHit());
            damageInfo.SetInstigator(attackerStatController.gameObject);
            damageInfo.SetSource(rawDamage.GetSource());
 
            // 대상에게 데미지를 적용
            damageable.TakeDamage(damageInfo);
        }
 
        /// <summary>
        /// 주어진 대상의 스탯 컨트롤러와 데미지 정보를 사용하여 데미지를 계산하고 적용
        /// </summary>
        /// <param name="targetStatController">데미지를 받을 대상의 스탯 컨트롤러</param>
        /// <param name="rawDamage">원본 데미지 정보</param>
        public static void TakeDamage(StatController targetStatController, IDamage rawDamage)
        {
            // 데미지 타입에 따른 방어 계산 전략을 선택
            var defenseStrategy = SelectDefenseStrategy(rawDamage.GetDamageType());
 
            // 최종 방어 후 데미지를 계산
            int finalDamage = defenseStrategy.CalculateDefense(targetStatController, rawDamage);
            //Debug.Log("최종 데미지"+finalDamage);
 
            // HealthModifier 객체를 생성하여 데미지 정보를 설정
            HealthModifier damageInfo = new HealthModifier();
            damageInfo.SetMagnitude(finalDamage); 
            damageInfo.SetIsCriticalHit(rawDamage.GetIsCriticalHit());
            damageInfo.SetInstigator(rawDamage.GetInstigator());
            damageInfo.SetSource(rawDamage.GetSource());
 
            Stat healthStat = targetStatController.GetStat("Health");
 
            // 대상의 체력에 데미지를 적용
            //(targetStatController.GetStat("Health") as Attribute).ApplyModifier(damageInfo);
            // Health가 Attribute 또는 CalculatedAttribute인지 확인하고 데미지 적용
            if (healthStat is Attribute healthAttribute)
            {
                //Debug.Log("스탯 컨트롤러에 적용");
                healthAttribute.ApplyModifier(damageInfo);
            }
            else if (healthStat is CalculatedAttribute calculatedAttribute)
            {
                calculatedAttribute.ApplyModifier(damageInfo);
            }
        }
        /// <summary>
        /// 주어진 데미지 타입에 따른 방어 계산 전략을 선택
        /// </summary>
        /// <param name="damageType">데미지 타입</param>
        /// <returns>방어 계산 전략</returns>
        public static IDefenseCalculationStrategy SelectDefenseStrategy(DamageType damageType)
        {
            switch (damageType)
            {
                case DamageType.PhysicalRanged:
                case DamageType.PhysicalMelee:
                    return new PhysicalDefenseStrategy();
                case DamageType.Magical:
                    return new MagicalDefenseStrategy();
                default:
                    Debug.LogError($"Unexpected damage type: {damageType}");
                    return null;
            }
        }
 
        /// <summary>
        /// 주어진 데미지 타입에 따른 데미지 계산 전략을 선택
        /// </summary>
        /// <param name="damageType">데미지 타입</param>
        /// <returns>데미지 계산 전략</returns>
        public static IDamageCalculationStrategy SelectDamageStrategy(DamageType damageType)
        {
            switch (damageType)
            {
                case DamageType.PhysicalRanged:
                    return new PhysicalRangedDamageStrategy();
                case DamageType.PhysicalMelee:
                    return new PhysicalMeleeDamageStrategy();
                case DamageType.Magical:
                    return new MagicalDamageStrategy();
                default:
                    Debug.LogError($"Unexpected damage type: {damageType}");
                    return null;
            }
        }
 
 
        /// <summary>
        /// 주어진 크리티컬 히트 확률을 기반으로 크리티컬 히트 여부를 결정
        /// </summary>
        /// <param name="statController">스탯 컨트롤러</param>
        /// <param name="attackCriticalHitChance">프로젝트 타격 확률</param>
        /// <returns>크리티컬 히트 여부</returns>
        private static bool GetIsCriticalHit(StatController statController, float attackCriticalHitChance)
        {
            // 공격자의 크리티컬 히트 확률을 가져옴
            int entityCriticalHitChance = statController.GetStatValue("CriticalHitChance");
 
            // 공격의 최종 크리티컬 히트 확률을 계산합니다. 
            float finalCriticalHitChance = attackCriticalHitChance + entityCriticalHitChance;
 
            // 무작위 값을 기반으로 크리티컬 히트 여부를 결정합니다.
            return Random.Range(0f, 100f) < finalCriticalHitChance;
        }
 
    }
}
 
cs