언리얼 엔진/Drag Down
[Drag Down] Data-Dirven 설계
라구넹
2025. 4. 30. 17:35
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "DDCharacterPlayerData.generated.h"
USTRUCT(BlueprintType)
struct FDDCharacterPlayerDataEntry
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Movement")
FRotator RotationRate;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float JumpZVelocity;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float AirControl;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float MaxWalkSpeed;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float MinAnalogWalkSpeed;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float BrakingDecelerationWalking;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Camera")
float TargetArmLength;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Anim")
TSubclassOf<class UAnimInstance> AnimInstance;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Mesh")
TObjectPtr<class USkeletalMesh> Mesh;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Mesh")
FVector MeshLocation;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Mesh")
FRotator MeshRotation;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Capsule")
float CapsuleRadius;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Capsule")
float CapsuleHeight;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
TObjectPtr<class UInputMappingContext> MappingContext;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
TObjectPtr<class UInputAction> JumpAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
TObjectPtr<class UInputAction> ShoulderMoveAction;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
TObjectPtr<class UInputAction> ShoulderLookAction;
};
/**
*
*/
UCLASS()
class DRAGDOWN_API UDDCharacterPlayerData : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UDDCharacterPlayerData();
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FDDCharacterPlayerDataEntry CharacterPlayerData;
};
유지보수에 편하고, 협업에도 좋으니 데이터 기반으로 리팩토링했다
void ADDCharacterPlayer::SetInputData()
{
if (Data == nullptr) return;
MappingContext = Data->CharacterPlayerData.MappingContext;
JumpAction = Data->CharacterPlayerData.JumpAction;
ShoulderMoveAction = Data->CharacterPlayerData.ShoulderMoveAction;
ShoulderLookAction = Data->CharacterPlayerData.ShoulderLookAction;
}
void ADDCharacterPlayer::SetData()
{
if (Data == nullptr) return;
GetCharacterMovement()->RotationRate = Data->CharacterPlayerData.RotationRate;
GetCharacterMovement()->JumpZVelocity = Data->CharacterPlayerData.JumpZVelocity;
GetCharacterMovement()->AirControl = Data->CharacterPlayerData.AirControl;
GetCharacterMovement()->MaxWalkSpeed = Data->CharacterPlayerData.MaxWalkSpeed;
GetCharacterMovement()->MinAnalogWalkSpeed = Data->CharacterPlayerData.MinAnalogWalkSpeed;
GetCharacterMovement()->BrakingDecelerationWalking = Data->CharacterPlayerData.BrakingDecelerationWalking;
GetCapsuleComponent()->SetCapsuleSize(Data->CharacterPlayerData.CapsuleRadius, Data->CharacterPlayerData.CapsuleHeight);
GetMesh()->SetSkeletalMesh(Data->CharacterPlayerData.Mesh);
GetMesh()->SetAnimInstanceClass(Data->CharacterPlayerData.AnimInstance);
GetMesh()->SetRelativeLocation(Data->CharacterPlayerData.MeshLocation);
GetMesh()->SetRelativeRotation(Data->CharacterPlayerData.MeshRotation);
UE_LOG(LogDD, Log, TEXT("[NetMode: %d] SetData - Mesh Z Pos : %f"), GetWorld()->GetNetMode(), GetMesh()->GetRelativeLocation().Z);
}
데이터 세팅은 인풋은 따로 해줘야 한다
void ADDCharacterPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
UE_LOG(LogDD, Log, TEXT("SetupPlayerInputComponent"));
SetInputData();
APlayerController* PlayerController = CastChecked<APlayerController>(GetController());
if (UEnhancedInputLocalPlayerSubsystem* InputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
InputSubsystem->AddMappingContext(MappingContext, 0);
}
UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent);
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Triggered, this, &ADDCharacterPlayer::Jump);
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
EnhancedInputComponent->BindAction(ShoulderMoveAction, ETriggerEvent::Triggered, this, &ADDCharacterPlayer::ShoulderMove);
EnhancedInputComponent->BindAction(ShoulderLookAction, ETriggerEvent::Triggered, this, &ADDCharacterPlayer::ShoulderLook);
GASManagerComponent->SetupGASInputComponent();
}
인풋 입력을 받기 전에 초기화해줘야 하는 값들이 있고
void ADDCharacterPlayer::PreInitializeComponents()
{
Super::PreInitializeComponents();
if (Data)
{
// ENetowkSmoothingMode 때문에 Mesh Location, Rotation이 덮어써지는 문제가 있음
// PreInitializeComponents에서 설정하면 Default Location, Rotation이 해당 값으로 설정됨
SetData();
}
}
런타임에 Mesh Position 설정하기 위해 PreInitializeComponents에서 작업해야 하는 것도 있다
그밖에, 어빌리티도 데이터 기반으로 분리했다