글의 요약 설명 부분. 150자를 적어주세요. 글의 요약 설명 부분. 150자를 적어주세요. 글의 요약 설명 부분. 150자를 적어
콤보 공격
지난 포스팅에 이어 GAS를 통한 캐릭터 입력을 처리하는 부분에서 콤보 공격까지 가능하게 구현하는 것이 이번 목표이다.
이전과 크게 다르지 않다.
InputPressed가 있을 때, 시간 내에 들어온 입력인지 확인하기만 하면 된다.
동작 원리는 다음과 같다.
- AT가 Activate될 때 콤보를 체크할 타이머를 발동시킨다.
- InputPressed가 실행되면 콤보타이머가 유효하다면 콤보 여부를 true로 설정한다.
- 타이머가 발동되면 콤보 입력이 들어왔는지를 체크한다.
- 입력이 들어왔다면 타이머를 다시 발동하고 그렇지 않다면 해제하고 종료한다.
콤보 애니메이션
콤보 공격을 위해서는 콤보 공격을 하는 애니메이션이 필요한다.
보통 AnimMontage를 이용하여 Section을 통해 구현한다.
Section을 통해 애니메이션을 실행하기 위해서는 이름이 필요하다.
또한, 공격마다 콤보 입력이 유효한 시간이 다르기 때문에 이를 모두 관리하는 데이터 클래스를 만들면 편리하다.
UCLASS()
class ARENABATTLE_API UABComboActionData : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UABComboActionData();
UPROPERTY(EditAnywhere, Category = Name)
FString MontageSectionNamePrefix;
UPROPERTY(EditAnywhere, Category = Name)
uint8 MaxComboCount;
UPROPERTY(EditAnywhere, Category = Name)
float FrameRate;
UPROPERTY(EditAnywhere, Category = ComboData)
TArray<float> EffectiveFrameCount;
};
이러한 데이터가 이미 캐릭터에 설정되어 있다는 가정하에 진행하겠다.
우선, Ability가 실행되면 처음 애니메이션을 실행하며 타이머를 발동한다.
타이머가 유효할 때, InputPressed가 발동되면 콤보 공격 여부를 true로 변경한다.
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.f, GetNextSection());
PlayAttackTask->OnCompleted.AddDynamic(this, &UABGA_Attack::OnCompleteCallback);
PlayAttackTask->OnCancelled.AddDynamic(this, &UABGA_Attack::OnCancelCallback);
PlayAttackTask->ReadyForActivation();
StartComboTimer();
}
void UABGA_Attack::InputPressed(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo)
{
if (!ComboTimerHandle.IsValid())
{
HasNextComboInput = false;
}
else
{
HasNextComboInput = true;
}
}
이때, AT를 이용하는 것은 이전과 똑같다.
타이머는 다음과 같이 설정한다.
void UABGA_Attack::StartComboTimer()
{
int32 ComboIdx = CurrentCombo - 1;
ensure(CurrentComboData->EffectiveFrameCount.IsValidIndex(ComboIdx));
const float ComboEffectiveTime = CurrentComboData->EffectiveFrameCount[ComboIdx] / CurrentComboData->FrameRate;
if (ComboEffectiveTime > 0.f)
{
GetWorld()->GetTimerManager().SetTimer(ComboTimerHandle, this, &UABGA_Attack::CheckComboInput, ComboEffectiveTime, false);
}
}
void UABGA_Attack::CheckComboInput()
{
ComboTimerHandle.Invalidate();
if (HasNextComboInput)
{
MontageJumpToSection(GetNextSection());
StartComboTimer();
HasNextComboInput = false;
}
}
타이머가 발동하여 CheckComboInput이 실행되면 InputPressed로 설정된 HasNextComboInput을 확인하여 타이머를 반복할지 종료할지를 결정한다.