트리거 박스와 오버랩 이벤트
BoxComponent에 Begin·End Overlap 이벤트를 연결해 대상 진입과 이탈에 반응하는 트리거를 구현합니다.
플레이어가 문 앞에 다가가면 "E 키를 눌러 열기"라는 안내가 뜨고, 문에서 멀어지면 사라지는 기능을 생각해 봅시다. 이 기능에는 벽처럼 플레이어를 막는 충돌이 필요하지 않습니다. 필요한 것은 플레이어가 어떤 영역에 들어왔는지와 나갔는지를 아는 일뿐입니다. 이렇게 막지 않고 감지만 하는 영역을 트리거(trigger)라고 합니다.
충돌 채널과 프로파일 설정에서 오버랩 응답과 이벤트 조건을 보았으니, 이 글에서는 UBoxComponent로 만든 트리거 박스로 진입과 이탈에 반응하는 방법을 자세히 살펴봅니다. 오버랩 이벤트가 넘겨주는 매개변수의 뜻을 정리하고, 콜백이 온 횟수와 "영역 안에 누가 있는가"라는 상태가 왜 다른지도 따라가 봅니다.
트리거는 무엇을 하는가
트리거는 게임 월드 안의 특정 영역(volume)으로, 플레이어나 다른 액터가 그 영역에 들어오거나 나갔을 때 미리 정한 게임플레이 이벤트를 일으킵니다. 일반적인 충돌 물체와 달리 이동을 막지 않고 감지만 한다는 점이 다릅니다.
트리거는 여러 상황에 쓰입니다. 플레이어가 아이템 위에 서면 아이템을 얻고 그 아이템을 사라지게 할 수 있고, 문 앞의 영역에 들어오면 문이 자동으로 열리게 할 수 있습니다. 새로운 지역에 들어서면 지역 이름을 화면에 띄우거나 배경 음악을 바꾸고, 특정 지점에 이르면 컷신을 시작하고, 지나가면 체크포인트를 활성화하는 것도 모두 트리거로 만듭니다.
UBoxComponent로 만드는 트리거 박스
언리얼에서 가장 흔한 트리거는 UBoxComponent를 바탕으로 한 트리거 볼륨입니다. UBoxComponent는 직육면체 모양의 충돌 감지 영역을 제공하며, 이를 트리거 용도로 설정합니다.
트리거 박스에는 몇 가지 특징이 있습니다. 기본적으로 화면에 그려지지 않으므로 게임 안에서는 보이지 않고, 에디터에서만 선으로 된 상자 모양으로 보여 배치와 크기 조절을 돕습니다. 또 물리적으로 다른 물체를 막지 않도록, 감지할 대상 채널에 대한 응답을 Overlap으로 맞춥니다. 여기서 쿼리에만 참여하는 QueryOnly는 SetCollisionEnabled의 값이고, OverlapAll 같은 이름은 응답을 묶은 프리셋이라는 점을 구분합니다. 다른 충돌 컴포넌트와 겹치면 OnComponentBeginOverlap과 OnComponentEndOverlap 이벤트를 일으킵니다.
C++로 트리거 박스 만들기
앞 글에서 만든 AMyTriggerVolume을 다시 살펴보겠습니다. 이번에는 겹친 폰이 로컬 플레이어인지까지 확인합니다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyTriggerVolume.generated.h"
class UBoxComponent; // UBoxComponent를 미리 선언
UCLASS()
class MYPROJECT_API AMyTriggerVolume : public AActor
{
GENERATED_BODY()
public:
AMyTriggerVolume(); // 생성자
protected:
virtual void BeginPlay() override; // 액터 초기화 시 호출
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Collision")
UBoxComponent* TriggerBox; // 트리거 박스 컴포넌트 포인터
// 오버랩 시작 이벤트에 바인딩될 함수
// UFUNCTION 매크로 필수: 델리게이트에 바인딩되기 위해 리플렉션 시스템에 노출되어야 함
UFUNCTION()
void OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
// 오버랩 종료 이벤트에 바인딩될 함수
UFUNCTION()
void OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};헤더의 주석에 적힌 것처럼, 델리게이트에 바인딩할 두 함수는 리플렉션 시스템에 등록되어야 하므로 UFUNCTION()이 꼭 필요합니다. 두 함수의 매개변수 목록이 긴 것도 델리게이트 때문입니다. 바인딩할 델리게이트가 정한 형식과 순서를 그대로 따라야 하므로, 이 예제에서 쓰지 않는 OtherBodyIndex나 SweepResult 같은 매개변수도 지우지 않습니다. 아래 cpp는 생성자의 충돌 설정, BeginPlay의 바인딩, 두 콜백의 플레이어 확인 순서로 읽으면 됩니다.
#include "MyTriggerVolume.h"
#include "Components/BoxComponent.h" // UBoxComponent 헤더 포함
#include "GameFramework/Pawn.h" // APawn과 제어 상태 검사
AMyTriggerVolume::AMyTriggerVolume()
{
// 액터가 매 프레임 업데이트될 필요가 없다면 틱 비활성화
PrimaryActorTick.bCanEverTick = false;
// UBoxComponent 생성
TriggerBox = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerBox"));
RootComponent = TriggerBox; // 트리거 박스를 액터의 루트 컴포넌트로 설정
// 충돌 설정: 오버랩 전용으로 설정
// Project Settings의 Collision Preset에 "TriggerOnly"와 같은 프로파일이 없다면
// 기본 OverlapAllDynamic을 사용하거나 직접 커스텀 설정을 할 수 있습니다.
TriggerBox->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
// TriggerBox->SetCollisionEnabled(ECollisionEnabled::QueryOnly); // 쿼리만 가능, 물리 없음
// TriggerBox->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic); // 이 트리거의 오브젝트 타입
// 중요: 오버랩 이벤트를 발생시키도록 설정
TriggerBox->SetGenerateOverlapEvents(true);
// (선택 사항) 트리거 박스의 크기 설정
TriggerBox->SetBoxExtent(FVector(100.0f, 100.0f, 100.0f)); // 각 축 반길이 100 cm: 스케일 1에서 전체 크기 200x200x200 cm
}
void AMyTriggerVolume::BeginPlay()
{
Super::BeginPlay();
// 오버랩 이벤트를 C++ 함수에 바인딩
// OnComponentBeginOverlap 델리게이트에 OnOverlapBegin 함수를 연결합니다.
TriggerBox->OnComponentBeginOverlap.AddDynamic(this, &AMyTriggerVolume::OnOverlapBegin);
TriggerBox->OnComponentEndOverlap.AddDynamic(this, &AMyTriggerVolume::OnOverlapEnd);
}
void AMyTriggerVolume::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
// 오버랩된 액터가 유효하고, 자기 자신이 아니며, 플레이어 폰인지 확인하는 것이 일반적입니다.
// 플레이어 폰인지 확인하는 예시:
if (OtherActor && OtherActor != this && OtherActor->IsA(APawn::StaticClass()))
{
APawn* PlayerPawn = Cast<APawn>(OtherActor); // Pawn으로 캐스팅; 아래에서 플레이어 제어 여부 확인
if (PlayerPawn && PlayerPawn->IsPlayerControlled() && PlayerPawn->IsLocallyControlled()) // 로컬 플레이어인지 확인
{
UE_LOG(LogTemp, Warning, TEXT("Local Player entered: %s"), *PlayerPawn->GetName());
// 여기에 플레이어가 트리거에 진입했을 때 실행할 게임플레이 로직을 구현합니다.
// 예: "아이템 획득!" 메시지 표시, 문 열기 함수 호출 등.
}
}
}
void AMyTriggerVolume::OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (OtherActor && OtherActor != this && OtherActor->IsA(APawn::StaticClass()))
{
APawn* PlayerPawn = Cast<APawn>(OtherActor);
if (PlayerPawn && PlayerPawn->IsPlayerControlled() && PlayerPawn->IsLocallyControlled())
{
UE_LOG(LogTemp, Warning, TEXT("Local Player exited: %s"), *PlayerPawn->GetName());
// 여기에 플레이어가 트리거에서 이탈했을 때 실행할 로직을 구현합니다.
// 예: "아이템 획득 가능" 메시지 숨기기 등.
}
}
}생성자의 핵심 설정은 세 가지입니다. 먼저 SetCollisionProfileName(TEXT("OverlapAllDynamic"))은 기본 정의에서 자신의 채널을 WorldDynamic으로 두고, 다른 채널에 모두 Overlap으로 응답하는 프로파일입니다. 이름에 Dynamic이 들어 있지만 감지 대상을 움직이는 물체로만 제한한다는 뜻은 아니며, 프로젝트에 더 세분화한 커스텀 프로파일이 있다면 그 이름을 쓰면 됩니다. 다음으로 SetGenerateOverlapEvents(true)로 이벤트를 켜는데, 이 설정은 실제로 겹치는 양쪽 컴포넌트에서 모두 켜져 있어야 하고 쿼리 참여와 서로의 응답도 맞아야 합니다. 마지막으로 SetBoxExtent(FVector(100.0f, 100.0f, 100.0f))는 박스의 각 축 반길이를 100cm로 정하므로, 스케일이 1이면 전체 크기는 200×200×200cm가 됩니다.
BeginPlay의 OnComponentBeginOverlap.AddDynamic(this, &AMyTriggerVolume::OnOverlapBegin)은 언리얼의 델리게이트 시스템에서 이벤트에 함수를 바인딩하는 코드입니다. OnComponentBeginOverlap은 UPrimitiveComponent가 제공하는 멀티캐스트 델리게이트(multicast delegate)로, 여러 함수를 함께 바인딩할 수 있고 겹침이 시작될 때 바인딩된 함수를 모두 부릅니다. 첫 번째 인자 this는 이벤트를 받을 객체이고, 두 번째 인자 &AMyTriggerVolume::OnOverlapBegin은 바인딩할 멤버 함수의 주소입니다. 이 함수는 UFUNCTION()으로 선언되어 있어야 하고, 매개변수가 델리게이트의 형식과 정확히 같아야 합니다.
콜백에서는 겹친 액터가 자기 자신이 아닌 폰인지 확인하고, 다시 IsPlayerControlled()와 IsLocallyControlled()로 이 실행 인스턴스에서 로컬 플레이어가 조종하는 폰인지 확인한 뒤 로그를 남깁니다. 이 두 조건은 이 실행에서 로컬 플레이어를 고르는 조건일 뿐, 서버가 모든 접속자의 아이템 획득을 확정하는 권한 검사나 원격 클라이언트와의 동기화까지 구현한 것은 아닙니다.
이 예제는 BeginPlay에서 구독한 뒤에 오는 콜백만 기록합니다. 게임이 시작될 때 이미 박스 안에 있던 대상까지 상태에 넣어야 한다면, 구독과 별도로 현재 겹친 목록을 조회해 초기화해야 합니다.
오버랩 이벤트의 매개변수
OnOverlapBegin과 OnOverlapEnd가 받는 매개변수는 겹침에 관한 정보를 담고 있습니다.
| 매개변수 | 뜻 |
|---|---|
UPrimitiveComponent* OverlappedComp | 이벤트를 일으킨 이쪽 컴포넌트, 즉 TriggerBox 자신 |
AActor* OtherActor | 트리거 박스와 겹친 다른 액터 |
UPrimitiveComponent* OtherComp | OtherActor 안에서 실제로 겹친 컴포넌트(예: 플레이어 캐릭터의 캡슐) |
int32 OtherBodyIndex | 상대 컴포넌트에서 겹친 물리 바디의 인덱스로, 일반적인 본 인덱스와 같다고 볼 수 없음 |
bool bFromSweep | 스윕 검사로 겹침이 생겼는지 여부(속도를 뜻하는 값이 아님) |
const FHitResult& SweepResult | bFromSweep이 참일 때 스윕 검사의 자세한 결과 |
이 매개변수로 어떤 액터의 어떤 컴포넌트가 트리거와 만났는지 정확히 알 수 있습니다. 특히 OtherComp는 뒤에서 볼 점유 상태 문제를 다룰 때 중요합니다.
블루프린트에서 이벤트 다루기
C++로 만든 AMyTriggerVolume을 부모로 블루프린트 클래스 BP_MyTriggerVolume을 만들면 레벨에 배치해 쓸 수 있습니다. 인스턴스를 레벨로 끌어다 놓고, 디테일 패널에서 TriggerBox 컴포넌트의 Box Extent를 조절해 원하는 크기로 만듭니다.
블루프린트 에디터에서는 TriggerBox 컴포넌트를 선택한 뒤 디테일 패널 아래쪽의 이벤트 목록에서 On Component Begin Overlap과 On Component End Overlap 이벤트를 추가할 수 있습니다. 이벤트 노드의 Other Actor 핀에서 끌어 Cast To ThirdPersonCharacter(또는 직접 만든 캐릭터 클래스) 같은 노드로 타입을 확인하고, 플레이어만 처리하려면 Is Player Controlled 같은 조건도 확인합니다. 다만 같은 동작을 C++ 콜백과 블루프린트에서 함께 실행하지 않도록 주의합니다.
콜백 횟수와 점유 상태는 다르다
겹침 콜백 기록과 액터 점유 상태는 다릅니다
예시 BeginC→BeginM→EndC→EndM에서 {}→{C}→{C,M}→{M}→{}가 되어 EndC 뒤 점유가 유지되는 구체 상태이다.
UNREAL C++ · CH5-2
겹침 콜백 기록과 액터 점유 상태는 다릅니다
본문 코드는 플레이어 제어·로컬 제어 Pawn만 진입과 이탈을 로그로 남깁니다. 영역 안에 머무는 액터의 상태를 유지하려면 추가 정책이 필요합니다.
C/M은 같은 Pawn의 서로 다른 허용 컴포넌트·바디 키입니다. 집합의 빈 상태가 액터 점유 해제 조건이며, 중복 시작 키·없는 종료 키·파괴와 초기 상태 정리는 별도 정책으로 처리합니다.
| 받은 사건 | 예제의 처리 | 상태를 유지할 때의 판단 |
|---|---|---|
| BeginOverlap | 로컬 플레이어 Pawn이면 진입 로그 | 캡슐·메시 등 여러 컴포넌트가 겹칠 수 있어 처리 대상 부품을 정함 |
| EndOverlap | 같은 필터를 통과하면 이탈 로그 | 한 컴포넌트의 이탈을 액터 전체의 퇴장으로 단정하지 않음 |
| 영역에 머무름 | 별도 지속 처리 없음 | 필요할 때만 점유 집합이나 타이머로 유지 효과를 관리 |
- BeginOverlap
- 예제의 처리: 로컬 플레이어 Pawn이면 진입 로그상태를 유지할 때의 판단: 캡슐·메시 등 여러 컴포넌트가 겹칠 수 있어 처리 대상 부품을 정함
- EndOverlap
- 예제의 처리: 같은 필터를 통과하면 이탈 로그상태를 유지할 때의 판단: 한 컴포넌트의 이탈을 액터 전체의 퇴장으로 단정하지 않음
- 영역에 머무름
- 예제의 처리: 별도 지속 처리 없음상태를 유지할 때의 판단: 필요할 때만 점유 집합이나 타이머로 유지 효과를 관리
컴포넌트의 콜백 호출 기록을 액터의 단 한 번 진입·퇴장이나 UI 상태 복구로 읽지 않습니다. BeginPlay 구독 전에 이미 겹친 대상을 포함하려면 현재 겹침 목록을 별도로 조회해 초기화합니다.
이 예의 조건
- 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
- 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
관계도의 보충 설명
| 범위 | 원문 |
|---|---|
| 본문·주석 | 본문 코드는 플레이어 제어·로컬 제어 Pawn의 진입과 이탈만 로그로 남깁니다. 영역 안에 머무는 액터의 상태를 유지하려면 추가 정책이 필요합니다. |
| 관계·조건 설명 | 같은 허용 Pawn의 캡슐 C와 메시 M이 겹치는 사건 순서 하나를 예로 든다. 비어 있는 집합에서 BeginC, BeginM, EndC, EndM을 받으면 집합은 C, C와 M, M, 비어 있음으로 바뀐다. EndC 뒤에도 M이 남으므로 액터 점유는 유지된다. 실제 모든 콜백의 전역 순서를 보장하거나 원래 로그 예제에 집합이 구현됐다는 뜻은 아니다. |
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 두 Begin C와 M 컴포넌트의 겹침이 차례로 등록된다. |
|
|
| EndC C만 나가도 M은 영역에 남는다. |
|
|
| EndM 마지막 컴포넌트가 나가 점유 집합이 빈다. |
|
|
겹침 콜백 기록과 액터 점유 상태는 다릅니다
예시 BeginC→BeginM→EndC→EndM에서 {}→{C}→{C,M}→{M}→{}가 되어 EndC 뒤 점유가 유지되는 구체 상태이다.
UNREAL C++ · CH5-2
겹침 콜백 기록과 액터 점유 상태는 다릅니다
본문 코드는 플레이어 제어·로컬 제어 Pawn만 진입과 이탈을 로그로 남깁니다. 영역 안에 머무는 액터의 상태를 유지하려면 추가 정책이 필요합니다.
C/M은 같은 Pawn의 서로 다른 허용 컴포넌트·바디 키입니다. 집합의 빈 상태가 액터 점유 해제 조건이며, 중복 시작 키·없는 종료 키·파괴와 초기 상태 정리는 별도 정책으로 처리합니다.
| 받은 사건 | 예제의 처리 | 상태를 유지할 때의 판단 |
|---|---|---|
| BeginOverlap | 로컬 플레이어 Pawn이면 진입 로그 | 캡슐·메시 등 여러 컴포넌트가 겹칠 수 있어 처리 대상 부품을 정함 |
| EndOverlap | 같은 필터를 통과하면 이탈 로그 | 한 컴포넌트의 이탈을 액터 전체의 퇴장으로 단정하지 않음 |
| 영역에 머무름 | 별도 지속 처리 없음 | 필요할 때만 점유 집합이나 타이머로 유지 효과를 관리 |
- BeginOverlap
- 예제의 처리: 로컬 플레이어 Pawn이면 진입 로그상태를 유지할 때의 판단: 캡슐·메시 등 여러 컴포넌트가 겹칠 수 있어 처리 대상 부품을 정함
- EndOverlap
- 예제의 처리: 같은 필터를 통과하면 이탈 로그상태를 유지할 때의 판단: 한 컴포넌트의 이탈을 액터 전체의 퇴장으로 단정하지 않음
- 영역에 머무름
- 예제의 처리: 별도 지속 처리 없음상태를 유지할 때의 판단: 필요할 때만 점유 집합이나 타이머로 유지 효과를 관리
컴포넌트의 콜백 호출 기록을 액터의 단 한 번 진입·퇴장이나 UI 상태 복구로 읽지 않습니다. BeginPlay 구독 전에 이미 겹친 대상을 포함하려면 현재 겹침 목록을 별도로 조회해 초기화합니다.
이 예의 조건
- 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
- 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
관계도의 보충 설명
| 범위 | 원문 |
|---|---|
| 본문·주석 | 본문 코드는 플레이어 제어·로컬 제어 Pawn의 진입과 이탈만 로그로 남깁니다. 영역 안에 머무는 액터의 상태를 유지하려면 추가 정책이 필요합니다. |
| 관계·조건 설명 | 같은 허용 Pawn의 캡슐 C와 메시 M이 겹치는 사건 순서 하나를 예로 든다. 비어 있는 집합에서 BeginC, BeginM, EndC, EndM을 받으면 집합은 C, C와 M, M, 비어 있음으로 바뀐다. EndC 뒤에도 M이 남으므로 액터 점유는 유지된다. 실제 모든 콜백의 전역 순서를 보장하거나 원래 로그 예제에 집합이 구현됐다는 뜻은 아니다. |
| 관찰·상황 | 값·보충 정보 | 변화·이유 |
|---|---|---|
| 두 Begin C와 M 컴포넌트의 겹침이 차례로 등록된다. |
|
|
| EndC C만 나가도 M은 영역에 남는다. |
|
|
| EndM 마지막 컴포넌트가 나가 점유 집합이 빈다. |
|
|
위 그림은 같은 폰의 두 컴포넌트가 트리거와 겹칠 때, 겹친 컴포넌트의 집합이 어떻게 바뀌는지를 보여 줍니다. 허용한 폰의 캡슐 C와 메시 M이 겹치는 사건 순서를 예로 들면, 비어 있던 집합은 Begin(C) 뒤에 {C}, Begin(M) 뒤에 {C, M}, End(C) 뒤에 {M}, End(M) 뒤에 다시 비게 됩니다. 핵심은 End(C) 직후에도 M이 남아 있어서 그 폰이 여전히 영역을 점유하고 있다는 점입니다. 그림은 이 사건 순서를 예로 든 것일 뿐, 모든 콜백이 늘 이 순서로 온다는 뜻도 아니고 앞의 로그 예제에 이 집합이 구현되어 있다는 뜻도 아닙니다.
그림의 표는 받은 사건마다 예제가 하는 일과, 상태를 유지하려면 판단할 점을 나란히 둡니다. BeginOverlap이 오면 예제는 로컬 플레이어의 폰일 때 진입 로그를 남기지만, 캡슐과 메시처럼 여러 컴포넌트가 겹칠 수 있으므로 어떤 부품을 처리 대상으로 할지 정해야 합니다. EndOverlap이 오면 같은 조건에서 이탈 로그를 남기지만, 한 컴포넌트가 나간 것을 액터 전체의 퇴장으로 판단하면 안 됩니다. 영역 안에 머무는 동안에는 예제가 따로 하는 일이 없으므로, 필요할 때만 점유 집합이나 타이머로 지속 효과를 관리합니다. 단계 그림도 두 Begin으로 C와 M이 차례로 등록되고, End(C) 뒤에도 M이 남으며, End(M)에서야 집합이 비는 과정을 따라갑니다.
이 차이를 놓치면 실제로 문제가 생깁니다. 앞 예제의 조건을 통과하는 같은 로컬 플레이어 폰에서 캡슐 C와 메시 M이 각각 겹친다면, Begin(C), Begin(M), End(C), End(M) 순서로 콜백이 오면서 진입 로그와 이탈 로그가 각각 두 번 남을 수 있습니다. End(C)가 왔을 때 플레이어가 완전히 나갔다고 판단해 안내 UI를 숨기면, 아직 M이 겹쳐 있는데도 UI가 너무 일찍 사라집니다.
게임 규칙이 캡슐만 감지하는 것이라면 OtherComp를 그 컴포넌트로 한정해 간단하게 만들 수 있습니다. 여러 부품을 허용해야 한다면, 액터마다 허용한 컴포넌트나 바디의 키를 집합으로 보관하고 그 집합이 비었는지로 점유를 판단하는 방법이 있습니다. 이때 같은 시작 키는 두 번 넣지 않고, 알고 있는 종료 키만 빼야 합니다. 대상이 파괴되거나 언로드되었을 때, 필터 조건이 바뀌었을 때의 정리와, 시작할 때 이미 겹쳐 있던 대상의 초기화도 함께 설계합니다.
정리
- 트리거는 이동을 막지 않고 영역에 들어오고 나가는 것만 감지하며, 아이템 획득, 문 열기, 지역 감지, 컷신, 체크포인트에 쓰입니다.
UBoxComponent로 만든 트리거 박스는OverlapAllDynamic같은 오버랩 프로파일, 양쪽의GenerateOverlapEvents,SetBoxExtent의 반길이로 설정합니다.OnComponentBeginOverlap,OnComponentEndOverlap은 멀티캐스트 델리게이트이며,AddDynamic으로 바인딩할 함수는UFUNCTION()이고 매개변수 형식이 같아야 합니다.OtherActor와OtherComp로 어떤 액터의 어떤 컴포넌트가 겹쳤는지 알 수 있으며,bFromSweep은 스윕으로 생긴 겹침인지를 나타냅니다.- 콜백 횟수는 영역 안의 인원이나 점유 상태가 아닙니다. 한 액터의 여러 컴포넌트가 겹칠 수 있으므로, 점유는 허용한 키의 집합이 비었는지로 판단합니다.
- 구독하기 전에 이미 겹쳐 있던 대상은 콜백으로 오지 않으므로 필요하면 현재 겹침 목록을 따로 조회합니다.
연습 문제
1. 점유 집합 따라가기
처음 집합은 비어 있고, C와 M은 서로 다른 허용 키입니다. Begin(C), Begin(C), Begin(M), End(C) 순서로 콜백이 왔습니다. 같은 키를 두 번 넣지 않는 정책에서 마지막 집합과 플레이어의 점유 상태는 무엇일까요?
해설 보기
집합은 {C}, {C}, {C, M}, {M} 순서로 바뀌므로, 마지막에도 M이 남아 있어 점유 중입니다. 두 번째 Begin(C)는 이미 있는 키라 집합이 바뀌지 않습니다.
Begin 콜백 횟수를 그대로 영역 안의 수로 세면 같은 C를 두 번 세게 됩니다. 점유는 콜백 횟수가 아니라 남아 있는 키의 집합으로 판단합니다.
2. AI가 들어왔을 때
AI가 조종하는 폰이 트리거 박스 안으로 들어왔는데 로그가 남지 않았습니다. AI 폰이 박스와 겹치지 않았다고 판단해도 될까요?
해설 보기
그렇게 판단하면 안 됩니다. 이 예제의 콜백은 IsPlayerControlled()와 IsLocallyControlled()를 통과한 폰만 로그를 남기므로, AI 폰은 실제로 겹쳤더라도 이 필터를 통과하지 못해 로그가 없습니다.
기하학적으로 겹쳤는지와 필터가 그 대상을 받아들였는지는 다른 문제입니다. 겹침 자체를 확인하려면 필터 앞에서 로그를 남기거나, 현재 겹친 목록을 조회해 봅니다.
오버랩 이벤트와 델리게이트의 형식은 Epic의 UPrimitiveComponent API 문서에서, 응답 조합과 이벤트 조건은 Collision Overview 문서에서 확인할 수 있습니다.
다음 글 물리 시뮬레이션과 Force 적용에서는 물리 시뮬레이션을 켠 물체에 힘과 충격을 주어 움직이는 방법을 살펴봅니다.