[UE GAS] 캐릭터의 콤보 공격의 구현 Implementing Combo Action, 상태를가지는 점프 어빌리티의 구현하기
입력에 따라서 콤보 공격과 상태를 가진 점프 어빌리티를 구현해보자.
- 게임플레이 어빌리티를 활용한 콤보 공격의 구현
- 게임플레이 어빌리티와 어빌리티 태스크 동작의 이해
- 블루프린트에서 활용가능한 어빌리티 태스크 설정 방법의 학습
목차
콤보 공격의 구현하기
Gameplay Ability(GA)에서 콤보 공격을 구현
캐릭터 콤보 공격 구현을 위한 기획
- 공격시작 후 유효 시간 내에 추가 공격 입력을 넣으면, 다음 공격 모션을 발동한다.
- 콤보 공격에 대한 정보는 ABComboActionData에서 불러들임.
- AbilityTask(AT)를 발동하고 입력 점검 타이머도 함께 발동.
- 입력점검 타이머가 발동되면 다음 공격 입력이 있는지 검사함.
- 다음 공격 입력이 있으면다음 공격 모션을 발동하고다시 입력 점검 타이머를 발동.
노란색 부분을 작업하였다. 주어진 어빌리티 태스크(AT)를 사용하는것이 아니라 직접 어빌리티 태스크(AT)를 만들어서 구현하였다.
노란색 부분을 작업하였다.
ABGA_Attack 클래스
ABGA_Attack.h
더보기
#pragma once
#include "CoreMinimal.h"
#include "Abilities/GameplayAbility.h"
#include "ABGA_Attack.generated.h"
UCLASS()
class ARENABATTLEGAS_API UABGA_Attack : public UGameplayAbility
{
GENERATED_BODY()
public:
UABGA_Attack();
public:
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
virtual void InputPressed(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) override;
virtual void CancelAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateCancelAbility) override;
virtual void EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled) override;
protected:
UFUNCTION()
void OnCompleteCallback();
UFUNCTION()
void OnInterruptedCallback();
FName GetNextSection();
void StartComboTimer();
void CheckComboInput();
protected:
UPROPERTY()
TObjectPtr<class UABComboActionData> CurrentComboData;
uint8 CurrentCombo = 0;
FTimerHandle ComboTimerHandle;
bool HasNextComboInput = false;
};
ABGA_Attack.cpp
더보기
#include "GA/ABGA_Attack.h"
#include "Character/ABCharacterBase.h"
#include "Abilities/Tasks/AbilityTask_PlayMontageAndWait.h"
#include "ArenaBattleGAS.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Character/ABComboActionData.h"
UABGA_Attack::UABGA_Attack()
{
InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;
}
void UABGA_Attack::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
AABCharacterBase* ABCharacter = CastChecked<AABCharacterBase>(ActorInfo->AvatarActor.Get());
CurrentComboData = ABCharacter->GetComboActionData();
ABCharacter->GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_None);
UAbilityTask_PlayMontageAndWait* PlayAttackTask = UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(this, TEXT("PlayAttack"), ABCharacter->GetComboActionMontage(), 1.0f, GetNextSection());
PlayAttackTask->OnCompleted.AddDynamic(this, &UABGA_Attack::OnCompleteCallback);
PlayAttackTask->OnInterrupted.AddDynamic(this, &UABGA_Attack::OnInterruptedCallback);
PlayAttackTask->ReadyForActivation();
StartComboTimer();
}
void UABGA_Attack::InputPressed(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo)
{
if (!ComboTimerHandle.IsValid()) // 마지막 공격인 경우
{
HasNextComboInput = false; // 콤보 공격이 이어지지 않도록 false 설정
}
else // 마지막 공격이 아닌 경우
{
HasNextComboInput = true; // 다음 몽타주 색션이 재생되도록 true 설정
}
}
void UABGA_Attack::CancelAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateCancelAbility)
{
Super::CancelAbility(Handle, ActorInfo, ActivationInfo, bReplicateCancelAbility);
}
void UABGA_Attack::EndAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, bool bReplicateEndAbility, bool bWasCancelled)
{
Super::EndAbility(Handle, ActorInfo, ActivationInfo, bReplicateEndAbility, bWasCancelled);
AABCharacterBase* ABCharacter = CastChecked<AABCharacterBase>(ActorInfo->AvatarActor.Get());
ABCharacter->GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_Walking);
//** 콤보 초기화
CurrentComboData = nullptr;
CurrentCombo = 0;
HasNextComboInput = false;
}
void UABGA_Attack::OnCompleteCallback()
{
bool bReplicatedEndAbility = true;
bool bWasCancelled = false;
EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, bReplicatedEndAbility, bWasCancelled);
}
void UABGA_Attack::OnInterruptedCallback()
{
bool bReplicatedEndAbility = true;
bool bWasCancelled = true;
EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, bReplicatedEndAbility, bWasCancelled);
}
FName UABGA_Attack::GetNextSection()
{
CurrentCombo = FMath::Clamp(CurrentCombo + 1, 1, CurrentComboData->MaxComboCount);
FName NextSection = *FString::Printf(TEXT("%s%d"), *CurrentComboData->MontageSectionNamePrefix, CurrentCombo);
return NextSection;
}
void UABGA_Attack::StartComboTimer() // 콤보 타이머
{
int32 ComboIndex = CurrentCombo - 1;
ensure(CurrentComboData->EffectiveFrameCount.IsValidIndex(ComboIndex));
const float ComboEffectiveTime = CurrentComboData->EffectiveFrameCount[ComboIndex] / CurrentComboData->FrameRate; // 몇 초 이후에 점검할지 변수
if (ComboEffectiveTime > 0.0f)
{
// 타이머
GetWorld()->GetTimerManager().SetTimer(ComboTimerHandle, this, &UABGA_Attack::CheckComboInput, ComboEffectiveTime, false);
}
}
void UABGA_Attack::CheckComboInput()
{
ComboTimerHandle.Invalidate(); // 타이머 핸들 무력화
if (HasNextComboInput) // 다음 공격 입력이 있다면
{
MontageJumpToSection(GetNextSection()); // 다음 몽타주 색션으로 넘어감
StartComboTimer(); // 콤보 타이머 새로 시작
HasNextComboInput = false;
}
}
실행화면
상태를가지는 점프 어빌리티의 구현하기
상태를 가지는 점프 GA 생성
점프 GA를 위한 새로운 AT의 생성
GA와 AT 사이의 통신 매커니즘 이해하기
블루프린트에서 AT를 사용하기 위한 매크로 설정
어빌리티 태스크 Ability Task(AT)의 제작 규칙
- AT는 UAbilityTask 클래스를 상속받아 제작한다.
- AT 인스턴스를 생성해 반환하는 static 함수를 선언해 구현한다. (= 즉, AT 안에 자기 자신의 인스턴스를 생성해서 반환하는 static 함수를 선언하여 구현한다)
- AT가 종료되면 이것을 호출한 GA에 알려줄 델리게이트를 선언한다.
- 시작과 종료 처리를 위해 Activate와 OnDestroy 함수를 재정의(Override)해 구현한다.
- 일정 시간이 지난 후 AT를 종료하고자 한다면, 활성화 시 SetWaitingOnAvatar 함수를 호출해 Waiting 상태로 설정한다.
- 만일 Tick을 활성화하고 싶다면 bTickingTask 값을 true로 설정한다.
- AT가 종료되면 델리게이트를 브로드캐스팅한다.
GA와 AT 사이의 실행 흐름
블루프린트에서 호출을 위한 제작 규칙
- static 함수에 UFUNCTION(BlueprintCallable)을 지정한다.
- 콜백을 위한 델리게이트는 Dynamic Delegate로 선언한다.
- AT의 델리게이트에 UPROPERTY(BlueprintAssignable)을 지정한다.
Visual Studio에서 찾아본 Gameplay Abilities
ABGA_Jump 생성
GameplayAbility - ABGA_Jump 생성
ABGA_Jump.h
더보기
#pragma once
#include "CoreMinimal.h"
#include "Abilities/GameplayAbility.h"
#include "ABGA_Jump.generated.h"
UCLASS()
class ARENABATTLEGAS_API UABGA_Jump : public UGameplayAbility
{
GENERATED_BODY()
public:
UABGA_Jump();
virtual bool CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags = nullptr, const FGameplayTagContainer* TargetTags = nullptr, OUT FGameplayTagContainer* OptionalRelevantTags = nullptr) const override;
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
virtual void InputReleased(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) override;
protected:
UFUNCTION() // Dynamic이므로 UFUNCTION 매크로 붙임
void OnLandedCallback();
};
ABGA_Jump.cpp
더보기
#include "GA/ABGA_Jump.h"
#include "GameFramework/Character.h"
#include "GA/AT/ABAT_JumpAndWaitForLanding.h"
UABGA_Jump::UABGA_Jump()
{
InstancingPolicy = EGameplayAbilityInstancingPolicy::InstancedPerActor;
}
bool UABGA_Jump::CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, OUT FGameplayTagContainer* OptionalRelevantTags) const
{
bool bResult = Super::CanActivateAbility(Handle, ActorInfo, SourceTags, TargetTags, OptionalRelevantTags);
if (!bResult)
{
return false;
}
const ACharacter* Character = Cast<ACharacter>(ActorInfo->AvatarActor.Get());
return (Character && Character->CanJump());
}
void UABGA_Jump::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
// 아래의 3줄의 코드처럼 콜백함수를 만들지않고 Blueprint로 구현하는 방법도 있다.
// 코드 아래에 첨부된 이미지처럼 Blueprint를 만들면 된다.
UABAT_JumpAndWaitForLanding* JumpAndWaitingForLandingTask = UABAT_JumpAndWaitForLanding::CreateTask(this);
JumpAndWaitingForLandingTask->OnComplete.AddDynamic(this, &UABGA_Jump::OnLandedCallback);
JumpAndWaitingForLandingTask->ReadyForActivation();
}
void UABGA_Jump::InputReleased(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo)
{
ACharacter* Character = CastChecked<ACharacter>(ActorInfo->AvatarActor.Get());
Character->StopJumping();
}
void UABGA_Jump::OnLandedCallback()
{
bool bReplicatedEndAbility = true;
bool bWasCancelled = false;
EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, bReplicatedEndAbility, bWasCancelled); // 어빌리티 종료
}
C++ 코드 대신 Blueprint를 사용하는 경우 아래와 같이 구현하면 된다.
BPGA_Jump
ABAT_JumpAndWaitForLanding 생성
점프를 수행해주고 땅에 떨어질 때까지 점프 상태를 유지해주는 어빌리티 테스크
AbilityTask - ABAT_JumpAndWaitForLanding 생성
ABAT_JumpAndWaitForLanding.h
더보기
#pragma once
#include "CoreMinimal.h"
#include "Abilities/Tasks/AbilityTask.h"
#include "ABAT_JumpAndWaitForLanding.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FJumpAndWaitForLandingDelegate);
UCLASS()
class ARENABATTLEGAS_API UABAT_JumpAndWaitForLanding : public UAbilityTask
{
GENERATED_BODY()
public:
UABAT_JumpAndWaitForLanding();
UFUNCTION(BlueprintCallable, Category = "Ability|Tasks", meta = (DisplayName = "JumpAndWaitForLanding", HidePin = "OwningAbility", DefaultToSelf = "OwningAbility", BlueprintInternalUseOnly = "TRUE"))
static UABAT_JumpAndWaitForLanding* CreateTask(UGameplayAbility* OwningAbility);
virtual void Activate() override;
virtual void OnDestroy(bool AbilityEnded) override;
UPROPERTY(BlueprintAssignable)
FJumpAndWaitForLandingDelegate OnComplete;
protected:
UFUNCTION() // Dynamic 콜백함수이기 때문에 UFUNCTION 매크로를 붙임
void OnLandedCallback(const FHitResult& Hit);
};
ABAT_JumpAndWaitForLanding.cpp
더보기
#include "GA/AT/ABAT_JumpAndWaitForLanding.h"
#include "GameFramework/Character.h"
UABAT_JumpAndWaitForLanding::UABAT_JumpAndWaitForLanding()
{
}
UABAT_JumpAndWaitForLanding* UABAT_JumpAndWaitForLanding::CreateTask(UGameplayAbility* OwningAbility)
{
UABAT_JumpAndWaitForLanding* NewTask = NewAbilityTask<UABAT_JumpAndWaitForLanding>(OwningAbility); // UABAT_JumpAndWaitForLanding라는 API 사용
return NewTask;
}
void UABAT_JumpAndWaitForLanding::Activate()
{
Super::Activate();
ACharacter* Character = CastChecked<ACharacter>(GetAvatarActor());
Character->LandedDelegate.AddDynamic(this, &UABAT_JumpAndWaitForLanding::OnLandedCallback); // 바닥에 착지하는 순간 델리게이트 OnLandedCallback콜백함수 호출되도록 AddDynamic등록
Character->Jump(); // 점프
//** 점프 후에 Waiting상태로 돌려줌
SetWaitingOnAvatar(); // EAbilityTaskWaitState::WaitingOnAvatar로 설정
}
void UABAT_JumpAndWaitForLanding::OnDestroy(bool AbilityEnded)
{
ACharacter* Character = CastChecked<ACharacter>(GetAvatarActor());
Character->LandedDelegate.RemoveDynamic(this, &UABAT_JumpAndWaitForLanding::OnLandedCallback); // 등록된 Dynamic 델리게이트 OnLandedCallback콜백함수 해제
Super::OnDestroy(AbilityEnded);
}
void UABAT_JumpAndWaitForLanding::OnLandedCallback(const FHitResult& Hit)
{
if (ShouldBroadcastAbilityTaskDelegates())
{
OnComplete.Broadcast(); // 델리게이트 브로드캐스트
}
}
BP_ABGASCharacterPlayer
실행화면
'⭐ Unreal Engine > UE Game Ability System(GAS)' 카테고리의 다른 글
[UE GAS] 캐릭터 어트리뷰트 설정 (0) | 2024.03.07 |
---|---|
[UE GAS] 공격 판정 시스템의 구현 (0) | 2024.03.06 |
[UE GAS] 캐릭터 입력처리 (0) | 2024.03.05 |
[UE GAS] 어빌리티시스템 컴포넌트 AbilitySystemComponent, 게임플레이 태그 Gameplay Tag (0) | 2024.03.03 |
[UE GAS] 어빌리티 시스템 (Game Ability System) (0) | 2024.03.03 |
댓글
이 글 공유하기
다른 글
-
[UE GAS] 캐릭터 어트리뷰트 설정
[UE GAS] 캐릭터 어트리뷰트 설정
2024.03.07 -
[UE GAS] 공격 판정 시스템의 구현
[UE GAS] 공격 판정 시스템의 구현
2024.03.06 -
[UE GAS] 캐릭터 입력처리
[UE GAS] 캐릭터 입력처리
2024.03.05 -
[UE GAS] 어빌리티시스템 컴포넌트 AbilitySystemComponent, 게임플레이 태그 Gameplay Tag
[UE GAS] 어빌리티시스템 컴포넌트 AbilitySystemComponent, 게임플레이 태그 Gameplay Tag
2024.03.03