UE5 C++ | Crypt Raider, Grabber 구현 (유데미)
언리얼 강의 중 Section 4를 정리한 여섯번째 글입니다.
UE5 C++ | Crypt Raider, Grabber 구현 (유데미)
강의 정보 🎓
- 강의명: Unreal Engine 5 C++ Developer: Learn C++ & Make Video Games
- 플랫폼: 유데미
- 현재 섹션: Section 4 - Crypt Raider
- 주요 내용: PhysicsHandle을 활용해서 Grabber를 구현하였다.
FindComponentByClass() & nullptr 🔍
컴포넌트 내에서 다른 컴포넌트를 연결하는 방법을 알아본다.
PhysicsHandle 컴포넌트 연결
- PhysicsHandle 컴포넌트를
BP_Player에 추가한다. - 잡아야 할 객체를 지정하고 잡은 객체의 놓을 위치를 알려주는 역할을 해야 한다.
Grab 시 사용할 PhysicsHandle 컴포넌트를 찾는 방법:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include "PhysicsEngine/PhysicsHandleComponent.h" ... void UGrabber::BeginPlay(){ ... // FindComponentByClass는 템플릿 함수 UPhysicsHandleComponent* PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>(); // 템플릿 함수 if(PhysicsHandle) { UE_LOG(LogTemp, Display, TEXT("Got Physics Handle: %s"), *PhysicsHandle->GetName()); } else { UE_LOG(LogTemp, Warning, TEXT("No Physics Handle Found!")); } } // VS Code에서 빌드를 한 후 프로젝트를 열어준다.
DrawDebugSphere() 🎨
디버그 구체를 그려본다.
- Grab 시 디버그용 구체 시각화가 가능하다.
1
2
3
4
5
6
7
8
9
10
void UGrabber::Grab(){
...
DrawDebugSphere(GetWorld(), End, 10.0f, 10, FColor::Blue, false, 5.0f);
...
if(HasHit)
{
DrawDebugSphere(GetWorld(), HitResult.Location,...); // 초록색 구
DrawDebugSphere(GetWorld(), HitResult.ImpactPoint,...); // 보라색 구
...
}
초록색 → Location, 보라색 → ImpactPoint, 파란색 → End
PhysicsHandle로 객체 잡기 🖐️
- 액터의 피직스 시뮬레이터를 키고 Mobility를 Movable 상태로 바꿔준다.
TickComponent 내부 구현
1
2
3
4
5
6
7
8
9
10
11
void UGrabber::TickComponent(...){
...
UPhysicsHandleComponent* PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
if(!PhysicsHandle)
{
return;
}
FVector TargetLocation = GetComponentLocation() + GetForwardVector() * HoldDistance;
PhysicsHandle->SetTargetLocationAndRotation(TargetLocation, GetComponentRotation());
}
Grab 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void UGrabber::Grab(){
UPhysicsHandleComponent* PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
if(!PhysicsHandle)
{
return;
}
...
if(HasHit)
{
PhysicsHandle->GrabComponentAtLocationWithRotation(
HitResult.GetComponent(),
NAME_None,
HitResult.ImpactPoint,
GetComponentRotation()
);
}
}
물리 오브젝트 깨우기 💤
- 물리 시뮬레이터를 담당하는
UPrimitiveComponent가 일정시간이 지나면 슬립 모드로 들어가는 것을 방지해야한다. 슬립 모드 방지:
1 2 3 4 5 6
.. if(HasHit) { UPrimitiveComponent* HitComponent = HitResult.GetComponent(); HitComponent->WakeAllRigidBodies(); ... }
Release 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void UGrabber::Release(){
UPhysicsHandleComponent* PhysicsHandle = GetPhysicsHandle();
if(!PhysicsHandle)
{
return;
}
UPrimitiveComponent* HitComponent = PhysicsHandle->GetGrabbedComponent();
if(HitComponent)
{
HitComponent->WakeAllRigidBodies();
PhysicsHandle->ReleaseComponent();
}
}
물리 충돌 해결
- 가고일 석상을 선택 후 All → Collision → Collision Presets → Pawn을 Overlap으로 설정한다.
- Dirt_Mound의 경우 Collision Preset을 NoCollision으로 설정해준다.
아웃 파라미터 리턴 ↩️
Grab 함수 리팩토링
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void UGrabber::Grab()
{
...
FHitResult HitResult;
bool HasHit = GetGrabbableInReach(HitResult);
...
}
bool UGrabber::GetGrabbableInReach(FHitResult& OutHitResult) const
{
FVector Start = GetComponentLocation();
FVector End = Start + GetForwardVector() * MaxGrabDistance;
DrawDebugLine(GetWorld(), Start, End, FColor::Red, false);
DrawDebugSphere(GetWorld(), End, 10.0f, 10, FColor::Blue, false, 5.0f);
FCollisionShape Sphere = FCollisionShape::MakeSphere(GrabRadius);
bool HasHit = GetWorld()->SweepSingleByChannel(
OutHitResult,
Start,
End,
FQuat::Identity,
ECC_GameTraceChannel2,
Sphere
);
return HasHit;
}
요약 및 느낀점 📝
- PhysicsHandle 활용법을 다루고 디버그 구체를 띄워보았다.
- Grab/Release 기능 구성하고 간단한 아웃 파라미터 기반 리팩토링을 적용하였다.
C++을 활용한 첫 기능을 구현해본 느낌이다. 지금은 단순히 들고 놓는 상태인데 들고있는 상태에서 오브젝트를 회전시킨다던지 이동시키는 등의 동작을 추가로 구현해보고싶다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
