본문 바로가기

게임프로그래밍/실습1

[언리얼 강의] 71. 모션워핑을 통해 적이 공격할 때 플레이어 바라보게 하기


목차

  1. Motion Warping
  2. 이벤트 설정하기
  3. 공격 시작 중 플레이어에게 맞아도 바로 공격하는 문제 수정하기

1. Motion Warping

 

현재 에너미는 캐릭터의 위치와는 상관없이 전방 방향으로만 공격한다. 이부분을 고쳐 에너미가 플레이어를 향하게 해볼 것이고 루트 모션 애니메이션과 모션 워핑을 활용해 이를 구현할 것이다.

 

 

모션 워핑을 사용하기 위해서는 플러그인을 사용해야 한다. 플러그인을 적용하려면 에디터를 껐다 켜야하니 저장을 잘 해놓자.

 

이제 에너미의 블루프린트 클래스로 들어간다.

 

 

모션 워핑 컴포넌트를 추가해주자.

 

그다음 공격 몽타주로 들어가자.

 

 

 

노티파이 스테이트에서 모션 워핑을 추가해준다.

 

 

노티파이의 길이를 조절할 수 있는데 저 길이 동안 모션 워핑을 진행하게 된다.

 

모션 워핑을 작동하는 법을 알아보자. 모션 워핑을 선택한 상태로 디테일 패널을 살펴본다.

 

 

모션 모디파이어를 Skew Warp로 설정해준다. 스케일의 경우 애니메이션의 크기나 길이를 조절하는 것이고 skew warp의 경우 각도등을 바꾸는 것이라고 한다.

 

 

워프 타겟 네임은 나중에 블루프린트나 C++ 에서 타겟으로 삼을 대상의 이름이다. 물론 대상은 나중에 설정해주어야 한다.

 

나머지 설정은 딱히 건드릴께 없고, 로테이션 타입만 바꿔보자. 디폴트의 경우 워프 타겟으로 부드럽게 회전하는 것이고 페이싱의 경우 바로 워프타겟을 향해 바라보게 하는 설정이라고 한다.


2. 이벤트 설정하기

 

이제 설정을 했으니 실제로 바라보게 해야한다. 커스텀 이벤트를 생성해서 이를 적용할 것이다. 에너미의 블루프린트 클래스로 들어가자.

 

 

커스텀 이벤트를 생성해준다.

 

 

모션 워핑 컴포넌트를 끌고 오자.

 

 

 

워프타겟으로 부터 트랜스폼을 받아와 업데이트나 추가하는 함수를 연결해준다.

 

 

이제 타겟의 위치를 알아야 할것이다.

 

비주얼 스튜디오로 들어가자.

 

 

에너미 클래스에서는 현재 교전중인 대상을 저장하는 변수가 있다.

 

이를 블루프린트에서 보이게 해야할 것이다.

 

 

블루프린트에서 읽을 수 있는 변수로 만들자.

 

컴파일을 하고 에너미의 블루프린트로 들어가자.

 

 

컴뱃 타겟이 유효한 대상인지 확인하고,

 

 

트랜스폼을 가져와 연결해준다.

 

 

워프타겟 네임도 물론 적어야 할 것이다.

 

몽타주로 들어와 노티파이를 하나 더 추가해준다.

 

 

이제 애니메이션 블루프린트 클래스에서 노티파이로 커스텀 이벤트를 호출하면 된다.

 

 

이렇게 하면 노티파이가 호출될 때 마다 워프 타겟의 위치가 업데이트가 될 것이고, 모션 워핑 스테이트 길이 동안 회전을 진행할 것이다.

 

노티파이가 호출되고 타겟의 위치가 바뀔 수 있다. 즉 노티파이를 자주 호출할 수록 업데이트가 자주 일어나고 그만큼 워프 타겟을 향할 확률이 증가한다.

 

이것을 잘 조절해서 게임의 난이도를 조절할 수 있다고 한다.

 

 

 

이제 에너미가 공격할때 플레이어를 향하게 움직인다.

 

플레이어의 트랜스폼 정보 전부를 가지고 가 업데이트 하는데 이때 Locaion까지 변경되어 에너미가 약간 순간이동을 하는 느낌을 주기도 한다. 이러한 부분들은 조절해서 어색하지 않게 바꾸면 될 듯하다.


3. 공격 시작 중 플레이어에게 맞아도 바로 공격하는 문제 수정하기

 

현재 공격 상태에 들어가면 어택 타이머가 실행중이라 히트를 해도 바로 애니메이션이 재생이 된다.

 

히트할 경우 타이머를 종료시켜 이를 방지하도록하자. 비주얼 스튜디오에 들어간다.

 

void AEnemy::GetHit_Implementation(const FVector& ImpactPoint, AActor* Hitter)
{
	Super::GetHit_Implementation(ImpactPoint, Hitter);
	if (!IsDead()) ShowHealthBar();
	ClearPatrolTimer();
	ClearAttackTimer();
    SetWeaponCollisionEnabled(ECollisionEnabled::NoCollision);
    
    StopAttackMontage();
}
void ABaseCharacter::StopAttackMontage()
{
	UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
	if (AnimInstance && AttackMontage)
	{
		AnimInstance->Montage_Stop(0.25f, AttackMontage);
	}
}

 

어택타이머를 초기화해주고 몽타주 재생을 중지시킨뒤 무기의 콜리전을 없앤다.. 여기서 ClearAttackTimer 함수는 커스텀 함수이다.

 

float AEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
	HandleDamage(DamageAmount);

	CombatTarget = EventInstigator->GetPawn();
	ChaseTarget();

	return DamageAmount;
}

 

그 다음 위 함수에서 데미지를 입으면 타겟을 추격하게 되어있는데 단순 추격이 아니라 거리에 따라 공격, 추격 무엇을 할지 정해야 할 것이다.

 

float AEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
	HandleDamage(DamageAmount);

	if (IsInSideAttackRadius())
	{
		EnemyState = EEnemyState::EES_Attacking;
	}
	else if (IsOutSideAttackRadius())
	{
		ChaseTarget();
	}

	return DamageAmount;
}

 

이제 다음에는 너무 가까이 붙었을 때 에너미가 플레이어를 공격하지 못하는 현상을 수정해볼것이다.