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

카메라에서 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 을 이용해서 총의 맨 끝에있는 소켓부터, 위에서 구한 HitResult 의 ImpactPoint 까지 트레이싱을 해줍니다.
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);
}

이렇게 하면 여러 문제점이 바로 보입니다.
AimOffset 이 제대로 설정되지 않았습니다. 항상 총구가 해당 방향을 가리키도록 해야합니다.fireDestVector 는 충돌 지점의 위치입니다. 길이를 더 늘려야 합니다.fireDestVector가 zeroVector가 반환됩니다.해당 문제점들은 치명적이지 않으므로 나중에 따로 고치도록 하겠습니다.
간단하게 몇가지 컴포넌트와 Mesh와 Collision 만 설정하여 LineTrace로 탐지할 수 있도록 했습니다.


주의해야하는 점은, 콜리전 프리셋에서 Visibility 를 Block 으로 설정해야합니다.
이제 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만 만들겠습니다.



CurveTable 과 GameplayEffect 를 사용하여 필요한 값들을 설정해줍니다.
해당 GE를 실행하기 위해서 DataAsset 클래스에 해당 GE들을 받아 실행해주겠습니다.
/** 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로 시각화 시켜주면 간단한 게임을 플레이할 수 있습니다.
하나씩 차근차근 해보도록 하겠습니다.