Unreal Engine#10에서 생긴 문제를 해결하는데 성공했다.
해결 방법은 오류 메세지에서 same data로 표시된 파일에 접근해 불필요한 비트를 삭제하고 만약 이것으로 해결되지 않으면 Config와 Intermediate 파일을 삭제후 ReBuild하면 해결된다.
이런 문제가 일어난 이유와 해결방법에 대한 코멘트는 다음과 같다.
일반적으로 빌드할 때 변경된 파일만 컴파일하고 변경되지 않은 파일에는 이전에 컴파일된 코드를 재사용합니다. 해당 폴더를 삭제하면 컴파일되고 생성된 코드가 모두 삭제되므로 처음부터 빌드할 수 있습니다. 따라서 이는 다시 컴파일되어야 하는 이전 컴파일 파일을 재사용한 결과일 가능성이 높습니다.
앞으로 Log suppression category LogTemplateCharacter was somehow declared twice with the same data.! 과 같은 문제가 일어날시 위와 같이 해결할 것이다.
FHitResult HitResult;
DrawDebugSphere(GetWorld(), HitResult.Location,10,10, FColor::Green, false, 5);
DrawDebugSphere(GetWorld(), HitResult.ImpactPoint,10,10, FColor::Red, false, 5);
AActor* HitActor = HitResult.GetActor();
UE_LOG(LogTemp,Display,TEXT("Hit Actor: %s"), *HitActor->GetActorNameOrLabel());
FHITResult는 충돌 지점(point of impact) 및 해당 point의 표면(surface) normal과 같은 trace의 한 번의 hit 정보를 포함하는 구조체입니다.
Location 초록색
ImpactPoint 빨간색
void UGrabber::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
UPhysicsHandleComponent* PhysicsHandle = GetPhysicsHandle();
if(PhysicsHandle == nullptr){
return;
}
if(PhysicsHandle->GetGrabbedComponent() != nullptr){
FVector TargetLocation = GetComponentLocation() + GetForwardVector() * HoldDistance;
PhysicsHandle->SetTargetLocationAndRotation(TargetLocation, GetComponentRotation());
}
}
Grab을 사용하기위해 프로젝트 세팅의 Input에서 마우스 좌클릭을 이용한 Grab을 선언해주었다. 그 후 BP_Player에서 Grab과 관련된 명령을 추가해주었다.
HitResult 종류는 위에서 좀 더 액터에 근접한 ImpactPoint를 사용한다.PhysicsHandle를 이용해 GrabComponentAtLocationWithRotation을 사용한다. GrabComponentAtLocationWithRotation이란 주어진 위치와 회전에서 지정된 구성 요소를 잡고 회전을 제한한다.
void UGrabber::Grab(){
UPhysicsHandleComponent* PhysicsHandle = GetPhysicsHandle();
if(PhysicsHandle == nullptr){
return;
}
//스윕하고 시작과 끝을 계산해 히트했는지 Bool 값을 반환함
//#########################################################
FHitResult HitResult;
bool HasHit = GetGrabableInReach(HitResult);
if(HasHit)
{
UPrimitiveComponent* HitComponent = HitResult.GetComponent();
HitComponent->WakeAllRigidBodies();
// DrawDebugSphere(GetWorld(), HitResult.Location,10,10, FColor::Green, false, 5);
// DrawDebugSphere(GetWorld(), HitResult.ImpactPoint,10,10, FColor::Red, false, 5);
// AActor* HitActor = HitResult.GetActor();
// UE_LOG(LogTemp,Display,TEXT("Hit Actor: %s"), *HitActor->GetActorNameOrLabel());
PhysicsHandle->GrabComponentAtLocationWithRotation(
HitComponent,
NAME_None,
HitResult.ImpactPoint,
HitResult.GetComponent()->GetComponentRotation()
// GetComponentRotation()
);
}
// else
// {
// UE_LOG(LogTemp,Display,TEXT("No Actor Hit"));
// }
//#########################################################
}
void UGrabber::Release(){
UPhysicsHandleComponent* PhysicsHandle = GetPhysicsHandle();
if(PhysicsHandle == nullptr){
return;
}
if(PhysicsHandle->GetGrabbedComponent() != nullptr){
PhysicsHandle->ReleaseComponent();
}
}
UPhysicsHandleComponent* UGrabber::GetPhysicsHandle() const
{
UPhysicsHandleComponent* Result = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
if(Result == nullptr){
// UE_LOG(LogTemp, Error, TEXT("Grabber requires a UPhysicsHandleComponent"));
}
return Result;
}
UPhysicsHandleComponent* UGrabber::GetPhysicsHandle() const
{
UPhysicsHandleComponent* Result = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();
if(Result == nullptr){
// UE_LOG(LogTemp, Error, TEXT("Grabber requires a UPhysicsHandleComponent"));
}
return Result;
}
bool UGrabber::GetGrabableInReach(FHitResult& OutHitResult) const
{
FVector Start = GetComponentLocation();
FVector End = Start + GetForwardVector() * MaxGrabDistance;
DrawDebugLine(GetWorld(), Start, End, FColor::Red);
DrawDebugSphere(GetWorld(), End,10,10, FColor::Blue, false, 5);
//내가 설정한 원으로 콜리션 원 만들기
FCollisionShape Sphere = FCollisionShape::MakeSphere(GrabRadius);
bool HasHit;
return HasHit = GetWorld()->SweepSingleByChannel(OutHitResult, Start, End, FQuat::Identity, ECC_GameTraceChannel2,Sphere);
}
석상을 움직이기 위해서는 Mobility를 Movable로 설정해줘야 한다.