우리 게임엔 유물이라는 요소가 있다. 유물은 던전 탐사 혹은 전투 중 팀 전체에게 이득을 주는 요소로, 다양한 상황에서 다양한 효과를 일으킨다. 아래는 유물의 예시이다.

  • 유물 A: SP를 5 획득할 때마다, 적 전체에게 피해를 10 줍니다.
  • 유물 B: SP를 3 이상 소모하는 스킬의 피해량이 6 늘어납니다.
  • 유물 C: 전투 종료 시 HP가 50% 이하인 아군은 HP를 18 회복합니다.

이걸 어떻게 전투와 연결할 수 있을까? 우리의 액션 기반 전투 시스템에 이걸 연결하는 방법은 몹시 간단하다. 특정 행동을 했을 때 호출되는 함수를 준비해두고, 각 유물을 구현할 때 필요한 행동에 대해서만 그 함수를 구현하면 된다. 아래는 유물 A를 구현한 간략한 C# 코드이다.

// 반응형 함수들의 원형. 유물 뿐 아니라 여러 요소를 구현하는데 쓰인다.
public abstract class GameEventHandler {
    public virtual List<ICombatAction> OnChangeSp(CombatModel combat, int amount) => null;
    public virtual List<ICombatAction> OnSpellCast(CombatModel combat, SpellModel spell) => null;
    public virtual List<ICombatAction> OnCombatEnd(CombatModel combat) => null;
    // More functions..
}

public abstract class Relic : GameEventHandler {
    public int Counter { get; protected set; }
}

public class RelicA : Relic {
    public override List<ICombatAction> OnChangeSp(CombatModel combat, int amount) {
    	// 소모된 SP를 Relic.Counter를 이용해 저장
        Counter += amount;
        
        List<ICombatAction> derivedActions = new();
        
        // Counter가 5가 넘으면 모두에게 10 피해를 주는 액션을 생성해 반환함.
        while (Counter >= 5) {
            Counter -= 5;
            
            AllDamageAction action = new(combat.Enemies, 10);
            
            derivedActions.Add(action);
        }
        
        return derivedActions;
    }
}

 

구조가 어렵지 않음을 알 수 있다. 그리고 실제로 Model-side에서 SP를 변화시키는 코드가 호출될 때는 아래 코드처럼 할 수 있다.

public class CombatModel {
    public int Sp { get; private set; }
    public int MaxSp { get; private set; }
    private List<Relic> _relics;
    public IReadOnlyList<Relic> Relics => _relics;

    // Naive한 버전. 부가 효과를 Action 기반 시스템과 연결하기 어렵다.
    public void ChangeSp(int amount) {
    	Sp = Math.Clamp(Sp + amount, MaxSp);
    }
    
    // 부가 효과를 Action 기반 시스템과 올바르게 연결한 버전.
    public List<ICombatAction> ChangeSp(int amount) {
    	int beforeSp = Sp;
        Sp = Math.Clamp(Sp + amount, MaxSp);
        
        int actualAmount = Sp - beforeSp;
        
        List<ICombatAction> derivedActions = new();
        
        foreach (Relic relic in _relics) {
            List<ICombatAction> relicActions = relic.OnChangeSp(this, amount);
            derivedActions.AddRange(relicActions);
        }
        
        return derivedActions;
    }

}

 

기존에 Action 기반 시스템을 잘 갖춰놓아 구현이 매우 쉬웠다. 기술적으로 엄청 특이한 건 아니지만 잘 작동하는 걸 보니 즐겁다.

'Unity, 게임 개발' 카테고리의 다른 글

2026.05.06 (수) - 상태 이상 시스템 구현  (0) 2026.05.07
2026.02.28 (토) 턴제 애니메이션 구현하기  (0) 2026.02.28
2026.02.09 (월)  (0) 2026.02.10
2026.02.02 (월)  (1) 2026.02.03

+ Recent posts