함수와 이벤트
블루프린트에서 로직을 모듈화하는 함수와 이벤트의 차이를 마스터합니다
함수 정의와 호출
사용자 정의 함수의 생성, 파라미터, 반환값
함수 생성
My Blueprint 패널에서 Functions 옆의 + 버튼을 클릭하여 함수를 생성합니다.
함수는 별도의 그래프 탭에서 편집하며, 항상 하나의 진입점(Entry 노드)에서 시작합니다.
// 함수: CalculateDamage
// 입력: BaseDamage (Float), CritMultiplier (Float), IsCritical (Boolean)
// 출력: FinalDamage (Float)
[Entry] ──> [Branch] ──True──> [Multiply] ──> [Return Node]
├─ BaseDamage │ ├─ A: BaseDamage ├─ FinalDamage
├─ CritMultiplier │ └─ B: CritMultiplier
└─ IsCritical ─────────┘
│
└──False──> [Return Node]
└─ FinalDamage: BaseDamage
입력/출력 파라미터 추가
함수를 선택한 상태에서 Details 패널의 Inputs와 Outputs 섹션에서
+ 버튼으로 파라미터를 추가합니다. 각 파라미터의 이름과 타입을 지정합니다.
Output 파라미터를 추가하면 자동으로 Return Node가 생성됩니다. 함수 내 모든 실행 경로는 반드시 Return Node에 도달해야 합니다. 우클릭 > Add Return Node로 여러 반환 지점을 만들 수 있습니다.
함수의 주요 속성
| 속성 | 설명 |
|---|---|
| Pure | 체크하면 실행 핀이 제거됩니다. 부작용 없이 값만 반환하는 계산 함수에 적합합니다. 연결될 때마다 재평가됩니다. |
| Call In Editor | 에디터의 Details 패널에서 버튼으로 호출할 수 있습니다. 디버깅/테스트에 유용합니다. |
| Access Specifier | Public(외부 호출 가능), Protected(자식만), Private(자신만) |
| Const | 함수가 오브젝트의 상태를 변경하지 않음을 보장합니다. const 함수 안에서는 Set 노드를 사용할 수 없습니다. |
| Description | 함수 노드에 마우스를 올렸을 때 표시되는 설명 텍스트입니다. |
이벤트 그래프
게임 이벤트에 반응하는 이벤트 그래프의 구조와 주요 이벤트
이벤트 그래프란?
이벤트 그래프(Event Graph)는 블루프린트의 메인 실행 환경입니다. 함수 그래프와 달리 여러 진입점(이벤트 노드)을 가질 수 있으며, Latent 노드(Delay, Timeline 등)를 사용할 수 있습니다.
주요 이벤트 노드
| 이벤트 | 발생 시점 | 주요 용도 |
|---|---|---|
| Event BeginPlay | Actor가 월드에서 활성화될 때 (1회) | 초기화, 참조 설정, 타이머 시작 |
| Event Tick | 매 프레임 | 지속적 업데이트. Delta Seconds 핀 제공 |
| Event EndPlay | Actor 파괴 또는 레벨 전환 시 | 정리(cleanup), 참조 해제 |
| Event ActorBeginOverlap | 다른 Actor와 오버랩 시작 | 트리거 존, 아이템 수집 |
| Event ActorEndOverlap | 오버랩 종료 | 영역 이탈 처리 |
| Event Hit | 물리적 충돌 발생 | 충돌 반응, 데미지 처리 |
| Event Any Damage | ApplyDamage 호출 시 | 데미지 처리 로직 |
// Event Tick을 사용한 프레임 독립적 이동
[Event Tick] ──> [AddActorWorldOffset]
└─ Delta Seconds ──> [Multiply] ──> [Make Vector] ──> Delta Location
├─ A: Delta Seconds
└─ B: 200.0 (Speed)
// Delta Seconds를 곱해야 프레임 레이트와 무관하게 일정한 속도로 이동
Event Tick은 매 프레임 실행되므로 비용이 큽니다. 가능하면 Timer나 이벤트 기반 방식으로 대체하세요. Actor의 Details > Tick 섹션에서 Start with Tick Enabled를 해제하면 불필요한 Tick을 방지할 수 있습니다. 필요 시 Set Actor Tick Enabled로 동적으로 제어합니다.
함수 vs 이벤트 vs 매크로
세 가지 실행 단위의 차이점과 사용 시나리오
| 특성 | 함수 (Function) | 이벤트 (Event) | 매크로 (Macro) |
|---|---|---|---|
| 실행 방식 | 호출 시 즉시 실행, 완료 후 반환 | 비동기적 트리거 | 인라인 확장 (컴파일 시) |
| 반환값 | 가능 (Output 핀) | 불가 | 가능 (Output Exec 여러 개) |
| Latent 노드 | 사용 불가 | 사용 가능 (Delay, Timeline) | 사용 가능 |
| 로컬 변수 | 지원 | 미지원 | 미지원 |
| 외부 호출 | 다른 BP에서 호출 가능 | 다른 BP에서 호출 가능 | 매크로 라이브러리 통해 공유 |
| 오버라이드 | 가능 (부모 함수) | 가능 (부모 이벤트) | 불가 |
사용자 정의 이벤트
이벤트 그래프에서 우클릭 > Add Custom Event로 생성합니다.
Custom Event는 함수처럼 입력 파라미터를 가질 수 있지만, 반환값이 없습니다.
대신 Latent 노드(Delay, Timeline)를 사용할 수 있어 비동기 로직에 적합합니다.
// Custom Event: PlayHitReaction
// Input: DamageAmount (Float), HitDirection (Vector)
[Custom Event: PlayHitReaction]
├─ DamageAmount
└─ HitDirection
│
├──> [Play Anim Montage] ──> [Delay] ──> [Reset State]
│ └─ Montage: AM_HitReact └─ 0.5s
│
└──> [Apply Knockback]
└─ LaunchVelocity: HitDirection * DamageAmount
매크로 활용
매크로는 My Blueprint > Macros에서 +로 생성합니다.
매크로의 가장 큰 장점은 실행 출력 핀을 여러 개 만들 수 있다는 것입니다.
// 매크로: SafeGetComponent
// Input Exec: Execute
// Input: TargetActor (Actor Reference)
// Output Exec 1: Valid
// Output Exec 2: Invalid
// Output: Component (ActorComponent Reference)
[Inputs] ──> [IsValid] ──True──> [Get Component by Class] ──> [Valid]
└─ TargetActor ──┘ └──False──> [Invalid]
함수 사용: 반환값이 필요하거나, 로컬 변수가 필요하거나, Pure 계산일 때
이벤트 사용: Delay/Timeline이 필요하거나, 외부에서 비동기적으로 트리거할 때
매크로 사용: 여러 실행 출력이 필요하거나, 반복되는 흐름 제어 패턴을 추상화할 때
오버라이드와 부모 호출
부모 클래스의 함수/이벤트를 재정의하고 확장합니다
함수 오버라이드
My Blueprint > Functions > Override 드롭다운에서 부모 클래스의 함수를 선택하면, 해당 함수를 오버라이드할 수 있습니다. 부모의 동작을 유지하면서 추가 로직을 넣으려면 Add call to parent function을 사용합니다.
// BeginPlay 오버라이드 (자식 블루프린트에서)
[Event BeginPlay] ──> [Parent: BeginPlay] ──> [Custom Init Logic]
│
├─ Set Health = 100
├─ Set Mana = 50
└─ Bind Input Actions
// Parent: BeginPlay를 먼저 호출하여 부모의 초기화를 실행한 뒤
// 자식 클래스의 추가 초기화 로직을 실행
주요 오버라이드 가능 함수
| 함수 | 클래스 | 설명 |
|---|---|---|
| BeginPlay | Actor | 게임 시작 시 1회 호출 |
| Tick | Actor | 매 프레임 호출 |
| GetLifetimeReplicatedProps | Actor | 복제 속성 설정 (멀티플레이어) |
| SetupPlayerInputComponent | Pawn | 입력 바인딩 설정 |
| Landed | Character | 착지 시 호출 |
| CanJumpInternal | Character | 점프 가능 여부 판단 |
이벤트 바인딩
컴포넌트의 이벤트(OnComponentBeginOverlap 등)를 이벤트 그래프에 바인딩할 수 있습니다.
컴포넌트를 선택한 후 Details > Events 섹션에서 + 버튼을 클릭합니다.
// Box Collision의 OnComponentBeginOverlap 이벤트 바인딩
[OnComponentBeginOverlap (BoxCollision)]
├─ Overlapped Component: UPrimitiveComponent*
├─ Other Actor: AActor*
├─ Other Comp: UPrimitiveComponent*
├─ Other Body Index: int32
├─ bFromSweep: bool
└─ Sweep Result: FHitResult
│
└──> [Cast To BP_Player] ──Success──> [Collect Item]
함수를 오버라이드할 때 Parent 호출을 잊으면 부모의 로직이 완전히 무시됩니다. 특히 BeginPlay, EndPlay, Tick 같은 생명주기 이벤트에서 Parent 호출을 빠뜨리면 C++ 부모 클래스의 중요한 초기화 코드가 실행되지 않아 예기치 않은 버그가 발생할 수 있습니다. 의도적으로 부모 동작을 완전히 대체하는 경우가 아니라면 항상 Parent를 호출하세요.
핵심 요약
- 함수는 반환값과 로컬 변수를 지원하지만 Latent 노드를 사용할 수 없다
- 이벤트는 반환값이 없지만 Delay, Timeline 같은 Latent 노드를 사용할 수 있다
- 매크로는 컴파일 시 인라인 확장되며, 여러 개의 실행 출력 핀을 가질 수 있다
- Event BeginPlay(1회), Event Tick(매 프레임), Event EndPlay(파괴 시)가 핵심 생명주기 이벤트이다
- Pure 함수는 실행 핀 없이 값만 반환하며, 연결된 곳마다 재평가된다
- 오버라이드 시 Parent 함수 호출을 잊지 않도록 주의한다
도전 과제
배운 내용을 직접 실습해보세요
CalculateDamage 함수를 생성하세요. 입력 파라미터로 BaseDamage(Float), CriticalMultiplier(Float), ArmorValue(Float)를 받고, 최종 데미지를 반환합니다. Pure 함수와 일반 함수 두 가지 버전으로 만들어 차이를 확인하세요.
동일한 로직(체력 회복: 현재 HP + 회복량, 최대치 클램프)을 Custom Event, Function, Macro 세 가지 방식으로 각각 구현하세요. Event Graph에서 세 가지를 모두 호출하고 결과를 비교해보세요.
블루프린트 함수 라이브러리를 생성하여 프로젝트 전역에서 사용할 수 있는 유틸리티 함수 3개(FormatTime, ClampVector, IsInRange)를 구현하세요. 다른 블루프린트에서 이 함수들을 호출하여 동작을 검증하세요.