강화 대상 선택 및 강화 준비 UI 동기화 구조

목차

1. 요구 사항

2. 흐름도

3. 구현

       3.1. 강화 대상 선택 상태 관리

       3.2. 강화 시스템 처리 흐름 제어

       3.3. 강화 준비 UI 출력 동기화

       3.4. UI 상태 초기화

4. 개발 의도

1. 시스템 요구 사항

강화 시스템에서 가장 먼저 해결해야 했던 문제는 인벤토리에서 선택된 아이템 정보를 기준으로 강화 시스템의 UI와 강화 가능 상태를 어떻게 일관되게 동기화할 것인가였다.

인벤토리에서 아이템을 선택했을 때, '아이템 이미지, 이름, 강화 단계, 필요 재화' 가 즉시 UI에 반영되어야 했고, 이후 강화 규칙이나 UI 구조가 변경되더라도 입력 처리 방식 자체는 영향을 받지 않도록 하고자 했다.

강화 시스템에서는 인벤토리 입력으로 전달된 아이템 정보를 기준으로 강화 시스템의 UI와 강화 가능 상태를 한 프레임 내에서 일관되게 갱신하는 것을 목표로 했다.

2. 흐름도

입력 이벤트는 선택 상태만 변경하고, 실제 UI 반영과 로직 처리는 Update 루프에서 수행하도록 설계했다.

입력 시점과 시스템 처리 시점을 분리하고, 한 프레임 내에서 모든 강화 관련 정보가 일관되게 갱신되도록 흐름을 구성하였다.

3. 구현

3.1. 강화 대상 선택 상태 관리
private Item selectedItem;

public void SelectItem(Item _item)
{
    selectedItem = _item;
}

강화 대상은 인벤토리에서 슬롯 클릭을 통해 전달된다.

강화 시스템은 아이템의 참조만 저장하고, 강화에 필요한 정보는 이후에 분리하여 처리하도록 구성했다.

SelectItem(Item _item) 함수는 인벤토리 슬롯 클릭 시 호출되며, 외부에서 전달된 Item 객체의 참조를 내부 변수 selectedItem에 저장한다.

이 함수는 아이템 선택이라는 상태 변경만 수행하며, UI 갱신이나 강화 로직 실행은 포함하지 않는다.

현재 강화 대상으로 지정된 아이템을 selectedItem 단일 변수로 관리하며, 강화 시스템에서의 모든 처리를 selectedItem의 null 여부와 데이터에 의존하여 수행한다.

강화 준비 UI, 비용 계산, 버튼 활성화 여부 판단 등이 모두 selectedItem 상태를 기준으로 동작한다.

3.2. 강화 시스템 처리 흐름 제어
void Update()
{
    if (selectedItem != null)
    {
        UpdateSelectedItemUI();
        UpdateRequirementsByType();
        UpdateUpgradeState();
    }

    UpdateGradeImageVisibility();
}

private void UpdateGradeImageVisibility()
{
    gradeImage.enabled = (gradeImage.sprite != null);
}

Update 함수는 선택된 아이템이 존재할 경우, 강화 준비 UI에 '해당 아이템의 기본 정보, 강화 비용, 강화 가능 여부' 를 한 프레임 내에서 갱신한다.

개발 초기에는 Update 함수 내부에서 '아이템 선택 여부 판단, UI 표시, 강화 비용 계산, 강화 가능 여부 판단' 을 하나의 흐름으로 처리했다.

이로 인해 UI 수정이 필요할 경우 강화 로직까지 함께 수정해야 했고, Update가 과도한 책임을 가지게 되었다.

이에 따라 Update의 역할을 선택된 아이템 존재 여부를 확인하고, 처리 흐름을 제어하는 수준으로 축소하고, 실제 로직은 전용 함수로 분리하였다.

Update 함수는 강화 시스템의 프레임 단위 상태 동기화 레이어로 사용된다.

강화 준비 UI는 선택된 아이템, 보유 재화 수량, 강화 단계 등의 상태에 따라 UI 출력과 강화 가능 여부가 실시간으로 동기화되어야 하는 구조이다.

특히 재화 수량은 강화 외에도 상점 구매, 보상 지급 등 외부 시스템에 의해 비동기적으로 변경될 수 있다.

이러한 상태 변화를 개별 이벤트로 모두 연결할 경우 강화 시스템이 재화 시스템, 인벤토리 시스템에 직접 의존하게 되며 시스템 간 결합도가 급격히 증가한다.

이를 피하기 위해 강화 준비 UI는 selectedItem과 현재 재화 상태를 프레임 단위로 조회하는 방식을 선택하였다.

매 프레임 호출로 인한 비용을 고려하여, 실제 연산은 선택된 아이템이 존재할 경우에만 수행되도록 제한하였으며, UI 갱신(UpdateSelectedItemUI), 강화 비용 계산(UpdateRequirementByType), 강화 가능 여부 판단(UpdateUpgradeState)을 각각의 함수로 분리하였다.

UpdateGradeImageVisibility 함수는 이미 강화된 아이템이면 강화 단계 이미지를 활성화하고, 강회되지 않았으면 강화 단계 이미지 비활성화하는 로직이다.

3.3. 강화 준비 UI 출력 동기화
private void UpdateSelectedItemUI()
{
    icon.enabled = true;
    icon.sprite = selectedItem.itemImage;
    gradeImage.sprite = selectedItem.gradeSprite;
    itemName.text = selectedItem.itemName;
}

UpdateSelectedItemUI 함수는 선택된 아이템의 데이터를 강화 준비 UI에 반영하는 역할을 수행한다.

selectedItem에 저장된 아이템 이미지, 강화 단계 이미지, 아이템 이름을 읽어 각각 아이콘 이미지와 텍스트 UI에 할당한다.

이 함수는 UI 출력만을 담당한다.

이는, 강화 규칙이나 알고리즘이 변경되더라도 UI 출력 코드에는 영향을 주지 않으며, 강화 준비 UI 구성이 변경될 경우에도 해당 함수만 수정하면 되도록 하였다.

3.4. UI 상태 초기화
public void CancelSelection()
{
    selectedItem = null;

    icon.enabled = false;
    icon.sprite = null;

    gradeImage.enabled = false;
    gradeImage.sprite = null;

    itemName.text = "";
    upgradeInfo.text = "";
    crystalCount.text = "";
    reqCoin.text = "";

    BtnOrErr(false, false);

    if (roulettePanel != null) roulettePanel.SetActive(false);
    if (resultPanel != null) resultPanel.SetActive(false);

    isRotating = false;
    upgradeAttempted = false;
}

CancelSelection 함수는 강화 준비 UI에서 사용되는 모든 선택 상태와 UI 출력 상태를 초기화하는 상태 리셋 전용 함수이다.

함수 호출 시 먼저 selectedItem을 null로 설정하여 강화 대상이 존재하지 않는 상태로 전환하고, 이를 기준으로 이후 강화 관련 로직이 실행되지 않도록 한다.

이후 아이템 아이콘과 강화 단계 이미지에 대해 enabled를 false로 설정하고, 연결된 sprite 참조를 제거하여 이전 아이템의 시각적 정보가 화면에 남지 않도록 한다.

아이템 이름, 강화 정보, 재화 수량과 관련된 텍스트 UI는 빈 문자열로 초기화하여 강화 대상이 없는 상태임을 UI 상에서 명확히 표시한다.

BtnOrErr(false, false) 호출을 통해 강화 버튼과 오류 메시지의 활성 상태를 동시에 비활성화하고, 강화 가능 여부와 무관하게 입력이 차단된 상태로 되돌린다.

룰렛 UI와 결과 UI가 존재할 경우 SetActive(false)를 호출하여 비활성화함으로써, 강화 연출 도중이거나 결과 표시 상태에서 강화 대상이 변경되는 상황을 방지한다.

마지막으로 isRotating과 upgradeAttempted 플래그를 false로 설정하여, 강화 시도 과정에서 사용되던 내부 진행 상태를 모두 리셋한다.

이를 통해 이전 강화 시도의 상태가 다음 강화 처리에 영향을 주지 않도록 하였다.

4. 개발 의도

처음에는 인벤토리 슬롯 클릭 시 강화 UI를 직접 갱신하는 방식도 고려했다.

하지만 이 방식은 UI 구조가 변경될 경우 인벤토리 코드까지 수정해야 하고, 강화 로직이 늘어날수록 시스템 간 의존성이 빠르게 증가할 수 있다고 판단했다.

이러한 문제를 고려하여, 입력 처리와 시스템 반영을 분리한 구조를 선택했다.

이 구조를 통해 강화 비용 계산, 강화 가능 조건 판단, 이후 확률 시스템까지 Update 루프 안에서 자연스럽게 확장할 수 있는 기반을 마련할 수 있었다.

결과적으로 인벤토리와 강화 준비 UI 간의 데이터 흐름이 명확해졌고, UI 변경에도 영향을 받지 않는 구조를 확보할 수 있었다.

또한 강화 시스템이 확장되더라도 기존 코드 수정 없이 기능을 추가할 수 있어 유지보수성과 확장성을 동시에 만족시킬 수 있었다.