본문으로 건너뛰기

조건 그래프

복잡한 게임 조건을 AND / OR / NOT 노드 트리로 데이터화합니다. if 지옥을 없애고 기획자가 인스펙터에서 직접 조건을 구성할 수 있습니다.

구조

ConditionGraph (ScriptableObject)
└── Root: ConditionNode [SerializeReference]
├── AndConditionNode
│ ├── CompareConditionNode Level >= 10
│ ├── CompareConditionNode VIP >= 3
│ └── CompareConditionNode Tutorial == 1
└── OrConditionNode
├── CompareConditionNode HasItem == 1
└── ...

빠른 시작

1. ConditionGraph 에셋 만들기

Create → AchUtils/Condition/Condition Graph

인스펙터에서 Root[+] 버튼으로 노드를 추가합니다.

2. 조건 평가

using AchUtils.Condition;

// 컨텍스트에 현재 게임 상태 주입
var ctx = new ConditionContext();
ctx.Set("Level", player.Level);
ctx.Set("VIP", player.VipGrade);
ctx.Set("Tutorial", tutorialDone ? 1f : 0f);

// 그래프 평가
bool canOpen = shopConditionGraph.Evaluate(ctx);
shopPanel.SetActive(canOpen);

노드 종류

CompareConditionNode

숫자 값을 비교합니다.

필드타입설명
Keystring컨텍스트 키
OpCompareOp비교 연산자
Valuefloat비교 대상 값
public enum CompareOp
{
Equal, NotEqual,
Greater, GreaterOrEqual,
Less, LessOrEqual
}

AndConditionNode

자식 노드 모두 true일 때 true.

AND
├ Level >= 10 ✓
├ VIP >= 3 ✓
└ Tutorial == 1 ✓
→ true

OrConditionNode

자식 노드 하나라도 true이면 true.

OR
├ HasFreeItem == 1 ✓
└ HasDiscount == 1 ✗
→ true

NotConditionNode

자식 노드의 결과를 반전합니다.

NOT
└ IsBanned == 1 ✗
→ true

ConditionContext API

var ctx = new ConditionContext();

ctx.Set("Level", 15f);
ctx.Get("Level"); // 15f
ctx.Has("Level"); // true
ctx.Remove("Level");
ctx.Clear();

::: tip 컨텍스트 재사용 ConditionContext는 매 프레임 생성하지 말고 필드로 보유한 뒤 Set으로 값만 갱신하세요. :::

활용 사례

// 상점 노출 조건
shopGraph.Evaluate(ctx)

// 이벤트 오픈
eventGraph.Evaluate(ctx)

// 업적 달성 조건
achievementGraph.Evaluate(ctx)

// 광고 등장 조건
adGraph.Evaluate(ctx)

커스텀 노드 추가

[Serializable]
public class DateRangeConditionNode : ConditionNode
{
public string StartDate; // "2024-12-25"
public string EndDate;

public override bool Evaluate(ConditionContext context)
{
var now = DateTime.Now;
return now >= DateTime.Parse(StartDate)
&& now <= DateTime.Parse(EndDate);
}
}

[SerializeReference][Serializable] 어트리뷰트만 붙이면 인스펙터에서 바로 사용 가능합니다.