강화 레벨별 강화 스테이터스 누적 합산 기능은 다음과 같이 구현하였다.
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CreateAssetMenu(fileName = "Unit_Data", menuName = "Data/Unit/Unit_Data")]
public class UnitData : MetaData
{
[Header("MetaData")]
public Grade Grade;
public string AddressableAddress;
public GameObject UnitPrefab => Manager.Resources.Load<GameObject>(AddressableAddress);
public int ID;
public int PerferredLine;
public int Cost;
[Header("AnimationData")]
public bool isNotChange;
public AnimatorData AnimatiorData;
[Header("Attack_Data")]
public UnitSkill Skill;
public UnitAttackData AttackData; // Melee, Ranged 등 공격 타입에 따라 다름
[Header("Unit_Stat")]
public UnitStats[] UnitStats; // 3개 1,2,3 성
public UnitStats[] UpgradeStats; // UnitStats의 레벨 강화 반영
[Header("Synergy")]
public ClassType ClassSynergy;
public Synergy Synergy;
[Header("Upgrade")]
public UpgradeUnitData UpgradeData;
public LevelUpData LevelUpData;
public UpgradeStatData UpgradeStatData;
public UnitStats GetUnitStat(int level)
{
return UpgradeStats[level];
}
public void Init()
{
UpgradeData?.Init(Grade, LevelUpData);
if(UpgradeData != null)
{
UpgradeData.OnLevelUp += UpdateUpgradeStats;
UpdateUpgradeStats();
}
}
private void OnDestroy()
{
if(UpgradeData != null)
{
UpgradeData.OnLevelUp -= UpdateUpgradeStats;
}
}
public void UpdateUpgradeStats()
{
UpgradeStats = new UnitStats[UnitStats.Length];
for (int i = 0; i < UnitStats.Length; i++)
{
UpgradeStats[i] = UnitStats[i].Clone();
}
if (UpgradeStatData == null) return;
var gradeGrowth = UpgradeStatData.StatData.Find(g => g.CharGrade == Grade);
if (gradeGrowth.Stats == null || gradeGrowth.Stats.Count == 0) return;
int currentLevel = UpgradeData?.CurrentUpgradeData.UpgradeLevel ?? 0;
foreach (var levelGrowth in gradeGrowth.Stats)
{
if (levelGrowth.Level <= currentLevel)
{
foreach (var statGrowth in levelGrowth.Stats)
{
for (int i = 0; i < UpgradeStats.Length; i++)
{
UpgradeStats[i].AddStat(statGrowth.Type, statGrowth.Value);
}
}
}
}
}
public UnitDataDTO ToDTO(UnitData data)
{
return new UnitDataDTO
{
ClassSynergy = (int)data.ClassSynergy,
Cost = data.Cost,
Description = data.Description,
Grade = data.Grade,
ID = data.ID,
Name = data.name,
PrefferedLine = data.PerferredLine,
Synergy = (int)data.Synergy,
UnitStats = data.UnitStats
};
}
}
[System.Serializable]
public class UnitDataDTO
{
public int ClassSynergy;
public int Cost;
public string Description;
public Grade Grade;
public int ID;
public string Name;
public int PrefferedLine;
public int Synergy;
public UnitStats[] UnitStats;
}
using System;
using UnityEngine;
[System.Serializable]
public class UnitStats
{
[Header("Status")]
public int MaxHealth;
public int MaxMana;
public int ManaGain;
public float AttackSpeed;
public float MoveSpeed;
[Header("Damage")]
public int PhysicalDamage;
public int MagicDamage;
[Header("CritRate")]
public int CritChance;
[Header("Defense")]
public int PhysicalDefense;
public int MagicDefense;
[Header("Range")]
public float AttackRange;
public int AttackCount;
public UnitStats Clone()
{
return new UnitStats
{
MaxHealth = this.MaxHealth,
MaxMana = this.MaxMana,
ManaGain = this.ManaGain,
AttackSpeed = this.AttackSpeed,
MoveSpeed = this.MoveSpeed,
PhysicalDamage = this.PhysicalDamage,
MagicDamage = this.MagicDamage,
CritChance = this.CritChance,
PhysicalDefense = this.PhysicalDefense,
MagicDefense = this.MagicDefense,
AttackRange = this.AttackRange,
AttackCount = this.AttackCount
};
}
public void AddStat(StatType type, float value)
{
switch (type)
{
case StatType.MaxHealth:
MaxHealth += (int)value;
break;
case StatType.MaxMana:
MaxMana += (int)value;
break;
case StatType.ManaGain:
ManaGain += (int)value;
break;
case StatType.AttackSpeed:
AttackSpeed += value;
break;
case StatType.MoveSpeed:
MoveSpeed += value;
break;
case StatType.PhysicalDamage:
PhysicalDamage += (int)value;
break;
case StatType.MagicDamage:
MagicDamage += (int)value;
break;
case StatType.CritChance:
CritChance += (int)value;
break;
case StatType.PhysicalDefense:
PhysicalDefense += (int)value;
break;
case StatType.MagicDefense:
MagicDefense += (int)value;
break;
case StatType.AttackRange:
AttackRange += (int)value;
break;
case StatType.AttackCount:
AttackCount += (int)value;
break;
}
}
public void AddAugments(StatType status, float rate, string name, UnitStatusController controller)
{
StatEffectModifier modifier = CalculateAugment(status, rate);
AugmentManager.Instance.AddAugment(modifier.StatType, modifier.Value, name, controller);
}
public StatEffectModifier CalculateAugment(StatType status, float rate)
{
StatEffectModifier modifier = new StatEffectModifier();
modifier.StatType = status;
switch (modifier.StatType)
{
case StatType.MaxHealth: modifier.Value = Mathf.RoundToInt(MaxHealth * (rate / 100)); break;
case StatType.MaxMana: modifier.Value = Mathf.RoundToInt(MaxMana * (rate / 100)); break;
case StatType.ManaGain: modifier.Value = Mathf.RoundToInt(ManaGain * (rate / 100)); break;
case StatType.AttackSpeed: modifier.Value = AttackSpeed * (rate / 100); break;
case StatType.MoveSpeed: modifier.Value = MoveSpeed * (rate / 100); break;
case StatType.PhysicalDamage: modifier.Value = Mathf.RoundToInt(PhysicalDamage * (rate / 100)); break;
case StatType.MagicDamage: modifier.Value = Mathf.RoundToInt(MagicDamage * (rate / 100)); break;
case StatType.CritChance: modifier.Value = Mathf.RoundToInt(CritChance * (rate / 100)); break;
case StatType.PhysicalDefense: modifier.Value = Mathf.RoundToInt(PhysicalDefense * (rate / 100)); break;
case StatType.MagicDefense: modifier.Value = Mathf.RoundToInt(MagicDefense * (rate / 100)); break;
case StatType.AttackRange: modifier.Value = AttackRange * (rate / 100); break;
case StatType.AttackCount: modifier.Value = Mathf.RoundToInt(AttackCount * (rate / 100)); break;
default: modifier.Value = 0; break;
}
return modifier;
}
public void RemoveAugments(StatType status, string name, UnitStatusController controller)
{
AugmentManager.Instance.RemoveAugment(status, name, controller);
}
}
using System;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "Unit_UpgradeUnitData", menuName = "Data/Upgrade/Unit_UpgradeUnitData")]
public class UpgradeUnitData : ScriptableObject
{
// 캐릭터의 업그레이드 레벨 - 레벨이 0일 때는 획득하지 않은 상태
private Grade _grade;
private LevelUpData _levelUpData;
public CurrentUpgradeData CurrentUpgradeData;
public event Action OnLevelUp;
public void Init(Grade grade, LevelUpData data)
{
_grade = grade;
_levelUpData = data;
}
public int GetRequiredPiece()
{
if (CurrentUpgradeData.UpgradeLevel >= 10 ||
CurrentUpgradeData.UpgradeLevel <= 0) return 0;
if (_levelUpData == null)
{
Debug.LogError($"[{name}] LevelUpData가 설정되지 않았습니다.");
return 0;
}
RequirePiece requirePiece = _levelUpData.RequirePieceData.Find(r=>r.Grade == _grade);
if (requirePiece == null)
{
Debug.LogError($"[{name}] {_grade} 등급에 맞는 RequirePiece 데이터가 없습니다.");
return 0;
}
PieceLevelRatio pieceLevelRatio = requirePiece.LevelRatio.Find(l => l.Level == CurrentUpgradeData.UpgradeLevel + 1);
if (pieceLevelRatio == null)
{
Debug.LogError($"[{name}] {_grade} / {CurrentUpgradeData.UpgradeLevel}에 맞는 PieceLevelRatio 데이터가 없습니다.");
return 0;
}
return pieceLevelRatio.RequirePiece;
}
public void ObtainCharacter()
{
if (CurrentUpgradeData.UpgradeLevel == 0) CurrentUpgradeData.UpgradeLevel += 1;
}
public void AddPiece(int piece)
{
CurrentUpgradeData.CurrentPieces += piece;
}
public void LevelUp()
{
// 최대레벨 변수 추가?
if (CurrentUpgradeData.UpgradeLevel >= 10 || CurrentUpgradeData.UpgradeLevel <= 0) return;
int requiredPiece = GetRequiredPiece();
if(CurrentUpgradeData.CurrentPieces >= requiredPiece)
{
CurrentUpgradeData.CurrentPieces -= requiredPiece;
CurrentUpgradeData.UpgradeLevel += 1;
OnLevelUp?.Invoke();
}
}
}
[CreateAssetMenu(fileName = "Unit_LevelUpData", menuName = "Data/Temp/Unit_LevelUpData")]
public class LevelUpData : ScriptableObject
{
public List<RequirePiece> RequirePieceData = new();
}
[Serializable]
public class RequirePiece
{
public Grade Grade;
public List<PieceLevelRatio> LevelRatio = new List<PieceLevelRatio>();
}
/// <summary>
/// 에디터상 입력을 위해 임시로 List 로 처리함. 추후에 Dictionary로 전환할 필요성 있음
/// </summary>
[Serializable]
public class PieceLevelRatio
{
public int RequirePiece;
public int Level;
}
[Serializable]
public class CurrentUpgradeData
{
// 현재 보유 캐릭터 조각 수
public int CurrentPieces;
public int UpgradeLevel;
public void SetData(int currentPieces, int upgradeLevel)
{
CurrentPieces = currentPieces;
UpgradeLevel = upgradeLevel;
}
}