개인프로젝트

[Unreal_C++_DarkSoul]#11_기능 구현, Parkour(Vaulting)

Hardii2 2022. 12. 25. 11:25

 

[Unreal_C++_DarkSoul]#11_Parkour(Vaulting)

 

장애물을 비교적 수월하게 극복하기 위해 Parkour 동작을 구현합니다.

Unreal 포트폴리오 작업 과정을 기록합니다.


 

Overview

 

  1. 개요
  2. 설계
  3. 상세 내용
  4. 게임 플레이 화면

 

개요

1. 목적

  1. Player가 장애물을 보다 자연스럽게 넘어갈 수 있도록 합니다.
  2. Player가 기본 동작만으로 극복할 수 없는 장애물들을 키 입력 하나로 보다 수월하게 극복할 수 있도록 합니다.
  3. Player의 게임 플레이 과정에서 찾을 수 있는 재미 요소(?)를 추가하기 위함입니다.

 

2. 개요

  1. 먼저, First Person Character를 기준으로 세 가지 Line Tracing을 수행합니다.
  2. 세 가지 Line Tracing을 통해 장애물과 FPC과의 거리, 장애물의 높이, 마지막으로 장애물의 두께를 측정합니다.
  3. 각각의 Line Tracing 과정을 통해 FPC가 해당 장애물을 "Parkour" 동작을 통해 극복할 수 있는지 결정합니다.
  4. 결과적으로, 세 가지 Line Tracing 조건들과 합치하는 장애물을 마주한 FPC는 "Parkour" 동작을 통해 해당 장애물을 극복합니다.

 

설계

1. Vault Component

  1. Unreal의 "UActorComponent" 클래스를 상속하는 Vault Component를 생성합니다.
  2. Player의 Parkour 동작 수행을 정의합니다.

2. VaultComponent::DetectWall()

  1. DetectWallFront(), DetectWallHeight(), 그리고 DetectWallDepth()를 차례대로 호출합니다.
  2. 위에서 설명했듯, 위 세 함수는 FPC가 해당 장애물을 "Parkour"를 통해 극복할 수 있는지 가늠하기 위함입니다.

3. Player의 상태 변경

  1. FPC가 "Parkour" 동작을 수행하는 과정을 화면에 그려내기 위해 "Anim Montage"를 재생합니다.
  2. FPC가 장애물과 불필요한 "충돌"을 피하기 위해 Capsule Collision의 충돌 여부를 변경해야 합니다.
  3. FPC가 "Parkour" 과정에서 이외 다른 동작을 수행하지 못하도록, 상태 기계(상태 값) 또한 관리해야 합니다. 
  4. FPC의 "Parkour" 동작을 수행함으로써, 응당 변경해야 하는 "Rotation""Location" 값 또한 변경해야합니다.

 

상세 내용

1. DetectWall()

bool UC_VaultComponent::DetectWall(class APlayerCharacter** InPlayer)
{

	bCanVault = true;
	// #1 Player와 Wall과의 거리
	bCanVault &= DetectWallFront(InPlayer);
	// #2 Wall의 높이
	if (bCanVault == true)
		bCanVault &= DetectWallHeight(InPlayer);
	// #3 Wall의 두께
	if (bCanVault == true || bCanClimb == true)
		bCanVault &= DetectWallDepth(InPlayer);
        
	return bCanVault || bCanClimb;
}

 

 

Details

 

  1. 먼저, Player와 Wall(장애물)과의 거리를 계산합니다.
  2. 위 조건이 합치한다면, DetectWall 함수는 다음으로 장애물의 높이, 그리고 장애물의 두께를 측정합니다.
  3. 이때, 장애물의 높이 조건을 살펴보는 과정에서 "Vault" 동작으로 극복할 수 없지만, "Climb" 동작으로 극복 가능할 경우를 대비해 "bCanClimb" 변수의 조건 또한 고려합니다.

 

2. FixRotation() + FixLocation()

void UC_VaultComponent::FixRotation(class APlayerCharacter** InPlayer)
{
	FRotator Rotation = (*InPlayer)->GetActorRotation();
	FRotator ChangeRotation = FrontWallNormalLocation.Rotation();
	ChangeRotation.Yaw += 180.f;
	Rotation.Yaw = ChangeRotation.Yaw;

	(*InPlayer)->SetActorRotation(Rotation);
}

void UC_VaultComponent::FixLocation(APlayerCharacter** InPlayer, float InFloat1, float InFloat2)
{
	FVector ChangeLocation = (UKismetMathLibrary::GetForwardVector(FrontWallNormalLocation.Rotation())) * InFloat1 + FrontWallLocation;
	float VectorZ = HeightWallLocation.Z + InFloat2;

	FVector NewLocation = FVector(ChangeLocation.X, ChangeLocation.Y, VectorZ);
	(*InPlayer)->SetActorLocation(NewLocation);
}

 

Details

 

  1. FixRotation() 함수는 DetectWall() 함수의 결과 값이 "True"라면, Player의 "Rotataion" 값 변환을 정의합니다.
  2. FixLocation() 함수는 Player가 최종적으로 "Parkour" 동작을 수행하며, 변환될 "Location"값을 정의합니다.

 

3. OnCollision() + OffCollision()

void UC_VaultComponent::OnCollision()
{
	AActor* OwnerActor = GetOwner();
	CheckNull(OwnerActor);
	APlayerCharacter* OwnerPlayer = Cast<APlayerCharacter>(OwnerActor);
	CheckNull(OwnerPlayer);

	OwnerPlayer->GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
	OwnerPlayer->GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_Walking);
	
}

void UC_VaultComponent::OffCollision(APlayerCharacter** InPlayer)
{

	(*InPlayer)->GetCapsuleComponent()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
	(*InPlayer)->GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_Flying);

}

 

Details

 

  1. OnCollision() 메서드와 OffCollision() 메서드는 Player와 장애물의 불필요한 "충돌"을 방지하기 위해 Player의 Capusle 컴포넌트의 충돌 여부를 정의합니다.
  2. 이때, "OnCollision()" 메서드는 Player가 장애물을 온전히 극복하고 호출되는 함수로, "Timer"를 활용합니다.

 

결과 화면