작성
·
87
0
강사님 Effect 에 추가적인 기능 구현에 대해 궁금한 점이 있어서 질문드립니다.
현재 강의의 Effect는 Start, Apply, Release의 세 가지 타이밍을 이용해서 여러 부가 효과를 주는 것으로 이해했습니다.(stat을 증가시키기, damage주기)
그런데 만약 죽음 저항, 마법 시전시 추가 피해,
,받는 화속성 피해 무효화, 특정 종족에게 가하는 피해 증가 등 다른 논리적인 코드 안에서 이 Effect의 여부를 따져야 하는 경우에는 어떤 식으로 처리할 수 있을까요?
예를 들어 죽음 저항의 Effect가 있다면
캐릭터의 TakeDamage의 코드 안에서
이 Effect의 여부를 따지는 부분이 필요할텐데
단순히 하드코딩으로 짜기엔 나중에 여러 효과들이 추가 되면 될 수록 감당할 수 없어질 것 같고 코드를 어떻게 확장 해야할지도 감이 잘 잡히지 않습니다.
제가 보기에도 질문이 조금 난해 하지만
결론은 이렇습니다.
effect가 다른 많은 코드들에 영향을 주어야 할 경우 어떻게 안전하게 확장 할 수 있을까요?
답변 2
1
수강해주셔서 감사합니다.
Effect를 다양한 상황에 적용시키기 위해서는 EffectAction의 Callback 함수를 연결할 수 있는 다양한 event들을 촘촘히 만들고, 때에 따라서는 특정 Damage 유형을 Stat으로 만드는 등 적절한 처리 방법을 고민해야합니다.
예를 들어, 죽으면 즉시 부활하는 효과라고 가정하면 아래와 같이 EffectAction을 만들 수 있을겁니다.
EffectAction.cs
public override Start(Effect effect)
{
effect.Owner.Owner.onTakeDamage += OnTakeDamage;
}
public override bool Apply(Effect effect)
{
// event를 통해 효과를 적용했다면, 상태를 리셋하고 true를 return
if (isApplied)
{
isApplied = false;
return true;
}
return isApplied;
}
public override Release(Effect effect)
{
effect.Owner.Owner.onTakeDamage -= OnTakeDamage;
}
public void OnTakeDamage(Entity target, float damage);
{
// 대상이 이번에 Damage를 받고 죽었다면 HP가 1인 상태로 부활시킴
if (target.IsDead)
{
target.HPStat.Value = 1f;
isApplied = true;
}
}
Effect가 실행될 때 Owner Entity의 onTakeDamage Event에 Callback 함수를 연결해두고, Entity가 죽으면 효과가 발동하는 형식입니다.
특정 종족에게 가하는 피해 증가는 종족 피해 배율을 Stat으로 만들 수 있을겁니다.
예를 들어, Elf 종족에 대한 Damage 증가를 담당하는 INCREASED_DAMAGE_TO_ELF Stat을 만들고, Effect는 Stat의 수치를 증가시키면 됩니다.
EffectAction.cs
public override Start(Effect effect)
{
}
public override bool Apply(Effect effect)
{
effect.Owner.Owner.Stats.SetBonusValue("STAT_INCREASED_DAMAGE_TO_ELF", this, 0.2f);
}
public override Release(Effect effect)
{
effect.Owner.Owner.Stats.RemoveBonusValue("STAT_INCREASED_DAMAGE_TO_ELF", this);
}
// Entity.cs
public void GiveDamage(Entity target)
{
float damage = Stats.GetValue("DAMAGE");
if (target.Race == Race.Elf)
damage *= Stats.GetValue(STAT_INCREASED_DAMAGE_TO_ELF);
target.TakeDamage(damage)
}
위는 예시라서 if문으로 하드 코딩했지만, 제대로 만들 때는 Entity가 제대로된 종족 값을 가지도록 확장을 해야겠죠.
Damage 감소 같은건 Damage를 계산할 때 사용할 Action Callback들을 받아서
Invocation을 통해서 연결된 Action들을 순회하면서 최종 값을 구할 수 있습니다
EffectAction.cs
public override Start(Effect effect)
{
effect.Owner.Owner.CalcDamage += CalcDamage;
}
public override bool Apply(Effect effect)
{
// event를 통해 효과를 적용했다면, 상태를 리셋하고 true를 return
if (isApplied)
{
isApplied = false;
return true;
}
return isApplied;
}
public override Release(Effect effect)
{
effect.Owner.Owner.CalcDamage -= CalcDamage;
}
private float CalcDamage(Entity instigator, DamageType damageType, float damage)
{
// 공격한 적의 Damage Type이 화속성이면 Damage를 무묘화시킴.
if (damage > 0f && damageType == DamageType.Fire)
{
isApplied = true;
return 0f;
}
// 적의 Damage Type이 화속성이 아니라면 Effect가 작동하지않음
else
return damage;
}
// TakeDamage 함수 안
// 연결된 Callback 함수들을 순회하며 최종 Damage 계산을 함.
// 위 Effect가 발동할 경우 최종 Damage는 0이 됨.
foreach (var calc in CalcDamage.GetInvocationList().Cast<CalcDamageHandler>())
damage = calc.Invoke(this, damageType, damage);
보시듯 복잡한 체계를 가진 전투 시스템은 복합적인 방식을 사용하여 구현하여야하기 때문에 모든 프로그래밍적 역량을 끌어올릴 필요가 있습니다. 그래서 RPG 게임 개발이 어렵다고 많이들 얘기하는 것입니다.
감사합니다.
네, 맞습니다.
효과를 만들 때는
"내가 만들려는 Effect가 Apply 함수를 구현하는 것만으로 충분할까?"
"안된다면 event에 Callback을 연결하는 방식으로 효과를 구현할 수 있을까?"
"구현할 수 있다면 어느 곳에 어떤 event를 만들어서 Callback을 연결해야할까?"
"이건 event로 구현하지말고 Stat으로 처리하는게 낫지 않을까?"
와 같이 다양한 고민이 필요합니다.
감사합니다.
추가로 질문이 하나 더 있습니다.
장비같은 아이템에도 특수 기능들이 필요할 경우
기존 Effect의 시스템을 이용해서 구현해도 괜찮을까요?
아니면 장비의 특수 기능은 Effect를 이용하지 않고 독립적으로 구현해야만 하나요?
0
안녕하세요, 인프런 AI 인턴입니다. 최성호님.
Effect가 여러 코드에 영향을 미칠 때 이를 안전하게 확장하기 위한 방법에 대한 질문을 주셨군요. 다양한 게임 메커니즘에서 발생할 수 있는 문제로, 확장을 고려한 설계가 필요합니다. 이에 대해 가능한 접근 방법을 소개드리겠습니다.
게임 로직에서 발생하는 주요 액션(예: 데미지, 마법 시전 등)은 이벤트로 처리하여 특정 Effect가 활성 상태인 경우 추가적인 로직을 실행할 수 있도록 합니다. 이렇게 하면 이러한 이벤트에 대해 여러 Effect가 순차적으로 반응할 수 있습니다.
예시 코드:
”`csharp
public class Entity : MonoBehaviour
{
public delegate void DamageTakenHandler(float damage);
public event DamageTakenHandler OnDamageTaken;
public void TakeDamage(float damage)
{
OnDamageTaken?.Invoke(damage); // 데미지 계산 전에 모든 구독된 핸들러에 알림
// 데미지 처리 로직
}
}
public class DeathResistanceEffect : Effect
{
public DeathResistanceEffect(Entity entity)
{
entity.OnDamageTaken += CheckDeathResistance;
}
private void CheckDeathResistance(float damage)
{
// 죽음 저항 로직 구현
}
}
### 2. **효과 관리 시스템**:
- 각 Entity가 자신에게 활성화된 Effect 목록을 관리하게 하고, 특정 조건(예: 마법 시전, 피해 입음 등)이 만족될 때 이 목록을 조회하여 적용할 효과를 찾고 처리합니다.
- 예시 접근 방법:
```csharp
public class EffectManager
{
private List<Effect> activeEffects = new List<Effect>();
public void AddEffect(Effect effect)
{
activeEffects.Add(effect);
effect.Apply();
}
public bool CheckEffect<T>() where T : Effect
{
foreach (var effect in activeEffects)
{
if (effect is T)
{
return true;
}
}
return false;
}
}
// 사용 예시
if (effectManager.CheckEffect<DeathResistanceEffect>())
{
// 죽음 저항 효과가 있을 경우 처리 로직
}
이와 같은 방법들은 코드의 확장성을 높이고, 다양한 효과를 추가하거나 조절할 때 강력한 유연성을 제공합니다. 특히 이벤트 기반 시스템은 단일 책임 원칙을 잘 지키면서 다양한 효과를 처리하는 데 유리합니다.
첨고로 관련된 질문에 대한 정보는 아래 링크들에서 보실 수 있습니다:
- 적 스킬 관련 질문
- 공격할 때마다 일정 확률로 추가 투사체 발사
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
아 코드 중간중간에 다른 복합적인 방식을 고려해야하는 곳에 콜백함수를 두어 Effect뿐 아니라 여러 다른 코드들에서도 추가적인 계산을 더할 수 있게 한다라는 규칙을 정하고,
Effect의 경우는 Start와 Release에서 이벤트의 등록과 해제를 통해 이 규칙을 이용해서 복합적인 기능을 구현한다. 라고 이해했는데 맞을까요?