상세 컨텐츠

본문 제목

Learning Unreal 4 언리얼 공부일지 - 충돌 감지 해보기

Computer Science/Unreal Engine

by 2022. 1. 27. 13:20

본문

반응형

프로젝트 세팅 → 엔진 → 콜리전에서 각 채널에 대해서 설정할 수 있다.

오브젝트 채널 및 트레이스 채널을 생성하고, Preset에서 충돌관계를 설정할 수 있다. 새 채널을 설정하면, preset에 있는 기본설정들에는 block으로 설정되기 때문에 필요한 경우 바꾸어 주어야 한다.

 

콜리전 프리셋을 설정하면, 적용할 캐릭터의 블루프린트에서 Capsule Component → 콜리전 → 콜리전 프리셋 에서 설정한다. 코드로 설정하는 방법도 가능하다.

 

private:
	UFUNCTION()
	void AnimNotify_AttackHit();
    
public:
	FOnAttackHit OnAttackHit;

AnimInstance 헤더에 AttackHit 함수와 OnAttackHit라는 변수를 추가했다. 

FOnAttackHit 는 델리게이트이다.

 

void UMyAnimInstance::AnimNotify_AttackHit() 
{
	//UE_LOG(LogTemp, Log, TEXT("AnimNotify_AttackHit"));
	OnAttackHit.Broadcast();
}

AnimInstance cpp파일에 AttackHit함수를 정의헀고, 여기에서 OnAttackHit 함수를 Boradcast 즉 범위에 포함되는 오브젝트들에게 호출신호를 보낸다.

 

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	virtual void PostInitializeComponents() override;
    
public:
/ ... /
	void Attack();
	void AttackCheck(); // 함수 선언

Character의 헤더인데 PostInitializeComponents는 Life Cycle 함수 중 BeginPlay보다 먼저 호출되는 함수이다.

Life Cycle 함수는 언리얼에서 선언해놓았으므로 virtual 및 override해서 클래스에 선언한다.

 

// MyCharacter.cpp

void AMyCharacter::BeginPlay()
{
	Super::BeginPlay();
}

void AMyCharacter::PostInitializeComponents()
{
	Super::PostInitializeComponents();

	AnimInstance = Cast<UMyAnimInstance>(GetMesh()->GetAnimInstance());
	if (AnimInstance)
	{
		AnimInstance->OnMontageEnded.AddDynamic(this, &AMyCharacter::OnAttackMontageEnded);
		AnimInstance->OnAttackHit.AddUObject(this, &AMyCharacter::AttackCheck);
	}
}

/ ... /

void AMyCharacter::AttackCheck()
{
	FHitResult HitResult;
	FCollisionQueryParams Params(NAME_None, false, this);

	float AttackRange = 100.f;
	float AttackRadius = 50.f;

	// 채널에 해당하는 충돌이 일어나면 true반환
	bool bResult = GetWorld()->SweepSingleByChannel(
		OUT HitResult,
		GetActorLocation(),
		GetActorLocation() + GetActorForwardVector() * AttackRange,
		FQuat::Identity,
		ECollisionChannel::ECC_GameTraceChannel2, // 
		FCollisionShape::MakeSphere(AttackRadius),
		Params);
        
	// 충돌하고, Actor 값이 있는 경우
	if (bResult && HitResult.Actor.IsValid())
	{
		UE_LOG(LogTemp, Log, TEXT("Hit Actor : %s"), *HitResult.Actor->GetName());
	}
}

Character cpp파일에서는 BeginPlay에 있던 AnimInstance를 가져와 대입하는 과정을 PostInitializeComponent로 옮겼다.

AttackCheck에서는 SweepSingleByChannel을 이용해서 충돌체크를 한다.

 

ECollisionChannel에는 충돌처리 채널을 지정해주어야하는데, 

프로젝트 경로 → Config → DefaultEngine.ini 를 참고하면 충돌관련 설정을 한 채널을 확인할 수 있다.

FCollisionShape를 통해 충돌하는 범위의 모양을 설정할 수 있다.

 

// MyCharacter.cpp

void AMyCharacter::AttackCheck()
{
	FHitResult HitResult;
	FCollisionQueryParams Params(NAME_None, false, this);

	float AttackRange = 100.f;
	float AttackRadius = 50.f;

	bool bResult = GetWorld()->SweepSingleByChannel(
		OUT HitResult,
		GetActorLocation(),
		GetActorLocation() + GetActorForwardVector() * AttackRange,
		FQuat::Identity,
		ECollisionChannel::ECC_GameTraceChannel2,
		FCollisionShape::MakeSphere(AttackRadius),
		Params);

	FVector Vec = GetActorForwardVector() * AttackRange; // 방향벡터
	FVector Center = GetActorLocation() + Vec * 0.5f; // 중심
	float HalfHeight = AttackRange * 0.5f + AttackRadius; // 캡슐 몸통길이
	FQuat Rotation = FRotationMatrix::MakeFromZ(Vec).ToQuat(); // rotation
	FColor DrawColor; // 색
    // 충돌 여부에 따라 색 변화
	if (bResult)
		DrawColor = FColor::Green;
	else
		DrawColor = FColor::Red;

	// debug 캡슐 그리기
	DrawDebugCapsule(GetWorld(), Center, HalfHeight, AttackRadius,
		Rotation, DrawColor, false, 2.f);

	if (bResult && HitResult.Actor.IsValid())
	{
		UE_LOG(LogTemp, Log, TEXT("Hit Actor : %s"), *HitResult.Actor->GetName());
	}
}

위와같은 방법으로 충돌에 반응하여 캡슐을 그릴 수 있다.

반응형

관련글 더보기