포스트

UE5 C++ | Crypt Raider, Grabber 구현 (유데미)

언리얼 강의 중 Section 4를 정리한 여섯번째 글입니다.

UE5 C++ | Crypt Raider, 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 초록색 → 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 장면 Grab 장면


아웃 파라미터 리턴 ↩️

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 라이센스를 따릅니다.