목차
- 외적이란?
- 외적을 통해 히트 방향 알아내기
- c++에서 적용하기
1. 외적이란?
백터의 외적은 3차원 공간에서 백터와 백터끼리 곱한 것으로 크기만 있는 내적과 달리 크기와 방향 모두 존재한다. 그리고 이 방향은 오른손 법칙을 통해 알아낼 수 있다.
전자기학에서도 이 오른손 법칙이 쓰이는데 재밌는 점은 백터의 외적 자체가 자기장 속 전하가 받는 힘의 크기와 방향을 구할 때도 쓰인다고 하니 본질적으로는 둘이 같은 것이라고 볼 수도 있을 것 같다. (출처)
외적은 크기와 방향 모두 구할 수 있지만 현재 알고 싶은 것은 방향이기 때문에 오른손 법칙이 주요하게 쓰일 것이다.
2. 외적을 통해 히트 방향 알아내기
백터의 내적은 그 특징상 양수의 값만 나오고 그렇기 때문에 이것만으로는 히트의 방향을 정확히 알 수가 없다. 그렇기 때문에 외적을 통해 추가적으로 방향을 알아내어야 한다.
A방향의 백터가 있고 B방향의 백터가 있을 경우 이 두 백터의 곱의 방향은 그림에서 처럼 위를 향하거나 아래를 향할 것이다. 이때 어느 방향으로 향할지는 어느 순서로 곱하냐에 따라 다르다.
그림에 나온 것처럼 A * B 의 경우 위를 향하고 B * A 의 경우 아래를 향하는데 이때 바로 오른손 법칙이 쓰일 수 있다.
그림으로만 보면 직관적으로 안 와닿을 수도 있는데 동영상을 보면 훨씬 직관적으로 이걸 알아볼 수 있다.
어쨌든 이것을 통해 드디어 히트 방향을 알아낼 수 있다.
전의 포스팅에서 이어 쓰면 에너미에게는 전방백터와 타격지점을 향하는 백터(ToHit)가 존재한다. 이렇게 두 개의 백터가 존재하고 이 두 백터의 곱의 방향을 알아내고 이를 내적에서 구한 각도와 합치면 정확한 타격방향을 알 수 있다.
3. c++에서 적용하기
이제 비주얼 스튜디오에서 이를 구현해보자. 백터의 외적은 대학 과정은 가야 배우는 어려운 수학 학문중 하나이고 그렇기 때문에 이 외적을 일일이 구하는 것은 현실적으로 힘들다.
하지만 다행이 외적또한 엔진에 있는 라이브러리를 통해 쉽게 구할 수 있다.
여기서 주의사항은 언리얼 엔진에서 실제 외적을 구할때 방향은 오른손 법칙과 반대라는 것이다. 그림에서 A * B 의 방향은 위를 향하지만 엔진에서는 방향이 아래를 향한다. 이것을 조심하면서 외적을 구해보자.
// 만약 외적 방향이 아래를 향하면 세타는 마이너스이다.
const FVector CrossProduct = FVector::CrossProduct(Forward, ToHit);
if (CrossProduct.Z < 0)
{
Theta *= -1.f;
}
다음과 같이 쉽게 구할 수 있다.
전체 코드는 아래와 같다.
void AEnemy::GetHit(const FVector& ImpactPoint)
{
if (GetWorld())
{
DrawDebugSphere(GetWorld(), ImpactPoint, 8.f, 12, FColor::White, false, 5.f);
}
PlayHitReactMontage(FName("FromFront"));
// 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;
}
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(1, 10.f, FColor::Cyan, FString::Printf(TEXT("Theta : %f"), Theta));
}
}
에디터에서 확인하면 이렇게 왼쪽에서 공격할 경우 마이너스의 값이 나오는 것을 확인할 수 있다. (오른손 법칙으로 따지면 이때 양수의 값이 나와야한다)
이제 세타를 정확히 알아낼 수 있으니 이 값을 통해 타격방향을 정할 수 있고 이를 통해 타격 애니메이션을 방향에 따라 다르게 줄 수 있다.
다음에 이것을 해보도록 하자.
'게임프로그래밍 > 실습1' 카테고리의 다른 글
[언리얼 실습] 31. C++에서 히트시 메타사운드 재생하기 (0) | 2024.10.30 |
---|---|
[언리얼 실습] 30. 1회 공격 당 1히트만 하기 (0) | 2024.10.29 |
[언리얼 실습] 28. 백터의 내적을 통해 Hit 방향 알아내기 (0) | 2024.10.29 |
[언리얼 실습] 27. 인터페이스 사용하기 (0) | 2024.10.28 |
[언리얼 실습] 26. 에너미 클래스 만들기 (0) | 2024.10.28 |