트리거 박스와 오버랩 이벤트
이전 절에서는 언리얼 엔진의 충돌 시스템 기초인 충돌 채널과 프로파일 설정에 대해 알아보았습니다. 이제 이러한 충돌 시스템을 활용하여 게임플레이에서 빈번하게 사용되는 상호작용 방식인 트리거(Trigger) 와 오버랩 이벤트(Overlap Event) 에 대해 자세히 살펴보겠습니다. 특히, 특정 영역에 진입했을 때 이벤트를 발생시키는 데 유용한 트리거 박스(Trigger Box) 의 활용법에 초점을 맞출 것입니다.
트리거(Trigger)란?
트리거는 게임 월드 내의 특정 영역(Volume) 으로, 플레이어나 다른 액터가 이 영역에 진입하거나 이탈했을 때 미리 정의된 게임플레이 이벤트를 발생시키는 역할을 합니다. 트리거는 물리적인 블록킹(Blocking)을 일으키지 않고, 단지 감지(Query)만을 수행한다는 점에서 일반적인 충돌 오브젝트와 차이가 있습니다.
트리거는 다음과 같은 다양한 상황에서 활용됩니다.
- 아이템 획득: 플레이어가 아이템 위에 서면 아이템을 획득하고 사라지게 합니다.
- 문 열림: 플레이어가 문 앞의 특정 영역에 진입하면 문이 자동으로 열리게 합니다.
- 지역 감지: 플레이어가 새로운 지역에 진입하면 해당 지역의 이름이 화면에 표시되거나, 배경 음악이 바뀌게 합니다.
- 컷씬 발동: 특정 지점에 도달하면 시네마틱 컷씬이 시작되게 합니다.
- 체크포인트: 플레이어가 지나가면 체크포인트가 활성화되게 합니다.
트리거 박스 (Trigger Box) 컴포넌트
언리얼 엔진에서 가장 흔하게 사용되는 트리거 형태는 UBoxComponent
를 기반으로 한 트리거 볼륨(Trigger Volume) 입니다. UBoxComponent
는 직육면체 형태의 충돌 감지 영역을 제공하며, 이를 트리거 용도로 설정할 수 있습니다.
트리거 박스의 특징
- 시각적 표현 없음: 기본적으로 렌더링되지 않으므로, 게임 내에서는 보이지 않습니다. 에디터에서만 와이어프레임 형태로 표시되어 배치와 크기 조절을 돕습니다.
- 물리적 상호작용 없음:
QueryOnly
또는OverlapAll
과 같은 충돌 프리셋을 사용하여 물리적인Block
반응을 일으키지 않습니다. - 오버랩 이벤트 발생: 다른 충돌 컴포넌트와 겹쳤을 때
OnComponentBeginOverlap
및OnComponentEndOverlap
이벤트를 발생시킵니다.
C++에서 트리거 박스 설정하기
이전 절에서 다룬 AMyTriggerVolume
액터 클래스를 다시 살펴보겠습니다. 이 액터는 UBoxComponent
를 사용하여 트리거 박스를 구현하는 전형적인 예시입니다.
#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);
};
#include "MyTriggerVolume.h"
#include "Components/BoxComponent.h" // UBoxComponent 헤더 포함
#include "Kismet/GameplayStatics.h" // Debug 메시지 등을 위해 (선택 사항)
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)); // 100x100x100 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); // 플레이어 폰으로 캐스팅
if (PlayerPawn && 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->IsLocallyControlled())
{
UE_LOG(LogTemp, Warning, TEXT("Local Player exited: %s"), *PlayerPawn->GetName());
// 여기에 플레이어가 트리거에서 이탈했을 때 실행할 로직을 구현합니다.
// 예: "아이템 획득 가능" 메시지 숨기기 등.
}
}
}
핵심 설정
SetCollisionProfileName(TEXT("OverlapAllDynamic"))
: 이 컴포넌트가 모든 동적 오브젝트와 오버랩을 감지하도록 설정합니다. 프로젝트 설정에서 더 세분화된 커스텀 프로파일을 만들었다면 해당 이름을 사용하세요.SetGenerateOverlapEvents(true)
: 이 함수를true
로 설정해야 오버랩 이벤트가 발생합니다.OnComponentBeginOverlap.AddDynamic(this, &AMyTriggerVolume::OnOverlapBegin)
:AddDynamic
함수는 언리얼 엔진의 델리게이트(Delegate) 시스템에서 이벤트에 함수를 바인딩하는 데 사용됩니다.OnComponentBeginOverlap
은UPrimitiveComponent
가 제공하는 멀티캐스트 델리게이트로, 오버랩이 시작될 때 호출됩니다.- 첫 번째 인자
this
는 이벤트를 받을 오브젝트(액터)의 포인터입니다. - 두 번째 인자
&AMyTriggerVolume::OnOverlapBegin
는 바인딩할 멤버 함수의 주소입니다. 이 함수는 반드시UFUNCTION()
으로 선언되어야 하며, 델리게이트의 시그니처와 일치하는 파라미터를 가져야 합니다.
오버랩 이벤트의 파라미터 이해
OnOverlapBegin
(그리고 OnOverlapEnd
) 함수가 받는 파라미터들은 오버랩에 대한 중요한 정보를 제공합니다.
UPrimitiveComponent* OverlappedComp
: 오버랩을 발생시킨 이 컴포넌트(즉,TriggerBox
자체).AActor* OtherActor
: 이 트리거 박스와 겹친 다른 액터의 포인터.UPrimitiveComponent* OtherComp
:OtherActor
내에서OverlappedComp
와 실제로 겹친 다른 컴포넌트의 포인터. (예: 플레이어 캐릭터의CapsuleComponent
)int32 OtherBodyIndex
: 스켈레탈 메시의 경우, 겹친 본(Bone)의 인덱스.bool bFromSweep
: 스윕(Sweep) 검사로 오버랩이 발생했는지 여부. (예: 빠르게 이동하는 오브젝트의 충돌 감지)const FHitResult& SweepResult
:bFromSweep
이true
일 경우, 스윕 검사의 자세한 결과.
이 파라미터들을 통해 우리는 어떤 액터의 어떤 컴포넌트가 우리 트리거 박스와 상호작용했는지 정확히 파악하고, 그에 따른 맞춤형 로직을 구현할 수 있습니다.
블루프린트에서 트리거 박스 및 이벤트 활용
C++로 AMyTriggerVolume
을 만들었다면, 언리얼 에디터에서 이를 기반으로 한 블루프린트 클래스(BP_MyTriggerVolume
)를 생성하여 레벨에 배치할 수 있습니다.
배치 및 크기 조절: BP_MyTriggerVolume
인스턴스를 레벨에 드래그하여 배치하고, 디테일 패널에서 TriggerBox
컴포넌트의 Box Extent
를 조절하여 원하는 트리거 영역 크기로 만듭니다.
이벤트 그래프에서 활용: BP_MyTriggerVolume
블루프린트 에디터를 열고, Event Graph
에서 TriggerBox
컴포넌트를 선택한 후, 디테일 패널 하단에 있는 이벤트 목록에서 OnComponentBeginOverlap
과 OnComponentEndOverlap
이벤트를 추가할 수 있습니다.
이 이벤트 노드들에서 Other Actor
핀을 뽑아 Cast To ThirdPersonCharacter
(혹은 여러분의 캐릭터 클래스)와 같은 캐스팅 노드를 사용하여 플레이어가 겹쳤는지 확인하고, 원하는 블루프린트 로직을 연결할 수 있습니다.
마치며
트리거 박스와 오버랩 이벤트는 언리얼 엔진에서 비물리적인 게임플레이 상호작용을 구현하는 데 있어 가장 기본적인 도구입니다. 이들을 통해 아이템 획득, 구역 진입/이탈 감지, 이벤트 발동 등 다양한 기능을 효율적으로 구현할 수 있습니다. 충돌 채널과 프로파일 설정을 통해 원하는 액터들 사이에서만 오버랩이 발생하도록 정교하게 제어할 수 있다는 점을 기억하는 것이 중요합니다.