Skip to content

Flow Module

Technical Docs · Flow Module

Flow

Universal Graph Runtime

게임 모드 시퀀스, 텍스쳐 생성, 캐릭터 조립, 이벤트 체인 — 어떤 절차든 노드 그래프로 표현하고 UniTask 기반으로 비동기 실행합니다.

Runtime UniTask StateMachine Graph
ASYNC
UniTask
CONTEXTS
3+
EXECUTION
Depth-first
STORAGE
ScriptableObject
USE CASES

절차적 표현 예시

GameMode Graph
게임 세션 시퀀스와 상태 전환
GameplayFlowNode
게임 시작
월드 로드scene
플레이어 스폰
이벤트 대기
종료 조건
게임 종료

각 노드는 async — 이벤트 대기, 딜레이, 조건부 분기 모두 자연스럽게 표현

Texture Graph
텍스쳐 생성 파이프라인
DataFlowNode
BaseColor
BrickPattern
Blend
Noise
출력

실행 흐름 없이 순수 데이터 변환 — 출력 노드가 평가될 때 입력을 역방향으로 pull

Character Assembly Graph
캐릭터 빌드 단계별 조립
DataFlowNode
골반 Pivot
하체 조립
상체 + 팔
머리 부착
캐릭터 완성

같은 그래프 구조로 조립 순서·파츠 교체 가능 — 코드 변경 없이 에디터에서 수정

CORE ARCHITECTURE

핵심 구성요소

FlowAsset
ScriptableObject

그래프 구조를 에셋으로 저장하는 컨테이너. 노드 목록, 실행 링크(ExecutionLink), 값 링크(ValueLink)를 보유합니다.

nodesList<FlowNode>
executionLinksfrom → to (슬롯 포함)
valueLinksfrom.slot → to.slot
contextProfile허용 노드 타입 필터
IImmutableFlowSerializable
FlowNode
abstract

그래프 내 하나의 실행 단위. 입/출력 포트를 선언하고 비동기 진입(EnterAsync)과 실행(RunAsync)을 구현합니다.

EnterAsync(ct)노드 초기화
RunAsync(ct)메인 로직 실행
TryValueOut<T>타입 안전 값 출력
GetValueInputPorts입력 포트 정의 목록
INodeIFlowValueNode
FlowSession
Runtime

그래프를 실제로 실행하는 컨텍스트. EntryNode부터 깊이 우선으로 순회하며 실행 흐름을 관리합니다.

BeginAsync(ct, owner)실행 시작
End() / Dispose()중단 및 정리
Blackboard노드 간 공유 데이터
UniTaskCancellationToken
Blackboard & Properties
Runtime Data

세션 내 노드들이 공유하는 데이터 레이어. FlowBlackboard는 int 키 딕셔너리, FlowProperty<T>는 Observable 값입니다.

Blackboard.Set<T>(key, val)런타임 데이터 저장
Blackboard.TryGet<T>타입 안전 읽기
Property.Subscribe(cb)값 변경 구독
ObservableType-safe
NODE TAXONOMY

노드 분류

FlowNode abstract
GameplayFlowNode
게임플레이 로직 · 실행 흐름 제어 · 씬 액세스 가능
DelayIfSpawnPawnWaitForEvent
DataFlowNode
순수 데이터 변환 · 부수 효과 없음 · 값 계산 전용
ConstantIntMathAddIf (값 선택)EntrySlotFlowNode
AlwaysAllowedFlowNode
컨텍스트 프로파일 관계없이 모든 그래프에서 허용
FlowEntryNodeFlowExitNodePrint
GraphContextProfile — 그래프 종류별 허용 노드 제어
GlobalProfile
모든 노드 허용 — 개발·테스트용
GameplayGraphContextProfile
GameplayFlowNode + DataFlowNode
DataGraphContextProfile
DataFlowNode 전용 — 텍스쳐·데이터 변환
EXECUTION MODEL

실행 모델

1
값 입력 와이어링

세션 시작 시 각 노드의 입력 포트에 소스 노드를 연결합니다. 이후 실행 중 소스 노드의 출력값이 자동으로 흐릅니다.

2
깊이 우선 실행 (Depth-First)

pendingNodes 스택에서 노드를 꺼내며 EnterAsync → RunAsync 순으로 실행 후 다음 노드들을 스택에 추가합니다.

3
값 Pull 방식

노드가 입력값을 필요로 할 때 TryGetInputOverrideData<T>로 연결된 소스에서 값을 당겨옵니다.

4
CancellationToken 전파

모든 async 호출에 동일한 CancellationToken이 전파됩니다. 세션이 End()되거나 오너가 파괴되면 전체 실행이 취소됩니다.

FlowSession 실행 의사코드
var pending = new List<INode> { flow.EntryNode };

while (pending.Count > 0) {
    var node = pending[^1];
    pending.RemoveAt(^1);

    ApplyValueInputs(node);       // 입력 포트 값 세팅
    await node.EnterAsync(ct);    // 진입 (딜레이, 준비)
    await node.RunAsync(ct);      // 실행

    pending.AddRange(            // 다음 노드 추가
        flow.GetNextNodes(node)
    );
}
CUSTOM NODE

커스텀 노드 작성

[FlowNode] 어트리뷰트

에디터 팔레트에 표시될 이름과 카테고리 지정

ValuePortDefinition

슬롯 번호와 값 타입으로 포트 선언

GetInputOverrideOrDefault

연결된 포트값 없으면 직렬화 필드 fallback

async UniTask

딜레이·대기·비동기 작업을 자연스럽게 표현

Delay.cs — 커스텀 노드 예시
[FlowNode("Delay", "Timing")]
public sealed class Delay : GameplayFlowNode {

    // 입력 포트: slot 0, 타입 float
    private static readonly IReadOnlyList<ValuePortDefinition> _inputs =
        new[] { new ValuePortDefinition(0, typeof(float)) };

    [SerializeField] private float delaySeconds = 1.0f;

    public override IReadOnlyList<ValuePortDefinition> GetValueInputPorts() => _inputs;

    public override async UniTask EnterAsync(CancellationToken ct) {
        var duration = GetInputOverrideOrDefault(0, delaySeconds);
        if (duration > 0)
            await UniTask.Delay(
                TimeSpan.FromSeconds(duration),
                cancellationToken: ct
            );
    }
}