[UE5] #5 - GAS-2 | Grant Ability

qweasfjbv·2024년 9월 30일

UnrealEngine5

목록 보기
5/8
post-thumbnail

개요


총을 발사하거나 재장전하는 등의 행동은 Aim을 한 상태에서만 가능하도록 해야합니다.
따라서 Aim을 하면 권한을 주고, Unaim을 하면 다시 권한을 뺏도록 해야합니다.

우선, GameAbility에서 각 능력을 Trigger 했을 때, 권한을 주거나 뺏을 자료형을 정의해야합니다.

구현


FPlayerWeaponData

USTRUCT(BlueprintType)
struct FPlayerWeaponData {
	GENERATED_BODY()

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	UInputMappingContext* WeaponMappingContext;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	TArray<FPlayerAbilitySet> DefaultPlayerAbilities;

};

해당 구조체를 GA에 하나 선언해주고 값을 넣어줍니다.

Controller 로부터 EnhancedInputLocalPlayerSubsystemAddMappingContext 함수를 호출할 수 있습니다.

입력을 막을 때에는 반대로 RemoveMappingContext 를 사용할 수 있습니다.


GrantAbility

void UPlayerAbilitySystemComponent::GrantHeroWeaponAbilities(const TArray<FPlayerAbilitySet>& InDefaultWeaponAbilities, int32 ApplyLevel, TArray<FGameplayAbilitySpecHandle>& OutGrantedAbilitySpecHandles)
{
	if (InDefaultWeaponAbilities.IsEmpty()) return;

	for (const FPlayerAbilitySet& AbilitySet : InDefaultWeaponAbilities) {
		if (!AbilitySet.IsValid()) continue;

		FGameplayAbilitySpec AbilitySpec(AbilitySet.AbilityToGrant);
		AbilitySpec.SourceObject = GetAvatarActor();
		AbilitySpec.Level = ApplyLevel;
		AbilitySpec.DynamicAbilityTags.AddTag(AbilitySet.InputTag);

		OutGrantedAbilitySpecHandles.AddUnique(GiveAbility(AbilitySpec));
	}
}


void UPlayerAbilitySystemComponent::RemoveGrantedHeroWeaponAbilities(UPARAM(ref)TArray<FGameplayAbilitySpecHandle>& InSpecHandlesToRemove)
{
	if (InSpecHandlesToRemove.IsEmpty()) return;

	for (const FGameplayAbilitySpecHandle& SpecHandle : InSpecHandlesToRemove) {
		if (!SpecHandle.IsValid()) continue;

		ClearAbility(SpecHandle);
	}

	InSpecHandlesToRemove.Empty();
}

위의 함수는 저번 글에서 생략했던 GiveAbility 로 권한을 부여하는 부분입니다.
우선, GiveAbility를 호출하는데 필요한 AbilitySpec을 정의하고, 반환되는 FGameplayAbilitySpec 또한 배열에 저장합니다.
이를 저장하는 이유는, 이 정보를 토대로 다시 권한을 뺏을 수 있기 때문입니다.

아래의 함수는 권한을 뺏는 함수입니다.
위의 함수에서 저장해뒀던 배열을 가지고있다가, 아래의 함수를 호출할 때 파라미터로 전달하면 됩니다.


Set Basic Values

Ability의 권한을 주고/뺏을 수 있게 되었습니다.
이제 총을 조준하는 듯한 애니메이션을 실행할 수 있도록 캐릭터 스크립트에 bool 변수를 선언하고 설정해줍니다.

저는 bUseControllerRotationYaw 를 True로 바꾸어서 조준할때에는 방향을 움직여도 회전하지 않도록 했습니다.

이제 마지막으로 Zoom 하는 효과를 나타내겠습니다.


Zoom with Curves

처음 캐릭터를 만들 때, CameraArmComponent 에 SocketOffset 을 설정했었습니다.
그렇기 때문에 ArmLength를 줄여도 어깨너머로 정면을 볼 수 있습니다.

우선 원만한 ZoomIn/Out을 위해 CurveFloat을 만들어주고, 이를 캐릭터에 넘겨줍니다.
Curve는 다음과 같이 사용할 수 있습니다.

/** Header File **/

protected:
	UPROPERTY(EditAnywhere, Category="Camera")
	UCurveFloat* CameraZoomCurve;

	FTimeline ZoomTimeline;

	UFUNCTION()
	void ControlArm();
   
	UFUNCTION(BlueprintCallable)
	void ZoomInCamera();

	UFUNCTION(BlueprintCallable)
	void ZoomOutCamera();

private:
	float TimelineValue;
	float CurveFloatValue;
	float PrevArmLength;

/** cpp File **/

void APlayerGunnerCharacter::BeginPlay()
{
	Super::BeginPlay();

	if (CameraZoomCurve) {

		FOnTimelineFloat TimelineCallback;
		FOnTimelineEvent TimelineFinishedCallback;

		TimelineCallback.BindUFunction(this, FName("ControlArm"));
		TimelineFinishedCallback.BindUFunction(this, FName("SetArm"));

		ZoomTimeline.AddInterpFloat(CameraZoomCurve, TimelineCallback);
		ZoomTimeline.SetTimelineFinishedFunc(TimelineFinishedCallback);
	}

	PrevArmLength = CameraBoom->TargetArmLength;
}

void APlayerGunnerCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	ZoomTimeline.TickTimeline(DeltaTime);
}

void APlayerGunnerCharacter::ControlArm()
{
	TimelineValue = ZoomTimeline.GetPlaybackPosition();
	CurveFloatValue = CameraZoomCurve->GetFloatValue(TimelineValue);

	CameraBoom->TargetArmLength = MinArmLength + CurveFloatValue * (MaxArmLength - MinArmLength);

	UE_LOG(LogTemp, Warning, TEXT("%f"), CurveFloatValue);
}

void APlayerGunnerCharacter::SetArm()
{
}

void APlayerGunnerCharacter::ZoomInCamera()
{
	PrevArmLength = CameraBoom->TargetArmLength;
	ZoomTimeline.ReverseFromEnd();
}

void APlayerGunnerCharacter::ZoomOutCamera()
{
	PrevArmLength = CameraBoom->TargetArmLength;
	ZoomTimeline.PlayFromStart();
}

BeginPlay 에서 콜백함수를 설정하고 해당 함수가 언제 실행될지 정합니다.
AddInterpFloat 에 들어간 TimelineCallback 에는 ControlArm 함수가 바인드 되었으므로, Float이 바뀔 때마다 ControlArm 이 호출되게 됩니다.

Aim과 비슷하게 Unaim, Fire, Reload GA도 간단하게 설정하고 실행해보겠습니다.

마무리


GA_Aim을 통해 여러 권한을 주고, 조준한 상태에서만 특정 어빌리티를 실행할 수 있도록 만들었습니다.
다음은 AttributeSet을 정의하고 간단한 적을 만들어 피가 닳도록 만들어보겠습니다.

0개의 댓글