본문 바로가기

게임프로그래밍/실습1

[언리얼 실습] 23. 무기 히트를 위한 콜리전 박스 추가랑 트레이싱 추가하기


목차

  1. 콜리전 박스 만들기
  2. 트레이싱 준비
  3. c++에서 트레이싱 하기

1. 콜리전 박스 만들기

 

충돌을 감지하기 위해서는 충돌을 일으킬 수 있어야 하고 그렇게 하기 위해 콜리전 박스를 만들 것이다. 비주얼 스튜디오로 들어가자

 

// 무기.h

private:
	UPROPERTY(VisibleAnywhere)
	class  UBoxComponent* WeaponBox;

 

박스 컴포넌트를 선언해주자. 이제 생성자에서 이를 정의해주어야 한다.

 

#include "Components/BoxComponent.h"

AWeapons::AWeapons()
{
	WeaponBox = CreateDefaultSubobject<UBoxComponent>(TEXT("Weapon Box"));
	WeaponBox->SetupAttachment(GetRootComponent());
}

 

이제 생성은 완료했으니 실제 블루프린트에서 이를 배치해보자.

 

 

콜리전 박스가 잘 생성된 것을 볼 수 있다. 물론 이대로 쓰기는 무리이니 이를 조절해서 무기의 모양에 맞게 고치도록 ㅎ하자.

 

 

대략 이런 모양으로 만들면 된다.

 

개인적인 생각으로 콜리전 박스를 너무 타이트하게 잡으면 Hit 이벤트를 발생시킬때 조금 애매한 감이 있으므로 여유롭게 설정해주는 게 좋은 것 같다.


2. 트레이싱 준비

 

이제 박스 컴포넌트는 만들었으니 트레이싱을 하여 실제 충돌을 하는 물체의 정보를 알아내도록 하자.

 

트레이싱의 시작점과 끝점을 만들고 그 사이에 충돌하는 물체만 감지할 것인데 시작점과 끝점은 신컴포넌트로 지정할 것이다.

 

 

이런 식으로 신 컴포넌트를 생성해준다.

 

그리고 각각의 시작점과 끝점을 무기의 바닥과 꼭대기에 설정해 준다.

 

이제 박스 컴포넌트의 콜리전 설정을 바꾸자. 히트를 할때 실제 매시에 충돌할때만 히트이벤트를 발생시킬 것이다.

 

 

추후 오버랩 이벤트는 폰 타입이 아닌 월드다이나믹 설정이 되어있는 객체에만 발생시킬 것이다. 폰 타입의 경우 오버랩 이벤트를 발생시키지 않을 것이다.

 

나중에 적 클래스를 만들고 이 부분을 유념하고 콜리전을 설정하면 된다.

 

이제 코드를 짜보자


3. c++에서 트레이싱 하기

 

박스컴포넌트에 오버랩 이벤트가 발생하면 트레이스를 하여 hitresult를 통해 다양한 작업을 할 것이다.

먼저 박스컴포넌트의 콜리전 프리셋을 설정해보자. 현재 블루프린트에서 설정하였는데 c++에서 기본값을 바꿀 것이다.

 

무기.cpp 로 들어가 생성자 부분에 구문을 추가하자.

 

AWeapons::AWeapons()
{
	WeaponBox = CreateDefaultSubobject<UBoxComponent>(TEXT("Weapon Box"));
	WeaponBox->SetupAttachment(GetRootComponent());
	WeaponBox->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
	WeaponBox->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Overlap);
	WeaponBox->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore);
}

 

SetCollisionEnabled: CollisionEnabled의 기본값을 설정한다. 현재 블루프린트에 설정되어있는 값으로 지정해주었다.

 

SetCollisionResponseToAllChannels: 콜리전 리스폰스 채널을 설정하는데 모든 채널을 설정한다.

ECollisionResponse::ECR_Overlap모든 채널에 대해 오버랩으로 설정한다.

 

SetCollisionResponseToChannel: 특정 채널의 콜리전을 설정한다.

ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore: Pawn에 대해 Ignore로 설정한다.

 

이렇게 하면 무기 클래스의 기본 콜리전 세팅을 할 수 있다.

 

이제 박스컴포넌트에 오버랩 이벤트가 발생하면 트레이스를 시작해보자.

 

UFUNCTION()
void OnBoxOverlap(
	UPrimitiveComponent* OverlappedComponent,
    AActor* OtherActor,
    UPrimitiveComponent* OtherComp,
    int32 OtherBodyIndex,
    bool bFromSweep,
    const FHitResult& SweepResult
);

 

오버랩이 발생하면 작동할 이벤트를 정의해준다. 델리게이트로 본 함수를 호출시켜 사용할 것이다.

 

void AWeapons::BeginPlay()
{
	Super::BeginPlay();

	WeaponBox->OnComponentBeginOverlap.AddDynamic(this, &AWeapons::OnBoxOverlap);
}

 

비긴플레이에서 델리게이트를 설정해주자. 이제 함수가 호출되면 트레이스를 할 수 있다.

 

트레이스의 시작점과 끝점을 블루프린트에서 만들었는데 C++에서 만들려고 한다.

// 헤더파일
UPROPERTY(VisibleAnywhere)
USceneComponent* BoxTraceStart;

UPROPERTY(VisibleAnywhere)
USceneComponent* BoxTraceEnd;

 

SceneComponent를 선언해주고 실제로 할당도 해주자.

 

BoxTraceStart = CreateDefaultSubobject<USceneComponent>(TEXT("Box Trace Start"));
BoxTraceStart->SetupAttachment(GetRootComponent());

BoxTraceEnd = CreateDefaultSubobject<USceneComponent>(TEXT("Box Trace End"));
BoxTraceEnd->SetupAttachment(GetRootComponent());

 

생성자에 해당 구문을 추가해주자. 이제 이 두개의 신 컴포넌트는 무기에서 위치를 다시 잡아주어야 한다.

 

이제 트레이스의 시작위치와 끝 위치가 있으니 트레이싱을 하면 된다.

BoxTraceSingle () 을 이용해 트레이싱을 할것인데 이걸 쓰기 위해서 include를 해야한다.

 

#include "Kismet/KismetSystemLibrary.h"

 

	UKismetSystemLibrary::BoxTraceSingle(this,
		Start,
		End,
		FVector(5.f, 5.f, 5.f),
		BoxTraceStart->GetComponentRotation(),
		ETraceTypeQuery::TraceTypeQuery1,
		false,
		ActorsToIgnore,
		EDrawDebugTrace::ForDuration,
		HitResult,
		true
	);

 

함수는 다음과 같이 매개변수를 넣을 수 있다. 이제 각각의 매개변수에 대해 알아보자.

 

Start, End : 트레이싱 시작점과 끝점이다.

(HalfSize) FVector(5.f, 5.f, 5.f) : 트레이싱할 구체의 크기이다.

(Orientation) BoxTraceStart->GetComponentRotation() : 트레이스의 회전방향으로 현재 박스트레이스스타트의 회전과 동일하게 설정했다.

(TraceChannel) ETraceTypeQuery::TraceTypeQuery1 : 트레이싱 채널을 지정하는 것으로 이를 통해 특정 오브젝트를 위한 충돌채널을 지정할 수 있다. 여기서는 따로 지정하지 않을 것이기 때문에 디폴트 값을 사용하였다.

(bTraceComplex) false : 복잡한 충돌검사를 할지 말지 정하는 것으로 굳이 사용할 필요가 없어서 false로 설정하였다.

ActorsToIgnore : 트레이싱을 할때 무시할 액터들을 담을 배열이;다.

(DrawDebugType) EDrawDebugTrace::ForDuration : 디버그 모드로 트레이스의 결과를 일정시간 동안 보여주게 설정하였다. 이 값은 차후 none으로 바꿀 것이다.

(OutHit) HitResult: 충돌 결과를 담을 HitResult 구조체이다.

(bIgnoreSelf) true : 자기자신을 추적하지 않을 지 설정하는 것으로 자기자신(무기)은 추적할 필요가 없기 때문에 true로 설정하였다.

 

이제 이렇게 트레이스를 하면 hitresult에 다양한 값들이 들어오고 이것을 활용할 수 있다.

 

컴파일하고 잘 되는 지 확인해보자. 참고로 코드는 아래와 같이 짯다.

void AWeapons::OnBoxOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	const FVector Start = BoxTraceStart->GetComponentLocation();
	const FVector End = BoxTraceEnd->GetComponentLocation();

	TArray<AActor*> ActorsToIgnore;
	ActorsToIgnore.Add(this);

	FHitResult HitResult;
	UKismetSystemLibrary::BoxTraceSingle(this,
		Start,
		End,
		FVector(5.f, 5.f, 5.f),
		BoxTraceStart->GetComponentRotation(),
		ETraceTypeQuery::TraceTypeQuery1,
		false,
		ActorsToIgnore,
		EDrawDebugTrace::ForDuration,
		HitResult,
		true
	);
}

 

 

이제 충돌을 감지할 수 있게 되었으니 이를 활용하여 다양한 것을 할 수 있게 될 것이다.