SetVisibility(ESlateVisibility InVisibility) : 현재 위젯의 상태를 변경할 때
GetVisibility() : 현재 위젯의 상태를 확인할 때 (Return ESlateVisibility Visibility)
위젯 애니메이션 블렌딩의 경우
마우스 입력 또는 키보드 입력값을 받을 수 있는지에 대한 여부 결정시
ESlateVisibility - SlateWrapperTypes.h
/** Is an entity visible? */
UENUM(BlueprintType)
enum class ESlateVisibility : uint8
{
/** Visible and hit-testable (can interact with cursor). Default value. */
Visible,
/** Not visible and takes up no space in the layout (obviously not hit-testable). */
Collapsed,
/** Not visible but occupies layout space (obviously not hit-testable). */
Hidden,
/** Visible but not hit-testable (cannot interact with cursor) and children in the hierarchy (if any) are also not hit-testable. */
HitTestInvisible UMETA(DisplayName = "Not Hit-Testable (Self & All Children)"),
/** Visible but not hit-testable (cannot interact with cursor) and doesn't affect hit-testing on children (if any). */
SelfHitTestInvisible UMETA(DisplayName = "Not Hit-Testable (Self Only)")
};
Visible
SetVisibility 설정하지 않을 경우의 기본값
화면에 출력되며 마우스 클릭 및 터치 등의 인터렉션이 가능하다.
일반적으로 위젯이 열려있으며, 버튼, 텍스트 등의 인터렉션이 필요하 경우 (우편함, 로비 플레이 버튼 등)
개인 프로젝트를 진행하던 중 애니메이션 구조에 대해서 확장적인 설계에 대해 고민하게 되었으며
UE5 프레임워크의 이해를 돕기 위한 샘플 게임 프로젝트로 설계된 학습 리소스 "Lyra Starter Game"의 구조를 학습하며
이를 기반으로 애니메이션을 설계 및 리팩토링을 하고자 합니다.
이번 포스팅에서는 개인 프로젝트의 확장적 구조 설계 및 오버헤드 관련 최적화와 관련되어 학습한 Lyra 프로젝트 내 애니메이션에 대해 알아보겠습니다.
※ Lyra는 GAS(GameAbilitySystem)를 사용하여 설계되어있으며, 진행중인 프로젝트에서는 GAS를 사용하지 않습니다. 이로인해 GAS 관련된 학습 내용은 해당 포스팅에서 최소한의 부분만 작성하였습니다.
Lyra Animation 구조
ABP_Mannequin_Base
ABP_Mannequin_Base
C++ 클래스 LyraAnimInstance를 기반으로 생성된 애니메이션 블루프린트입니다.
LyraAnimInstance.h
UCLASS(Config = Game)
class ULyraAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
ULyraAnimInstance(const FObjectInitializer& ObjectInitializer);
virtual void InitializeWithAbilitySystem(UAbilitySystemComponent* ASC);
protected:
#if WITH_EDITOR
virtual EDataValidationResult IsDataValid(class FDataValidationContext& Context) const override;
#endif // WITH_EDITOR
virtual void NativeInitializeAnimation() override;
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
protected:
// Gameplay tags that can be mapped to blueprint variables. The variables will automatically update as the tags are added or removed.
// These should be used instead of manually querying for the gameplay tags.
UPROPERTY(EditDefaultsOnly, Category = "GameplayTags")
FGameplayTagBlueprintPropertyMap GameplayTagPropertyMap;
UPROPERTY(BlueprintReadOnly, Category = "Character State Data")
float GroundDistance = -1.0f;
};
FDataValidationContext
데이터 검증을 위한 구조체
#if WITH_EDITOR를 사용하여 에디터 레벨에서만 컴파일되게 제한, 유효성검사를 하여 런타임 내 최적화
데이터 검증에 따른 결과를 EDataValidationResult를 사용하여 반환한다. (Data Validation Plugin / UObjectGlobal.h)
FGameplayTagBlueprintPropertyMap
GAS와 애니메이션 그래프간 프로퍼티들을 연결하기위한 구조체
EWeaponBlendType을 사용한 블렌드 포즈와 같은 프로퍼티들을 관리한다.
애니메이션의 변화를 위한 값들을 저장하고 있다.
Ex)Event .Movement.ADS - GameplayTag_IsADS를 매핑하여 프로퍼티 업데이트
PlayerController BeginPlay내에서 난수를 생성하는 경우, Server, Local의 난수값이 서로 다르다.
RPC (Client)에서 InputValue가 Server와 비교하고 싶은 경우
RPC(Server)에서 Client 호출시 해당 정보를 같이 전송해야한다.
현재 구조는 FString 하나의 데이터만을 전송하지만, FCharacterMoveData와 같은 구조체 전송의 경우 불필요한 대역폭 소모
RPC (Client)에서 InputValue Client와 비교하는 경우
Client (!HasAuthority())의 경우 값을 수정할 수 없음
데이터 변경의 경우 서버에서만 실행된다.
데이터를 변경해야 하는 경우 복제된 컨트롤러 내 값을 사용하면 일관성이 유지되지 않는다.
해당 문제들은 데이터 변경시 RPC(Server) 이벤트 호출하여 실행 할 수 있다. 하지만, 난수값과 같은 경우 Set이 아니라면 일관성을 유지하지 않는다.
Replicated를 사용한 리팩토링
Replicated를 사용한 데이터만으로 난수 비교 가능
UPROPERTY(ReplicatedUsing = OnRep_PlayerNumbers)
FString RandValue;
AChatPlayerState::AChatPlayerState()
{
// PlayerState 클래스의 경우 기본적으로 RPC와같은 네트워크 지원
bReplicates = true;
}
void AChatPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
// Replicated한 데이터를 네트워크 복제하라는 명령 매크로
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AChatPlayerState, RandValue);
}