Dev11 적 보간/공격 텀, NPC 무기/애니메이션, 타겟에게 마법 이동, 마법 추가
기말 발표 때문에 시간 없어서 미뤄둔 포스팅.. 드디어 시작
적 보간
Enemy.h
플레이어 보간과 똑같다.
// When enemy attck target, enemy look at target
float InterpSpeed;
bool bInterpToTarget;
void SetInterpToTarget(bool Interp);
FRotator GetLookAtRotationYaw(FVector Target);
in Enemy.cpp
void AEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (bInterpToTarget && bOverlappingCombatSphere)
{
FRotator LookAtYaw = GetLookAtRotationYaw(CombatTarget->GetActorLocation());
FRotator InterpRotation = FMath::RInterpTo(GetActorRotation(), LookAtYaw, DeltaTime, InterpSpeed); //smooth transition
SetActorRotation(InterpRotation);
}
}
void AEnemy::SetInterpToTarget(bool Interp)
{
bInterpToTarget = Interp;
}
FRotator AEnemy::GetLookAtRotationYaw(FVector Target)
{
FRotator LookAtRotation = UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), Target);
FRotator LookAtRotationYaw(0.f, LookAtRotation.Yaw, 0.f);
return LookAtRotationYaw;
}
회전은 bInterpToTarget와 bOverlappingCombatSphere가 모두 참일 때 실행한다.
bInterpToTarget은 공격을 끝낸 뒤 참으로 만들고
void AEnemy::AttackEnd()
{
bAttacking = false;
SetInterpToTarget(true);
if (bOverlappingCombatSphere)
{
GetWorldTimerManager().SetTimer(AttackTimer, this, &AEnemy::Attack, AttackDelay);
}
}
Attack()에서 false로 만든다. 즉, 공격 애니메이션을 실행 중일 때는 회전하지 않는다.
공격 애니메이션이 끝난 뒤 (타겟이 전투 범위 내에 있으면) 회전한다. + 그리고 다시 공격
그리고 공격 텀은 따로 타이머를 두었다.
in Enemey.h
FTimerHandle AttackTimer;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Combat")
float AttackDelay;
타이머는 AttackEnd()에서 동작한다. (위에 있음)
딜레이 시간은 몹마다 다르다.
NPC 무기쪽을 손봤다.
원래는 무기가 각각 블루프린트 클래스로 존재해서 오버랩해서 장착하는 방식이었는데,
전에 고블린한테 스태틱 메시로 방망이 무기 붙였던 것에서 영감을 받아서 NPC들의 무기도 전부 스태틱 메시로 붙였다. 이렇게 하면 굳이 블루프린트 클래스가 존재하지 않아도 되고 딜레이를 주어서 오버랩되어있는지 검사하지 않아도 된다.
이제 Equip_NPC메서드가 필요없어져서 Weapon 클래스에서 없앴다.
NPC의 애니메이션도 대부분 지팡이를 손에 쥐고 있지 않은, 즉 손을 편 상태여서 전부 플레이어와 같은 애니메이션으로 리타깃해서 만들어줬다.
전투 몽타주도 만들어줬다. 대신 아직 공격 애니메이션만 들어가있다.
타겟에게 마법 공격 보내기
in MagicSkill.h
UPROPERTY(EditInstanceOnly, BlueprintReadOnly, Category = "MoveActor")
class AEnemy* Target;
// To move Target
FVector Direction;
float TotalDistance;
float CurrentDistance;
FVector StartLocation;
일단 어디로 이동할 것인지 타겟이 있어야함.
현재 마법은 플레이어와 NPC들만이 사용하므로 타겟의 타입은 AEnemy이지만 나중에 마법 쓰는 적도 추가할 예정이다. (타입을 아마 캐릭터로 바꿔야할 듯??)
그리고 타겟까지의 거리 등등이 필요.
참고로 이 기능은 이동하는 마법만이 해당된다. (스톰, 파이어볼, 워터볼 등등)
타겟 위치에서 바로 스폰되는 마법들은 해당 안 됨.
플레이어로 예를 들자면 현재 이동 마법이 모래바람(1번 스킬) 하나이므로 1번 스킬일 때만 마법 공격의 타겟을 지정해준다.
in Spawn() of Main.cpp
if (MagicAttack && SkillNum == 1 && CombatTarget) MagicAttack->Target = CombatTarget;
in BeginPlay() of MagicSkill.cpp
FTimerHandle WaitHandle2;
GetWorld()->GetTimerManager().SetTimer(WaitHandle2, FTimerDelegate::CreateLambda([&]() {
if (this->GetName().Contains("Hit") || this->GetName().Contains("Storm"))
{
SetLocation();
}
}), 0.1f, false);
타이머를 안 쓰고 바로 하면 실행이 안 되는 듯하다. 그래서 0.1초 뒤에 실행하기로 했다.
NPC들이 쓰는 스톰 공격과 이름에 Hit이 들어간 공격들만 해당된다. 이동하는 공격들은 스톰 제외 전부 이름에 Hit을 넣어줬다.
in MaigicSkill.cpp
void AMagicSkill::SetLocation()
{
if (Target != nullptr)
{
StartLocation = GetActorLocation();
Direction = Target->GetActorLocation() - StartLocation;
TotalDistance = Direction.Size();
Direction = Direction.GetSafeNormal();
CurrentDistance = 0.0f;
}
}
스타트 위치를 현재 스폰된 마법 공격의 위치로 할당하고,
타겟의 위치에서 스타트 위치를 뺀 값을 Direction에 할당.
총 거리는 방금 계산한 Direction이 된다.
GetSafeNormal()은
벡터의 정규화된 복사본을 가져와 길이에 따라 안전한지 확인합니다. 벡터 길이가 너무 작아 안전하게 정규화할 수 없는 경우 0 벡터를 반환합니다.
라고 한다.
현재 거리를 0.0으로 초기화해준다.
(사실 이미 0.0이긴 하다.)
void AMagicSkill::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (Target != nullptr)
{
if (CurrentDistance < TotalDistance)
{
FVector Location = GetActorLocation();
Location += Direction * MovementComponent->InitialSpeed * DeltaTime;
SetActorLocation(Location);
CurrentDistance = (Location - StartLocation).Size();
}
}
}
틱 함수에서는 총 거리보다 현재 거리가 작으면(즉, 타겟 위치에 도달하지 않았으면)
현재 액터(마법 공격)의 위치를 받아와서 DeltaTime마다 InitialSpeed의 속도로 (타겟의 위치쪽으로)조금씩 증가시킨다.
그리고 액터의 위치를 방금 증가시킨 Location으로 설정한다.
그리고 현재 거리를 갱신한다.
실행 순서는 BeginPlay() - SetLocation() - Tick() 순이다.
SetLocation()에서 TotalDistance의 값이 바뀌기 때문에 그제야 비로소 Tick의
if (CurrentDistance < TotalDistance) 조건에 부합하게 된다.
(SetLocation() 전에는 Current/Total 모두 0.0이다.)
마법 공격 추가
NPC들도 각자 3개씩 마법을 사용할 수 있다.
영상은 다음 포스팅에!