오늘의 목표는 커서 위치의 히트 결과를 받아 위치를 표현하는 것! 이것으 디버그 구체를 그려서 할 수 있다.
Start라고 부를 점을 FVector 타입으로 만들고 End라고 부를 점은 마찬가지로 스페이스의 한 점이고 FVector 타입이다. Start에서 End까지 보이지 않는 선을 그을 것이라고 하자
선을 그을 때 Start 위치와 End 위치 사이에 오브젝트가 있는지 확인하고 싶다.
오브젝트가 있다면 스페이스에 그리려는 선은 오브젝트 표면에 부딪히게 된다. 이런 상황을 히트 이벤트라고 부른다. 이렇게 보이지 않는 선을 그리는 건 라인 트레이스를 수행한다고 한다.
무언가와 부딪히는 경우는 트레이스 히트라고 한다. 무언가에 부딪혀 히트 이벤트가 발생하면 트레이스 히트에서 히트 결과라는 구조체에 정보를 FHitResult 타입으로 저장하게 된다.
FHitResult 구조체에는 히트 이벤트 관련 정보를 저장하는 변수가 있다. 스페이스의 FVector로 표현한 히트 위치, 히트 액터 등이 이러한 정보이다.
라인 트레이스는 콜리전 채널을 명시하여 수행한다. 보통 라인 트레이스를 수행할 때는 비저빌리티란 채널을 선택한다. ECollisionChannel이라는 열거형이 있고, 이 열거형에는 ECC_Visibility라는 열거형 상수가 존재한다. 이는 라인 트레이스를 수행할 때 지정하는 매개 변수 중 하나이다.
비저빌리티 채널을 지정하면 콜리전 설정에서 비저빌리티 채널을 막도록 설정된 오브젝트가 히트 이벤트를 기록하게 된다. 비저빌리티 채널을 차단하도록 설정되지 않은 오브젝트로는 히트 이벤트가 발생하지 않는다.
Tank.cpp에서 매 프레임마다 커서 위치의 히트 결과를 가져오려고 한다. 그러기 위해선 Tick함수가 필요하다. BasePawn에서 훔쳐오기 성공
이제 히트에 대한 함수를 다뤄볼건데, 사용하려는 함수는 GetHitResultUnderCursor라는 플레이어 컨트롤러에 존재한다
bool GetHitResultUnderCursor
{
ECollisionChannel TraceChannel,
bool bTraceComplex;
FHitResult& HitResult
} const
잊지말고 우리는 트레이스 채널을 지정해야 하고, 비저빌리티를 사용해야한다.
void ATank::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (PlayerControllerRef)//유효한지 확인
{
PlayerControllerRef->GetHitResultUnderCursor(ECollisionChannel::ECC_Visibility,false,)
}
}
여기서 매개 변수가 좀 특이한데, 첫 번째는 트래이스 채널이다. ECollisionChannel을 사용하고, 콜론 두개를 사용해 비저빌리티를 사용해준다(ECC_Visibility라고 입력해 비저빌리티 채널을 사용하도록). 마지막 인수는 FHitReult가 참조로 전달되는 것을 볼 수 있다. 보통 참조로 무언가를 전달하는 경우에는 상수 참조를 사용한다. 하지만 여기서는 비상수 참조로 일반적으로, 이 함수가 인풋 매개 변수를 직접 바꾸도록 고안되었다는 의미다. GetHitResultUnderCursor는 히트 결과의 변수를 히트 결과에 대한 정보로 채우는 역할을 한다. 그러면 우리는 한가지 FHitResult를 넣어야 한다.
void ATank::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (PlayerControllerRef)//유효한지 확인
{
FHitResult HitResult;
PlayerControllerRef->GetHitResultUnderCursor(ECollisionChannel::ECC_Visibility, false, HitResult);
HitResult.ImpactPoint; //히트 이벤트가 발생한 스페이스 위치를 가져올 수 있다. 라인 트레이스에 대한 정보를 가져오기 위해 HitResult 사용함
}
}
디버그 구체를 그려서 라인 트레이스 결과를 쉽게 시각화 할 수 있다.
디버그 구체는 스페이스에 그리는 단순한 형태로 위치를 잘 나타내주고 디버깅할 때 사용
DrawDebugSphere을 사용해 그린다. GetWorld()는 현재 월드에 UWorld 포인터를 반환한다.
void ATank::BeginPlay()
{
Super::BeginPlay();
PlayerControllerRef = Cast<APlayerController>(GetController());
DrawDebugSphere(GetWorld(), GetActorLocation() + FVector(0.f, 0.f, 200.f), 100.f,12,FColor::Red,true,30.f);
}
GetActorLocation() + FVector(0.f, 0.f, 200.f)는 툰탱크 가져와서 조금 위로 올리겠다는 의미.
구체의 중심은 탱크 위치에서 공중으로 200 유닛 위에 있다. 이런 방식으로 디버그 구체를 그린다.
void ATank::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (PlayerControllerRef)//유효한지 확인
{
FHitResult HitResult;
PlayerControllerRef->GetHitResultUnderCursor(ECollisionChannel::ECC_Visibility, false, HitResult);
DrawDebugSphere(GetWorld(), HitResult.ImpactPoint, 25.f, 12, FColor::Red, false, -1.f);
HitResult.ImpactPoint; //히트 이벤트가 발생한 스페이스 위치를 가져올 수 있다. 라인 트레이스에 대한 정보를 가져오기 위해 HitResult 사용함
}
}
DrawDebugSphere(GetWorld(), HitResult.ImpactPoint, 25.f, 12, FColor::Red, false, -1.f);에서 끝에서 두번째 인수는 선 개수 유지
beginplay에 있던 DrawDebugSphere을 Tick으로 움직여주고 기존보다 인수를 좀 변경해주었다.
와우 결과가 놀랍다 디버그 구체그 생기고 커서 위치의 라인 트레이스에 대한 임팩트가 그려진다
진짜 신기하다
벽과 다른 오브젝트 위로 움직이면 트레이스가 오브젝트와 부딪히게 되는데 이는 비저빌리티 채널을 차단하도록 설정했기 때문이다!
오늘의 TIL: 이런 류의 코딩은 잘 안해봐서 결과가 놀랍고 새롭기만 하다. 라인 트레이스와 비저빌리티 채널 등 새로운 개념이 넘쳐나는 강의였다. 다시 복습은 해야겠지만 뭔가를 배울수록 더 행복해진다는 것이 이런건가 하는 하루이다.