언리얼 엔진 5/개발 일지

[UE5] 블루아카이브 TPS게임 개발일지 (32) - 엄폐 시스템 구현 2

ciel45 2024. 1. 7. 18:35

이제 플레이어가 Cover 인풋 액션을 입력하면, 그에 맞는 함수가 실행될 것이다. 현재 인풋에 대한 바인딩은 이렇게 되어있다.

 

//KannaCharacter.cpp
EnhancedInputComponent->BindAction(CoverAction, ETriggerEvent::Triggered, this, &AKannaCharacter::TakeCover);

 

콜백함수인 TakeCover은 다음과 같은 기능을 해야한다.

  • 엄폐 중일 시 엄폐물에서 빠져나옴
  • 엄폐 중이 아니었을 시, 앞에 적절한 엄폐물이 있을 때에만 엄폐 수행

 

TakeCover 함수는 다음과 같다.

void AKannaCharacter::TakeCover()
{
	if (IsInCover)
	{
		StopCover();
	}
	else
	{
		WallTrace(); // 엄폐물이 있는지 탐지
	}
}

 

 

StopCover 함수가 있다면, StartCover도 물론 있다. StartCover는 WallTrace 안에서 호출되게 할 것이다.

각각의 함수는 다음과 같다.

void AKannaCharacter::StartCover(FVector& PlaneNormal)
{
	//이동 방향 좌우로 고정
	GetCharacterMovement()->SetPlaneConstraintEnabled(true);
	GetCharacterMovement()->SetPlaneConstraintNormal(PlaneNormal);

	IsInCover = true;

	Crouch();	
}

void AKannaCharacter::StopCover()
{
	//이동 방향 고정 해제
	GetCharacterMovement()->SetPlaneConstraintEnabled(false);
	
	IsInCover = false;

	UnCrouch();
}

SetPlaneConstraintEnabled를 이용하여, 캐릭터의 특정 평면에서의 이동을 제한할 수 있다.

엄폐한 상태에서 벽면 기준 좌, 우로만 이동이 가능해야 할 것이다..

 

따라서 여기서 그 제한할 평면은, 벽면에 수직 방향인 법평면이다.

그러므로 StartCover의 인자로 넣어주는 벡터는, 바로 벽면의 법선 벡터가 될 것이다.

 

법선 벡터는 영어로 Normal Vector,

법평면은 영어로 Normal Plane이다. 파라미터의 이름이 PlaneNormal인 것도 그러한 이유이다.

 

 

 

 

다음은 StartCover를 호출하는 WallTrace 함수의 내용이다.

void AKannaCharacter::WallTrace()
{
	FVector Start = GetActorLocation();
	FVector End = GetActorLocation() + GetActorForwardVector() * 100.f;

	if (GetWorld())
	{
		FHitResult HitResult;

		FCollisionQueryParams CollisionParameters; // 트레이싱이 자기자신은 무시하도록
		CollisionParameters.AddIgnoredActor(this);

		if (GetWorld()->LineTraceSingleByChannel
			(HitResult, 
			Start, 
			End, 
			ECC_GameTraceChannel1, CollisionParameters
			)
		)
		{
			StartCover(HitResult.Normal);
		}

	}
}

캐릭터의 위치에서 정면으로 짧게 라인트레이싱을 하여, 엄폐물을 감지할 시 StartCover를 호출한다.

 

결과적으로, 엄폐물을 앞에 두고 엄폐 버튼을 누르면 캐릭터의 이동 방향이 좌,우로 제한되며, 캐릭터가 앉아서 엄폐한다.

 

 

 

 

 

캐릭터가 엄폐하고 있는 동안은 이동을 기존의 Move함수(WASD 이동의 콜백함수)가 아닌 새로 만든 함수에 맡길 것이다.

따라서 기존의 Move함수를 다음과 같이 수정했다.

void AKannaCharacter::Move(const FInputActionValue& Value)
{
	if (IsInCover) // 엄폐중일 경우 이동은 CoverTrace 함수에서 담당한다.
	{
		CoverTrace();
		return;
	}

	const FVector2D MovementVector = Value.Get<FVector2D>();

	const FRotator Rotation = Controller->GetControlRotation();
	const FRotator YawRotation(0.f, Rotation.Yaw, 0.f);

	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
	AddMovementInput(ForwardDirection, MovementVector.Y);
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
	AddMovementInput(RightDirection, MovementVector.X);
}

 

이렇게 한 이유는 엄폐중일때는 캐릭터의 좌, 우에 엄폐물의 잔여 공간이 남아있는지 확인하여, 엄폐물이 끝나는 지점에서는 움직일 수 없도록 해야하기 때문이다.

 

CoverTrace는 굉장히 길고 복잡한 함수가 될 예정이다. 따라서 이에 대한 포스팅은 별도로 분리하여 바로 다음 포스팅에 작성할 것이다.