[25.08.05] :: 가디언 앤 시커 프로젝트 23

chooha·2025년 8월 5일

가디언앤시커

목록 보기
23/25

📝 개발일지 - 룬 시스템 프리셋 기능 구현 (1)

👨💻 오늘의 개발 작업

오늘은 룬 시스템에 프리셋 기능을 추가하기 위한 기초 작업을 완료했음

기존에는 직업별로 하나의 룬 배치만 저장할 수 있었는데, 사용자들이 여러 개의 빌드를 저장하고 전환하고 싶다는 요청이 많아서 프리셋 시스템을 도입하기로 결정

이번 단계에서는 데이터 구조 변경과 저장/로드 로직을 새로운 프리셋 구조에 맞게 전면 개편했음


💡 오늘의 5분 기록

1. 기존 데이터 구조의 한계점 파악

기존 방식의 문제:

  • 직업별로 룬 배치 하나만 저장 가능
  • 다양한 빌드를 테스트하려면 매번 룬을 다시 배치해야 함
  • 상황에 맞는 빌드 전환이 불가능

기존 데이터 구조

// 삭제된 구조체
USTRUCT(BlueprintType)
struct FRunePlacementData
{
    GENERATED_BODY()
    
    UPROPERTY()
    TArray<FPlacedRuneInfo> PlacedRunes;
};

// SaveGame에서 사용
TMap<ECharacterClass, FRunePlacementData> SavedRunesByClass;

2. 새로운 프리셋 데이터 구조 설계

핵심 아이디어: "각 직업마다 3개의 프리셋 슬롯 제공"

새로운 구조체로 프리셋 시스템 구현:

USTRUCT(Atomic, BlueprintType)
struct FArcaneBoardPresets
{
    GENERATED_BODY()

    UPROPERTY()
    TArray<FPlacedRuneInfo> Preset1;
    
    UPROPERTY()
    TArray<FPlacedRuneInfo> Preset2;
    
    UPROPERTY()
    TArray<FPlacedRuneInfo> Preset3;
    
    UPROPERTY()
    int32 LastUsedPresetIndex;

    FArcaneBoardPresets()
    {
        LastUsedPresetIndex = 1; // 기본값은 프리셋 1
    }
};

SaveGame 구조 변경

// GS_ArcaneBoardSaveGame.h에서
TMap<ECharacterClass, FArcaneBoardPresets> SavedRunesByClass; // 구조 변경

3. LPS 헤더 파일 확장

기존 함수 시그니처 변경

// 기존
void SaveBoardConfig();
void LoadBoardConfig();

// 새로운 - 프리셋 인덱스 매개변수 추가
void SaveBoardConfig(int32 PresetIndex = -1); // -1은 현재 프리셋에 저장
void LoadBoardConfig(int32 PresetIndex = -1); // -1은 최근 사용 프리셋 로드

새로운 프리셋 관련 함수들 추가

// UI에서 필요한 최소한의 함수들만 추가
bool IsPresetEmpty(int32 PresetIndex) const;
int32 GetCurrentPresetIndex() const;

// 현재 프리셋 추적용 변수
int32 CurrentPresetIndex;

4. 트러블슈팅 - const 오버로딩 패턴 적용

GetPresetArray 함수의 중복

// 초기에는 두 개 함수가 필요한지 의문이었음
TArray<FPlacedRuneInfo>* GetPresetArray(FArcaneBoardPresets& Presets, int32 PresetIndex);
const TArray<FPlacedRuneInfo>* GetPresetArray(const FArcaneBoardPresets& Presets, int32 PresetIndex) const;

표준 C++ const 오버로딩 패턴으로 해결

// const 버전에 실제 로직 구현
const TArray<FPlacedRuneInfo>* UGS_ArcaneBoardLPS::GetPresetArray(
    const FArcaneBoardPresets& Presets, int32 PresetIndex) const
{
    switch (PresetIndex)
    {
    case 1: return &Presets.Preset1;
    case 2: return &Presets.Preset2;
    case 3: return &Presets.Preset3;
    default: return nullptr;
    }
}

// non-const 버전은 const 버전을 호출
TArray<FPlacedRuneInfo>* UGS_ArcaneBoardLPS::GetPresetArray(
    FArcaneBoardPresets& Presets, int32 PresetIndex)
{
    return const_cast<TArray<FPlacedRuneInfo>*>(
        static_cast<const UGS_ArcaneBoardLPS*>(this)->GetPresetArray(
            static_cast<const FArcaneBoardPresets&>(Presets), PresetIndex));
}

코드 중복을 방지하면서도 const 안전성을 보장하는 표준적인 방식을 적용했음

5. SaveBoardConfig 함수 전면 재구현

새로운 저장 로직

void UGS_ArcaneBoardLPS::SaveBoardConfig(int32 PresetIndex)
{
    // PresetIndex가 -1이면 현재 프리셋에 저장
    int32 TargetPresetIndex = (PresetIndex == -1) ? CurrentPresetIndex : PresetIndex;
    
    // 세이브 파일 로드 또는 생성
    UGS_ArcaneBoardSaveGame* SaveGameInstance = GetOrCreateSaveGame();
    
    // 현재 클래스의 프리셋 구조체 가져오기
    FArcaneBoardPresets& ClassPresets = SaveGameInstance->SavedRunesByClass[CurrentClass];
    
    // 해당 프리셋에 현재 룬 배치 저장
    TArray<FPlacedRuneInfo>* TargetPreset = GetPresetArray(ClassPresets, TargetPresetIndex);
    *TargetPreset = BoardManager->PlacedRunes;
    
    // 최근 사용 프리셋 업데이트
    ClassPresets.LastUsedPresetIndex = TargetPresetIndex;
    CurrentPresetIndex = TargetPresetIndex;
}

6. LoadBoardConfig 함수 전면 재구현

새로운 로드 로직

void UGS_ArcaneBoardLPS::LoadBoardConfig(int32 PresetIndex)
{
    // 로드할 프리셋 인덱스 결정
    int32 TargetPresetIndex;
    if (PresetIndex == -1)
    {
        // 최근 사용 프리셋 로드 (기본값은 1)
        TargetPresetIndex = ClassPresets.LastUsedPresetIndex;
    }
    else
    {
        TargetPresetIndex = PresetIndex;
    }
    
    CurrentPresetIndex = TargetPresetIndex;
    
    // 해당 프리셋 로드
    const TArray<FPlacedRuneInfo>* TargetPreset = GetPresetArray(ClassPresets, TargetPresetIndex);
    BoardManager->LoadSavedData(CurrentClass, *TargetPreset);
}

7. IsPresetEmpty 함수 구현

빈 프리셋 체크 로직

bool UGS_ArcaneBoardLPS::IsPresetEmpty(int32 PresetIndex) const
{
    // 세이브 파일이 없거나 해당 프리셋에 룬이 없으면 빈 프리셋
    const TArray<FPlacedRuneInfo>* TargetPreset = GetPresetArray(ClassPresets, PresetIndex);
    return !TargetPreset || TargetPreset->Num() == 0;
}

UI에서 빈 프리셋 슬롯을 다르게 표시하기 위한 함수

8. 성과와 준비 완료

완료 항목

  • 데이터 구조 변경: FRunePlacementData → FArcaneBoardPresets
  • 저장/로드 로직 재구현: 프리셋 시스템에 맞게 전면 개편
  • const 오버로딩: 표준적인 C++ 패턴 적용
  • API 단순화: 불필요한 래퍼 함수들 제거
  • 빈 프리셋 처리: UI에서 활용할 수 있도록 준비

남은 항목

  • BoardManager에 프리셋 관련 함수들 추가
  • UI에 프리셋 버튼들 추가
  • 프리셋 전환/저장 로직 구현

0개의 댓글