Unreal5 Dot Product(내적) C++
- 프로그래밍/언리얼
- 2023. 5. 8.
Unreal5 Dot Product(내적) C++
저번글에서 간단한 Hit를 구현했는데 좀 더 살을 붙여보려고 합니다.
이번 글에서는 Dot Product를 이용해 Player가 때리는 각도를 알아보려고 합니다.
- Dot Product(내적).
- 코드 작성.
- 결과.
DotProduct(내적).
Enemy를 어제 구현한 Hit로 때렸을 때 각도를 알아보겠습니다.
일단 이 글에서는 Dot Product에 대한 코드만 작성할 예정입니다.
구한 각도는 아래 사진처럼 (0-180도)로 표시됩니다.
아래처럼 내적을 사용하면 Player가 어느 각도에서 공격했는지 구할 수 있습니다.
이 부분을 아래에서 코드로 구현할 예정입니다.
코드 작성.
먼저 HitInterface c++ class를 하나 만들어줬습니다.
내용은 별 것 없습니다.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "HitInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UHitInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class SLAYER_API IHitInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
virtual void GetHit(const FVector& ImpactPoint)=0;
};
Enemy.h에서 HitInterface를 include해주고, IHitInterface를 상속합니다.
HitInterface에 GetHit를 선언했으니 Enemy.h에서는 사용하기 위해 override 해줍니다.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Interface/HitInterface.h"
#include "Enemy.generated.h"
UCLASS()
class SLAYER_API AEnemy : public ACharacter,public IHitInterface
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AEnemy();
virtual void GetHit(const FVector& ImpactPoint) override;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
//void DirectHitReact(const FVector& impactPoint);
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};
이제 GetHit를 구현하겠습니다.
FVector ImpactPoint 매개변수로 충격지점을 받아와서 해당 지점에 대한 디버깅 구를 그리고, 적 캐릭터가 바라보는 방향벡터와 충격 지점과의 각도를 위에서 설명한 방법을 통해 계산해서 로그에 출력하는 함수입니다.
이를 통해 적 캐릭터가 어떤 방향을 바라보고 있을 때 어느 방향으로 공격받았는지 알 수 있습니다.
하지만 아직 왼쪽에서 공격을 받았는지 오른쪽에서 공격을 받았는지는 구분할 수 없으며, 이를 위해 다음 글에서 Cross Product(외적)을 이용해 알아낼 예정입니다.
void AEnemy::GetHit(const FVector& ImpactPoint)
{
DrawDebugSphere(GetWorld(), ImpactPoint, 10.f,15, FColor::Orange, false, 3.f);
const FVector Forward = GetActorForwardVector();
const FVector Impact (ImpactPoint.X, ImpactPoint.Y, GetActorLocation().Z);
const FVector ToHit = (ImpactPoint - GetActorLocation()).GetSafeNormal();
//Dot Product
const double CosTheta = FVector::DotProduct(Forward, ToHit);
double Theta = FMath::Acos(CosTheta);
Theta = FMath::RadiansToDegrees(Theta);
UE_LOG(LogTemp, Log, TEXT("%f"),Theta);
}
마지막으로 Weapon.cpp의 OnBoxOverlap함수입니다.
Enemy의 GetHit 함수에 impact point를 전달합니다.
void AWeapon::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);
//#include "Kismet/KismetSystemLibrary.h"
FHitResult BoxHit;
UKismetSystemLibrary::BoxTraceSingle(this,Start,End, FVector(5.f, 5.f, 5.f),BoxTraceStart->GetComponentRotation(), ETraceTypeQuery::TraceTypeQuery1,
false,ActorsToIgnore,EDrawDebugTrace::None, BoxHit,true);
//if (GetWorld()) {
// DrawDebugSphere(GetWorld(),BoxHit.ImpactPoint,20.f,15,FColor::Red,false,5.f);
//}
if (BoxHit.GetActor()) {
/*Actor를 때렸을 때*/
IHitInterface* HitInterface = Cast<IHitInterface>(BoxHit.GetActor());
if (HitInterface) {
HitInterface->GetHit(BoxHit.ImpactPoint);
}
}
}
결과.
이런식으로 각도가 표시됩니다.