[UE4] PhysicsHandleComponent로 임의의 오브젝트 잡기

#언리얼4 공부중 / UE4 버젼: 4.22.3 

캐릭터가 임의의 오브젝트를 잡을 때 혹은 소유하고자 할때 어떻게 해야 할까.

유니티에서는 보통 두가지 방식을 사용 했었는데, 하나는 캐릭터에 빈 게임오브젝트를 원하는 지점에 만들어 그 아래에 child로 붙이는 방식과, 다른 하나는 매 프레임마다 잡고자 하는 오브젝트의 월드 좌표를 업데이트하여 원하는 지점으로 옮기는 방식을 쓰곤 했다.

언리얼에서는 유니티에서 처럼 child로 붙이는 방식으로 작업을 많이 하는지는 잘 모르겠다.. 대신 소켓을 구성하여 소켓 정보를 이용하는 방식이 보편적인 방식으로 보인다 (스태틱 메시에 소켓 구성 및 사용). 소켓에 대한 내용은 나중으로 미뤄 두기로 하고..

그래서 처음 시도했던 방식은 타겟 오브젝트의 위치를 캐릭터의 소켓 위치와 매 프레임마다 동기를 맞추는 방식을 해보았다.

auto location = rootComp->GetSocketLocation(FName("attach_socket"));  // 소켓 위치 
targetObjActor->SetActorLocation(location);  //타겟 위치 변경

attach_socket이라는 이름의 소켓 위치를 가져와 targetObjActor의 위치를 맞춰주는 방식이였는데, targetObjActor가 첫 프레임에는 잘 위치가 옮겨지지만 그 다음 프레임 부터는 땅을 뚫고 무한히 떨어졌다 (targetObjActor는 simulate physics와 enable gravity가 켜진 상태).

물리가 적용된 오브젝트에 대해선 SetActorLocation이 적용되지 않는 것인가.  USceneComponent::SetWorldLocation을 사용해도 같은 결과여서, 열심히 구글링을 해보니 USkeletalMeshComponent::SetAllPhysicsPosition이 있어서 뭔가 그럴싸해 보였는데 이것도 동일하게 오브젝트가 무한히 떨어지는 결과를 보여주었다.  

언리얼 메뉴얼을 뒤지다가 Physics Component에 대한 글을 보니 physics를 사용하는 컴포넌트에 대한 설명이 있는데, 여기서 PhysicsHandleComponent가 “피직스 오브젝트를 잡아 움직이기 위한 오브젝트로, 잡은 오브젝트에는 계속해서 피직스가 적용됩니다”라고 친절하게 설명을 해 주었다.  

PhysicsHandleComponent를 사용하면 물리가 적용된 오브젝트를 잡을 수 있구나.

handle(핸들)이라고 하니 이게 타겟 오브젝트에 붙어 있어야 잡을 수 있겠구나 생각이 들었는데, 그 반대여서 약간 헛갈리긴 했다.  잡으려고 하는 캐릭터 쪽에 PhysicsHandleComponent이 있어야 하는 걸 보니, handle이 약간 hand(손의 느낌)인가 보다.

기본적으로 잡고 놓고 하기 위해 사용되는 API는 GrabComponentAtLocation / ReleaseComponent가 있다.

Blueprint editor상에서 Add Component로 Physics Handle을 추가하거나, 아래와 같이 만들어 주자. 

// .h 헤더
UPROPERTY(EditDefaultsOnly) 
UPhysicsHandleComponent* PhysicsHandle;

//.cpp 
PhysicsHandle = CreateDefaultSubobject<UPhysicsHandleComponent>(TEXT("PhysicsHandle"));  // BeginPlay에서.

피직스 핸들을 생성한 후에, Grab과 Release를 통해 오브젝트를 잡고 놓을 수 있는데 샘플 코드는 아래와 같이 해보았다.

//오브젝트를 잡을때 샘플 코드.
auto prim = Cast<UPrimitiveComponent>(targetObjActor->GetRootComponent());
PhysicsHandle->GrabComponentAtLocation(prim, FName(""),  prim->GetComponentLocation());
auto location = rootComp->GetSocketLocation(FName("attach_socket"));
PhysicsHandle->SetTargetLocation(footlocation);   //소켓 위치로 physicshandle 위치 변경하기

......

//놓을때 샘플 코드. 
PhysicsHandle->ReleaseComponent();

실제로 PhysicsHandleComponent 로 테스트를 해보니 물리가 적용된 오브젝트가 원하는 소켓 위치로 잘 잡히고 놓아졌다.  앞으로 메뉴얼을 좀 더 꼼꼼히 읽어 봐야 할 것 같다..  

참고로 다양한 피드백/조언 환영합니다.


Leave a Reply

Your email address will not be published. Required fields are marked *