일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- nanite
- gameplay effect
- stride
- UI
- 유니티
- gas
- 언리얼엔진
- listen server
- gameplay ability system
- Aegis
- 언리얼 엔진
- unity
- photon fusion2
- CTF
- local prediction
- gameplay tag
- 게임 개발
- os
- Multiplay
- Unreal Engine
- 보안
- ability task
- rpc
- MAC
- network object pooling
- animation
- 게임개발
- Replication
- map design
- attribute
- Today
- Total
Replicated
[Drag Down] Action 인풋 처리 본문
애니메이션이 끝나기 전에 어빌리티 end 처리해서 애니메이션 도중에 움직일 수 있게 됨
애니메이션 종료는 태그를 따로 만들어서 처리하자
정확히 말하면 Animation과 Trace나 dodge 이벤트를 분리하는 거다
PlayMontageAndWait 태스크를 쓰지 않아서 이렇게 해야 되는 거기도 하지만, 이렇게 관리하는게 더 유연성이 더 좋기도 하다
태그 추가
void UDDGA_ActionBase::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
bIsEventTriggered = false;
AnimEndTask = UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(
this,
DDTAG_EVENT_ANIMEND
);
AnimEndTask->EventReceived.AddDynamic(this, &UDDGA_ActionBase::OnAnimEnd);
AnimEndTask->ReadyForActivation();
}
액션 베이스 클래스의 ActivateAbility에서 WaitGameplayEvent에 등록해주고
void UDDGA_ActionBase::OnAnimEnd(FGameplayEventData Payload)
{
EnableInput();
bool bReplicatedEndAbility = true;
bool bWasCancelled = false;
EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, bReplicatedEndAbility, bWasCancelled);
}
애니메이션 종료 시 인풋을 Enable하도록 한다
void UDDGA_ActionBase::EnableInput()
{
if (AvatarCharacter)
{
AvatarCharacter->EnableCharacterInput();
}
}
void UDDGA_ActionBase::DisableInput()
{
if ( AvatarCharacter )
{
AvatarCharacter->DisableCharacterInput();
}
}
CharacterBase에서 Input 관련 함수를 만들어두고 해당 함수를 호출한다
void UDDGA_PushingCharacter::ActivateAbility(const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
const FGameplayEventData* TriggerEventData)
{
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
bIsEventTriggered = false;
if ( AvatarCharacter )
{
if (AvatarCharacter->GetCharacterMovement()->IsFalling())
{
if (ASC)
{
ASC->TryActivateAbilityByClass(UDDGA_JumpPushingCharacter::StaticClass());
}
bool bReplicatedEndAbility = true;
bool bWasCancelled = false;
EndAbility(Handle, ActorInfo, ActivationInfo, true, false);
return;
}
}
DisableInput();
그리고 세부 구현 클래스의 ActivateAbility에서 Diable 해준다
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "DDCharacterBase.generated.h"
UCLASS()
class DRAGDOWN_API ADDCharacterBase : public ACharacter
{
GENERATED_BODY()
public:
ADDCharacterBase();
UFUNCTION(NetMulticast, Reliable)
void NetMulticastPlayAnimMontage(UAnimMontage* Montage, FName SectionName);
void EnableCharacterInput();
void DisableCharacterInput();
protected:
TObjectPtr<class UDDAttackStateComponent> AttackStateComponent;
UFUNCTION(Client, Reliable)
void ClientEnableInput();
UFUNCTION(Client, Reliable)
void ClientDisableInput();
void HandleEnableInput();
void HandleDisableInput();
};
CharacterBase에선 Input을 RPC로 제어한다
이유는, RPC로 애니메이션을 제어하다보니 서버의 권위 실행이 클라이언트의 예측 실행보다 먼저 발생하고 클라이언트에선 발동을 안해버리는 경우가 있어서 Input이 다시 Enable되지 않는 경우도 있음
Disable은 잘 작동하긴 하는데, 일단 더 단단한 구조로 만들기 위해 RPC로 처리
void ADDCharacterBase::EnableCharacterInput()
{
HandleEnableInput();
if ( HasAuthority() )
{
ClientEnableInput();
}
}
void ADDCharacterBase::DisableCharacterInput()
{
HandleDisableInput();
if ( HasAuthority() )
{
ClientDisableInput();
}
}
void ADDCharacterBase::HandleEnableInput()
{
if (GetController() == nullptr) return;
APlayerController* PC = Cast<APlayerController>(GetController());
if (PC == nullptr) return;
PC->EnableInput(PC);
EnableInput(PC);
}
void ADDCharacterBase::HandleDisableInput()
{
if (GetController() == nullptr) return;
APlayerController* PC = Cast<APlayerController>(GetController());
if (PC == nullptr) return;
PC->DisableInput(PC);
DisableInput(PC);
}
void ADDCharacterBase::ClientEnableInput_Implementation()
{
if ( IsLocallyControlled() )
{
HandleEnableInput();
}
}
void ADDCharacterBase::ClientDisableInput_Implementation()
{
if (IsLocallyControlled())
{
HandleDisableInput();
}
}
서버가 실행되면 서버 캐릭터에 대해서 실행하고 클라이언트에 RPC를 날려주는 구조
동영상에선 확인이 안되는데 키 씹힘이 생겼다
두번은 눌러야 나간다
그냥 입력을 아예 안받는 대신 내부에서 처리하는 방법이 나을 듯..
그리고 이게 더 구조적으로 안전할 것 같다
CharacterBase에 변수 두고
액션에 조건 체크
void UDDGA_ActionBase::EnableInput()
{
if (AvatarCharacter)
{
AvatarCharacter->SetActionEnabled(true);
}
}
void UDDGA_ActionBase::DisableInput()
{
if ( AvatarCharacter )
{
AvatarCharacter->SetActionEnabled(false);
}
}
void ADDCharacterBase::ClientSetActionEnabled_Implementation(bool bInActionEnabled)
{
if ( IsLocallyControlled() )
{
bIsActionEnabled = bInActionEnabled;
}
}
void ADDCharacterBase::SetActionEnabled(bool bInActionEnabled)
{
bIsActionEnabled = bInActionEnabled;
if ( HasAuthority() )
{
ClientSetActionEnabled(bInActionEnabled);
}
}
액션 세팅은 RPC 처리
이제 문제 없이 작동하고, 카메라 회전은 예외로 처리해서 인풋을 받을 수 있는 더 유연한 구조이다
'언리얼 엔진 > Drag Down (캡스톤 디자인)' 카테고리의 다른 글
[Drag Down] 메뉴 만들기 #1 커스텀 UserSetting, 메뉴 토글 (0) | 2025.04.23 |
---|---|
[Drag Down] 앞으로 해야 하는 거 간단히 정리 (0) | 2025.04.20 |
[Drag Down] 미끄러지는 길 (Physical Material + Surface type + Data Asset) (0) | 2025.04.17 |
** [Drag Down] Performance Enhancement of Network Object Pooling ** (0) | 2025.04.16 |
** [Drag Down] Network Object Pooling (Subsystem + Interface + GameMode + DataAsset) ** (0) | 2025.04.16 |