inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[유니티 레벨 업!] 모듈식으로 개발하는 스킬 시스템

Effect (2)

Effect에 기능 확장에 대해서 질문이 있습니다.

149

최성호

작성한 질문수 10

0

강사님 Effect 에 추가적인 기능 구현에 대해 궁금한 점이 있어서 질문드립니다.
현재 강의의 Effect는 Start, Apply, Release의 세 가지 타이밍을 이용해서 여러 부가 효과를 주는 것으로 이해했습니다.(stat을 증가시키기, damage주기)
그런데 만약 죽음 저항, 마법 시전시 추가 피해,
,받는 화속성 피해 무효화, 특정 종족에게 가하는 피해 증가 등 다른 논리적인 코드 안에서 이 Effect의 여부를 따져야 하는 경우에는 어떤 식으로 처리할 수 있을까요?
예를 들어 죽음 저항의 Effect가 있다면
캐릭터의 TakeDamage의 코드 안에서
이 Effect의 여부를 따지는 부분이 필요할텐데
단순히 하드코딩으로 짜기엔 나중에 여러 효과들이 추가 되면 될 수록 감당할 수 없어질 것 같고 코드를 어떻게 확장 해야할지도 감이 잘 잡히지 않습니다.

제가 보기에도 질문이 조금 난해 하지만
결론은 이렇습니다.
effect가 다른 많은 코드들에 영향을 주어야 할 경우 어떻게 안전하게 확장 할 수 있을까요?

unity modules

답변 2

1

Developer G

수강해주셔서 감사합니다.

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 게임 개발이 어렵다고 많이들 얘기하는 것입니다.

감사합니다.

0

최성호

아 코드 중간중간에 다른 복합적인 방식을 고려해야하는 곳에 콜백함수를 두어 Effect뿐 아니라 여러 다른 코드들에서도 추가적인 계산을 더할 수 있게 한다라는 규칙을 정하고,
Effect의 경우는 Start와 Release에서 이벤트의 등록과 해제를 통해 이 규칙을 이용해서 복합적인 기능을 구현한다. 라고 이해했는데 맞을까요?

1

Developer G

네, 맞습니다.

효과를 만들 때는
"내가 만들려는 Effect가 Apply 함수를 구현하는 것만으로 충분할까?"
"안된다면 event에 Callback을 연결하는 방식으로 효과를 구현할 수 있을까?"
"구현할 수 있다면 어느 곳에 어떤 event를 만들어서 Callback을 연결해야할까?"
"이건 event로 구현하지말고 Stat으로 처리하는게 낫지 않을까?"
와 같이 다양한 고민이 필요합니다.

0

최성호

감사합니다.
추가로 질문이 하나 더 있습니다.
장비같은 아이템에도 특수 기능들이 필요할 경우
기존 Effect의 시스템을 이용해서 구현해도 괜찮을까요?
아니면 장비의 특수 기능은 Effect를 이용하지 않고 독립적으로 구현해야만 하나요?

1

Developer G

롤처럼 Item에 달린 패시브나 액티브 능력은 전부 Skill이라고 생각하시면 됩니다.

0

최성호

감사합니다

0

인프런 AI 인턴

안녕하세요, 인프런 AI 인턴입니다. 최성호님.

Effect가 여러 코드에 영향을 미칠 때 이를 안전하게 확장하기 위한 방법에 대한 질문을 주셨군요. 다양한 게임 메커니즘에서 발생할 수 있는 문제로, 확장을 고려한 설계가 필요합니다. 이에 대해 가능한 접근 방법을 소개드리겠습니다.

1. 이벤트 기반 시스템:

  • 게임 로직에서 발생하는 주요 액션(예: 데미지, 마법 시전 등)은 이벤트로 처리하여 특정 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>())
  {
      // 죽음 저항 효과가 있을 경우 처리 로직
  }

3. 설계 패턴 활용:

  • 컴포지트 패턴 또는 체인오브리스폰서빌리티 패턴을 활용하여, 각 Effect가 자기의 역할을 캡슐화하고 필요에 따라 다른 Effect와 조합할 수 있도록 합니다.

이와 같은 방법들은 코드의 확장성을 높이고, 다양한 효과를 추가하거나 조절할 때 강력한 유연성을 제공합니다. 특히 이벤트 기반 시스템은 단일 책임 원칙을 잘 지키면서 다양한 효과를 처리하는 데 유리합니다.

첨고로 관련된 질문에 대한 정보는 아래 링크들에서 보실 수 있습니다:
- 적 스킬 관련 질문
- 공격할 때마다 일정 확률로 추가 투사체 발사

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

Indicator와 SelectionAction 및 SearchAction 간의 관계에 대해 질문있습니다.

0

70

2

ChargingState에서 질문이 있습니다.

0

49

1

Effect.GetData 함수 질문있습니다.

0

45

2

CanTransitionToSelf 질문 있습니다.

0

53

2

Stat의 MaxValue에 관하여 질문이 있습니다.

0

42

1

Stat vs StatScaleFloat

0

75

4

애니매이션 버그가 있는것 같습니다.

0

65

2

StatsOverride질문이 있습니다.

0

50

2

SetBonusValue함수 질문있습니다.

0

46

2

오늘 수강시작한 취준생입니다.

0

49

1

사소하지만 에디터 관련 질문있습니다

0

69

1

스킬시스템을 데이터 테이블화 하는 법에 대해 감이안잡혀서 질문드립니다.

0

144

2

TargetSearcher에 대해서 질문이 있습니다

0

52

1

돌진해서 몸박을하면 피격자를 날리면서 데미지를 입히는 스킬은 이 시스템에서 어떻게 만들 수 있을까요??

0

116

2

스킬 관련 질문입니다

0

110

2

통일된 Stat을 사용하지 않고 모듈화 방식으로 Stats를 만드신 이유가 궁금합니다.

0

152

1

SkillData 구조체 질문

0

122

1

스킬트리 저장 질문입니다

0

135

2

BT와 FSM을 활용해 몬스터 AI 구현

0

349

2

MonoStateMachine을 만든 이유가 잘 이해가 가지 않습니다.

0

128

1

근접 콤보 공격을 만들고 싶습니다.

0

153

1

하나의 스킬 내에서 타겟, 이펙트가 여러번 바뀌게 하는 방법이 궁금합니다.

0

190

1

올해에 예정된 새로운 강의가 있으신지요?

0

115

2

스킬트리 질문입니다

0

153

3