본문 바로가기

게임프로그래밍/실습1

[언리얼 실습] 70. 방향성 히트 리액션 수정하기


목차

  1. 타격자 기준으로 히트 방향 설정하기
  2. 버그 수정하기

1. 타격자 기준으로 히트 방향 설정하기

 

현재 방향성 히트를 구현하고 있는데 피격 지점을 기준으로 방향을 설정한다. 이것의 문제점은 회전 공격 같이 측면을 때리는 경우 정면에서 공격을 해도 측면에 피격이 일어나 일반적으로 생각하는 반응이 나오지 않는다.

 

그렇기에 이를 피격지점이 아닌 타격자와 피격자의 위치를 기준으로 계산하게 바꿔보자

 

현재 방향성 타격은 다음과 같이 구하고 있다.

void ABaseCharacter::DirectionalHitReact(const FVector& ImpactPoint)
{
	// Forward = U
	const FVector Forward = GetActorForwardVector();
	// ImpactPoint의 Z축을 에너미의 Z축과 동일하게 설정
	const FVector ImpactLowered(ImpactPoint.X, ImpactPoint.Y, GetActorLocation().Z);
	// ToHit = V
	const FVector ToHit = (ImpactLowered - GetActorLocation()).GetSafeNormal();

	// U * V = |U||V| cosθ
	// |U| = 1, |V| = 1, 따라서
	//  cosθ = U * V
	const double CosTheta = FVector::DotProduct(Forward, ToHit);
	// cosθ의 역함수 구하기
	double Theta = FMath::Acos(CosTheta);
	// 라디안 단위를 디그리 단위로 변환
	Theta = FMath::RadiansToDegrees(Theta);

	// 만약 외적 방향이 아래를 향하면 세타는 마이너스이다.
	const FVector CrossProduct = FVector::CrossProduct(Forward, ToHit);
	if (CrossProduct.Z < 0)
	{
		Theta *= -1.f;
	}

	FName Section("FromBack");

	if (Theta >= -45.f && Theta < 45.f)
	{
		Section = FName("FromFront");
	}
	else if (Theta >= -135.f && Theta < -45.f)
	{
		Section = FName("FromLeft");
	}
	else if (Theta >= 45.f && Theta < 135.f)
	{
		Section = FName("FromRight");
	}

	PlayHitReactMontage(Section);
}

 

여기에 이제 ImpactPoint(타격지점)이 아닌 공격자의 위치를 넘겨 이를 계산할 수 있게 하자.

 

함수 호출은 아래에서 하고 있다.

 

void ABaseCharacter::GetHit_Implementation(const FVector& ImpactPoint)
{
	if (IsAlive()) DirectionalHitReact(ImpactPoint);
	else Die();

	PlayHitSound(ImpactPoint);
	SpawnHitParticles(ImpactPoint);
}

 

공격자의 위치를 넘겨야하기 때문에 함수의 매개변수를 바꿔야 한다. 인터페이스에서 이를 수정하자.

 

UFUNCTION(BlueprintNativeEvent)
void GetHit(const FVector& ImpactPoint, AActor* Hitter);

 

이제 인터페이스를 바꾸었기 때문에 이를 상속받는 모든 클래스에서 이 부분을 수정해주어야 한다.

 

해당 함수를 사용하고 있는 모든 클래스로 들어가 수정해주자. 어떤 클래스에서 상속받고 있는지 기억이 잘 안나면 한가지 방법으로 그냥 컴파일을 해보는 것이다.

 

컴파일을 하면 오류가 나는 곳을 알려주기 때문에 그곳에 가서 수정해주면 된다.

 

이제 수정을 다했으면 다시 방향성 히트를 수정하자.

 

void ABaseCharacter::GetHit_Implementation(const FVector& ImpactPoint, AActor* Hitter)
{
	if (IsAlive() && Hitter) DirectionalHitReact(Hitter->GetActorLocation());

 

타격자의 위치 정보를 준다.

 

물론 이렇게 바꾸려면 바인딩 되어있는 함수(GetHit를 호출하는 함수)에서도 매개변수를 다르게 줘야할 것이다.

 

GetHit 함수는 무기 클래스에서 호출하고 있으며 각각의 자식 클래스에서도 Super:: 로 호출하고 있다.

 

void AWeapons::ExecuteGetHit(FHitResult& HitResult)
{
	IHitInterface* HitInterace = Cast<IHitInterface>(HitResult.GetActor());
	if (HitInterace)
	{
		HitInterace->Execute_GetHit(HitResult.GetActor(), HitResult.ImpactPoint, GetOwner());
	}
}

 

무기 클래스에서는 타격자, 즉 무기의 주인을 넘겨주면 된다.


2. 버그 수정하기

 

방향성 타격과는 관계없는 다른 버그가 있는데 이것을 수정할 것이다. 플레이어가 공격 중에 맞으면 검을 대기만 해도 적이 피해를 입는다. 이를 방지하자.

 

void AKnight::GetHit_Implementation(const FVector& ImpactPoint, AActor* Hitter)
{
	Super::GetHit_Implementation(ImpactPoint, Hitter);

	SetWeaponCollisionEnabled(ECollisionEnabled::NoCollision);
	ActionState = EActionState::EAS_HitReaction;
}

 

캐릭터 클래스에서 히트할 경우 무기의 콜리전을 사라지게 하면 된다.