[UE5] #6 - GAS-3 | AttributeSet

qweasfjbv·2024년 10월 3일

UnrealEngine5

목록 보기
6/8

개요


이번에는 지금까지 만든 GAS를 수치적으로 확인해보기 위해서, AttributeSet을 정의하고 제 캐릭터와 적에게 적용한 후에 실제로 공격을 통해 체력이 줄어드는것을 확인해보겠습니다.

우선, 총을 발사하기 위해 RayCast를 사용하겠습니다.

구현


LineTrace

카메라에서 LineTrace를 통해 표적의 위치를 찾고, 총에서부터 해당 위치로 LineTrace를 한번 더 쏴서 처음 맞는 적에게 데미지를 입히도록 합니다.

우선, 위 그림의 파란 LineTrace부터 구현하겠습니다.

/** cpp File **/
void APlayerGunnerCharacter::RaycastAim()
{
	if (!bIsAiming) return;

	FHitResult HitResultCam;
	FVector2D AimPosition = FVector2D(GEngine->GameViewport->Viewport->GetSizeXY() / 2);
	
	PlayerController->GetHitResultAtScreenPosition(
		AimPosition,
		ECollisionChannel::ECC_Visibility,
		false,
		HitResultCam
	);


	DrawDebugSphere(
		GetWorld(),
		HitResultCam.ImpactPoint,
		20.f,
		12,
		FColor::Red,
		false,
		1.f
	);

Viewport의 중앙에 해당하는 월드의 위치를 찾습니다.

그리고 LineTraceSingleByChannel 을 이용해서 총의 맨 끝에있는 소켓부터, 위에서 구한 HitResultImpactPoint 까지 트레이싱을 해줍니다.

	const FVector fireStartVector = GetGunnerSkeletalMeshFromActorInfo()->GetSocketLocation("FireSocket");
	const FVector fireDestVector = HitResultCam.ImpactPoint;

	FCollisionQueryParams collisionParams;
	collisionParams.AddIgnoredActor(this);

	FHitResult HitResultFire;

	if (
		GetWorld()->LineTraceSingleByChannel(
			HitResultFire,
			fireStartVector, fireDestVector,
			ECollisionChannel::ECC_Visibility,
			collisionParams
		)) {
		UE_LOG(LogTemp, Warning, TEXT("Line Traced!"));
	}

	DrawDebugLine(GetWorld(), fireStartVector, fireDestVector, FColor::Emerald, false, 1.f);

}

이렇게 하면 여러 문제점이 바로 보입니다.

  1. AimOffset 이 제대로 설정되지 않았습니다. 항상 총구가 해당 방향을 가리키도록 해야합니다.
  2. fireDestVector 는 충돌 지점의 위치입니다. 길이를 더 늘려야 합니다.
  3. 아무 오브젝트도 없는 곳을 조준하면 fireDestVector가 zeroVector가 반환됩니다.

해당 문제점들은 치명적이지 않으므로 나중에 따로 고치도록 하겠습니다.


EnemyCharacter 생성

간단하게 몇가지 컴포넌트와 Mesh와 Collision 만 설정하여 LineTrace로 탐지할 수 있도록 했습니다.

주의해야하는 점은, 콜리전 프리셋에서 VisibilityBlock 으로 설정해야합니다.

이제 AttributeSet을 통해 간단하게 체력과 공격력, 방어력을 만들겠습니다.


AttributeSet

AttributeSet.h 에 있는 Getter/Setter 등 접근하는 함수들을 편하게 만들어주는 매크로입니다.
이걸 사용하면 제가 직접 구현하지 않아도 편하게 사용가능합니다.

/** HeaderFile **/

public:
	UPlayerAttributeSet();

	UPROPERTY(BlueprintReadOnly, Category = "Health")
	FGameplayAttributeData CurrentHealth;
	ATTRIBUTE_ACCESSORS(UPlayerAttributeSet, CurrentHealth)

	// .. Other AttributeDatas...
    
/** cpp File **/

UPlayerAttributeSet::UPlayerAttributeSet()
{
	InitCurrentHealth(5.f);
    
    // ...
}

이제 이 AttributeSet 에 값을 지정하겠습니다.


GameEffect 설정 및 AttributeSet 적용

간단하게 먼저 두 개의 GameEffect만 만들겠습니다.

  • 레벨에 따라 변하는 값 설정
  • 게임 중 실시간으로 변하는 값 설정

CurveTableGameplayEffect 를 사용하여 필요한 값들을 설정해줍니다.

해당 GE를 실행하기 위해서 DataAsset 클래스에 해당 GE들을 받아 실행해주겠습니다.

UDataAsset_StartupDataBase : UDataAsset

/** Header File **/

	UPROPERTY(EditDefaultsOnly, Category = "StartUpData")
	TArray<TSubclassOf<UGameplayEffect>> StartUpGameplayEffects;
    
/** cpp File **/

	if (!StartUpGameplayEffects.IsEmpty()) {
		for (const TSubclassOf<UGameplayEffect>& Effect : StartUpGameplayEffects) {
			if (!Effect) continue;

			InASCToGive->ApplyGameplayEffectToSelf(
				Effect->GetDefaultObject<UGameplayEffect>(),
				ApplyLevel,
				InASCToGive->MakeEffectContext()
			);
		}
	}

해당 코드를 적절한 함수에 추가한 후에 실행합니다.

showdebug abilitysystem 으로 확인해보면 값이 잘 들어가있는걸 확인할 수 있습니다.

마무리


플레이어와 적에게 AttributeSet이 설정한대로 잘 적용되었습니다.
이제, 총을 발사 했을 때 데미지가 닳는 것을 구현할 차례입니다.

그 후에 플레이어의 VFX와 피격시 애니메이션, 회피, EnemyAI 와 적의 VFX까지 구현한 후에 UI로 시각화 시켜주면 간단한 게임을 플레이할 수 있습니다.

하나씩 차근차근 해보도록 하겠습니다.

0개의 댓글