오늘의 코드카타
- 아방가르드 타일링
- 특정한 모양의 타일이 있을 때, 이를 배치하는 경우의 수를 찾는 문제
- 가로 길이를 x라고 했을 때, x일 때 새로 나올 수 있는 경우의 수를 세고, 그 이전의 값들을 통해 경우의 수를 계산하는 문제
- 중복되는 경우의 수로 인해 예를 들어
f(4)를 구할 때, (x=1일 때의 새로운 경우의 수)*(x=3일 때의 모든 경우의 수)와 같은 방식으로 문제를 해결해야함
- x가 7일 때까지는 직접 그려보면서 새로 나올 수 있는 경우의 수를 확인해야 하고, 점화식도 매우 복잡함. 반면 구현은 매우 쉬움. 수학적으로 경우의 수를 찾는 문제.
- https://school.programmers.co.kr/learn/courses/30/lessons/181186
팀 프로젝트 진행 내용
1. 리팩토링
- 사용하지 않는 데미지 및 파쿠르 컴포넌트 코드를 삭제
- 코딩 컨벤션에 맞춰서
continue 구문에도 중괄호를 추가했고, if(!Statement)return; 부분을 check()로 변환을 했다.
- 주의할 점으로
AnimInstance 부분에서 NativeThreadSafeUpdateAnimation() 함수에서 Proxy.Owner, Proxy.Character, Proxy.Movement에 대해 유효성 검사를 실시하는데, 프록시를 기반으로 동작하기 때문에 에디터를 키게 되면 null 값을 반환하게 된다. 로딩 과정에서도 null 값을 반환할 수 있기 때문에 해당 부분은 assertion으로 처리하면 안 된다.
- 또한 노티파이의 경우에는
World가 에디터인 상황에서는 넘어가는 코드를 추가해줘야 한다.
2. 캐릭터에 속도 속성 추가
- 캐릭터가 3개의 상태로 이동속도가 관리되기 때문에 각 속도를 Attribute Set에 추가했다.
- 이 Attribute Set의 속성을 통해서 패시브 아이템으로 속도를 증가시키거나 할 예정이다.
// AO_PlayerCharacter_AttributeSet.h
UCLASS()
class AO_API UAO_PlayerCharacter_AttributeSet : public UAttributeSet
{
GENERATED_BODY()
...
// 걷기(Walk) 이동속도
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_WalkSpeed, Category = "Speed|Walk")
FGameplayAttributeData WalkSpeed;
ATTRIBUTE_ACCESSORS_BASIC(UAO_PlayerCharacter_AttributeSet, WalkSpeed)
// 뛰기(Run) 이동속도
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_RunSpeed, Category = "Speed|Run")
FGameplayAttributeData RunSpeed;
ATTRIBUTE_ACCESSORS_BASIC(UAO_PlayerCharacter_AttributeSet, RunSpeed)
// 스프린트(Sprint) 이동속도
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_SprintSpeed, Category = "Speed|Sprint")
FGameplayAttributeData SprintSpeed;
ATTRIBUTE_ACCESSORS_BASIC(UAO_PlayerCharacter_AttributeSet, SprintSpeed)
}
- 캐릭터에서 이동 속도 관련된 속성이 변경되면 캐릭터의 이동속도를 변경시켜야 하기 때문에 해당 속성이 변경될 때의 델리게이트를 연결했다.
- 기존의 이동 속도를 변경하는 코드를 추가해서 실시간으로 변경할 수 있게끔 코드를 구현했다.
// AAO_PlayerCharacter.cpp
void AAO_PlayerCharacter::BindSpeedAttributeDelegates()
{
checkf(AttributeSet, TEXT("AttributeSet is null"));
// 이동속도 변경 시 발생할 델리게이트 연결
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeSet->GetWalkSpeedAttribute())
.AddUObject(this, &AAO_PlayerCharacter::OnSpeedChanged);
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeSet->GetRunSpeedAttribute())
.AddUObject(this, &AAO_PlayerCharacter::OnSpeedChanged);
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AttributeSet->GetSprintSpeedAttribute())
.AddUObject(this, &AAO_PlayerCharacter::OnSpeedChanged);
}
void AAO_PlayerCharacter::OnSpeedChanged(const FOnAttributeChangeData& Data)
{
SetCurrentGait();
if (!HasAuthority())
{
ServerRPC_SetInputState(CharacterInputState.bWantsToSprint, CharacterInputState.bWantsToWalk);
}
}
void AAO_PlayerCharacter::OnRep_Gait()
{
switch (Gait)
{
case EGait::Walk:
GetCharacterMovement()->MaxWalkSpeed = AttributeSet->GetWalkSpeed();
break;
case EGait::Run:
GetCharacterMovement()->MaxWalkSpeed = AttributeSet->GetRunSpeed();
break;
case EGait::Sprint:
GetCharacterMovement()->MaxWalkSpeed = AttributeSet->GetSprintSpeed();
break;
}
}
3. Attribute Set 초기화 부분 데이터 에셋으로 수정
- 이후에 레벨 디자인 시에 캐릭터의 속성의 초기 값을 지정하는 것을 코드에서 직접 하는 것은 번거로울 것으로 느껴져 별도의 데이터 에셋 파일을 두고 수정하는 방식으로 변경하고자 했다.
- 먼저 초기 값을 가지고 있을 데이터 에셋 클래스를 선언해서 초기값을 할당했다.
// UAO_PlayerCharacter_AttributeDefaults.h
UCLASS()
class AO_API UAO_PlayerCharacter_AttributeDefaults : public UDataAsset
{
GENERATED_BODY()
public:
// 체력
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Health")
float Health = 100.0f;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Health")
float MaxHealth = 100.0f;
// 스태미나
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Stamina")
float Stamina = 100.0f;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Stamina")
float MaxStamina = 100.0f;
// 이동속도
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Speed")
float WalkSpeed = 200.0f;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Speed")
float RunSpeed = 500.0f;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Speed")
float SprintSpeed = 800.0f;
};
- 캐릭터에서 해당 데이터 에셋을 받아서 속성을 초기화하는 코드를
PossessedBy()에서 ASC를 초기화한 이후에 추가했다.
// AAO_PlayerCharacter.h
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "PlayerCharacter|GAS")
TObjectPtr<UAO_PlayerCharacter_AttributeDefaults> AttributeDefaults;
// AAO_PlayerCharacter.cpp
void AAO_PlayerCharacter::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
AbilitySystemComponent->InitAbilityActorInfo(this, this);
if (HasAuthority())
{
InitializeAttributes();
...
}
}
void AAO_PlayerCharacter::InitializeAttributes()
{
if (!HasAuthority())
{
return;
}
AttributeSet->InitHealth(AttributeDefaults->Health);
AttributeSet->InitMaxHealth(AttributeDefaults->MaxHealth);
AttributeSet->InitStamina(AttributeDefaults->Stamina);
AttributeSet->InitMaxStamina(AttributeDefaults->MaxStamina);
AttributeSet->InitWalkSpeed(AttributeDefaults->WalkSpeed);
AttributeSet->InitRunSpeed(AttributeDefaults->RunSpeed);
AttributeSet->InitSprintSpeed(AttributeDefaults->SprintSpeed);
}