속성 대상 선택 및 속성 UI 동기화 구조

목차

1. 시스템 요구 사항

속성 시스템에서 가장 먼저 해결해야 했던 문제는 플레이어의 입력이 속성 시스템으로 어떻게 전달되어야 하는가였다.

속성 시스템은 강화 시스템과 달리, 모든 장비에 적용되는 기능이 아니라 아케인 스톤(반지)에만 제한적으로 적용되는 시스템이다.

인벤토리에서 반지를 선택했을 때, 현재 부여된 속성의 개수, 추가 속성 가능 여부, 그리고 다음 시도에 필요한 재료와 재화량을 한 프레임 내에서 일관되게 속성 패널에 반영되어야 했다.

이 과정에서 가장 경계해야 했던 것은 인벤토리 슬롯 클릭 시점에 UI를 직접 갱신하는 구조였다.

이 방식은 구현은 빠르지만, 속성 규칙이 추가되거나 UI 구조가 변경될 경우 인벤토리 코드와 속성 시스템 코드가 강하게 결합되는 문제를 만든다.

속성 부여 시스템은 단발성 기능이 아니라, 동일 아이템에 대해 반복적으로 사용되는 시스템이기 때문에, 입력 처리 방식 자체가 이후 로직 확장에도 영향을 받지 않는 구조여야 했다.

따라서 입력 처리 방식 자체가 이후 로직 확장에도 영향을 받지 않는 구조여야 했다.

결국 이 문제는 단순한 UI 반영 문제가 아니라 '입력 → 시스템 → UI' 로 이어지는 데이터 흐름 구조를 먼저 설계해야 하는 문제였다.

2. 설계  목표

- 속성 부여 대상 아이템을 시스템 단계에서 명확히 제한할 것

- 아이템 선택 로직과 UI 갱신 로직을 분리할 것

- 선택 상태 변경 후, 한 프레임 내에서 UI가 일관되게 갱신될 것

- 속성 최대 상태, 재차 불가 상태를 UI에서 즉시 인지 가능하도록 할 것

- 이후 확률 미니게임, 결과 처리 로직이 자연스럽게 확장될 수 있는 구조를 만들 것

3. 흐름도

속성 시스템은 '입력 → 상태 저장 → UI 동기화 → 조건 판단' 의 흐름으로 동작한다.

아이템 선택 시점에는 UI를 직접 변경하지 않고, 선택된 아이템 상태만 시스템 내부에 저장한다.

실제 UI 갱신과 조건 판단은 Update 루프를 통해 일괄적으로 처리하여 항상 동일한 기준 상태를 유지하도록 설계하였다.

이 구조를 통해, 아이템 선택 시점과 관계없이 항상 현재 아이템 상태를 기준으로 UI와 로직이 동기화되도록 구성하였다.

4. 구현

위 표는 속성 시스템에서 사용한 속성 부여 재료와 대상 구조를 나타낸다.

속성 부여는 전용 크리스탈을 사용하며, 모든 장비가 아닌 특정 장비(아케인 스톤(반지))에만 적용 가능하도록 제한하였다.

이를 통해 속성 시스템이 강화 시스템과는 다른 성격의 성장 요소로 작동하도록 명확히 구분하였다.

4.1. 속성 대상 아이템 선택 제한

속성 부여 시스템은 인벤토리에서 선택된 아이템을 currentItem 변수에 저장하는 방식으로 구성하였다.

public void UpgradeItem(Item item)
{
    if (item == null) return;

    if (item.itemType == Item.ITEMTYPE.Equipment &&
        item.equipType == Item.EquipType.Ring)
    {
        currentItem = item;

        ringSlot.sprite = currentItem.itemImage;
        ringSlot.enabled = true;
    }
}

UpgradeItem() 함수는 인벤토리 슬롯 클릭 시 호출된다.

오직 선택된 아이템이 장비인지, 그리고 그 장비가 반지(아케인 스톤)인지만을 판단한다.

초기 구현에서는 아이템 타입과 장비 타입을 검사한 뒤, 반지 장비인 경우 UI 슬롯 이미지를 활성화했다.

그러나 이 과정에서 실제 속성 부여 대상인 currentItem이 명확하게 갱신되지 않아, 이후 속성 부여 로직이 어떤 아이템을 기준으로 동작하는지 흐름을 파악하기 어려운 문제가 있었다.

이를 해결하기 위해 구조를 개선하여, 반지(아케인 스톤) 장비를 선택하는 시점에 currentItem을 명확히 할당하도록 변경하였다.

조건을 만족하는 경우에만 선택된 아이템을 currentItem으로 저장하며, 속성 부여 시스템 전반은 항상 이 단일 대상만을 기준으로 동작하도록 통일되었다.

이를 통해 속성 부여 대상의 출처가 명확해지고, 로직 흐름을 추적하기 쉬운 구조가 되었다.

또한 속성 부여가 반지에만 가능하다는 규칙을 이 단계에서 구조적으로 제한함으로써, 이후 속성 부여 로직에서 불필요한 조건 분기를 줄일 수 있었다.

이 과정에서는 속성 패널의 상세 정보 UI를 즉시 갱신하지 않고, 선택 대상 변경을 나타내는 최소한의 선택 표시만 수행하도록 역할을 분리하였다.

4.2. 선택 상태 기반 UI 갱신 구조

선택된 아이템이 존재할 경우,속성 부여 시스템은 Update 루프를 통해 현재 아이템 상태를 기준으로 UI를 갱신한다.

private void Update()
{
    UpdateCrystalUI();
    UpdateUpgradeCostUI();
}

초기에는 Update() 함수 내부에서 크리스탈 수량 갱신과 속성 부여 단계에 따른 비용 계산이 함께 처리하였다.

그러나, 조건 분기가 늘어나면서 Update 함수의 책임이 과도해졌고, UI 변경이 속성 부여 로직과 강하게 결합되는 문제가 생겼었다.

그래서 Update() 함수는 UI 갱신 트리거 역할만 수행하도록 변경하였다.

보유 크리스탈 수 UI를 책임지는 함수와 속성 부여 단계 및 최대 부여 상태에 따른 UI를 책임지는 함수로 나누어 각각의 전용 함수로 분리하였다.

UpdateCrystalUI() 함수는 보유 크리스탈 수량 표시만을 책임지며, UpdateUpgradeCostUI() 함수는 속성 부여 단계 및 최대 부여 상태에 따른 필요 재료 표시만을 담당하도록 하였다.

이로 인해 Update() 함수는 UI 갱신을 트리거하는 역할만 수행하게 되었고, 각 UI 요소가 어떤 조건에서 변경되는지 흐름을 명확히 파악할 수 있게 되었다.

이 구조를 선택한 이유는, 속성 시스템이 재화 변화, 결과 반영, 자동 실행 등 다양한 상태 변화에 영향을 받기 때문이다.

Update 루프에서 UI를 갱신함으로써, 아이템 선택 시점과 관계없이 항상 상태 기준으로 UI가 동기화되도록 구성하였다.

물론, 이벤트 기반으로 할 수 있지만, 현재는 단일 속성 부여 패널이라 성능 부담이 적어 Update로 두었다.

실제 프로젝트에서는 선택/재화 변경 시 이벤트로 전환 가능하다.

이로 인해, 속성 시스템은 아이템 선택, 재화 변화, 결과 반영 등 어떤 상태 변화가 발생하더라도 항상 동일한 기준으로 UI를 출력할 수 있게 되었다.

5. 개발 의도

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

하지만 이 방식은 UI 구조가 바뀔 경우 인벤토리 코드까지 함께 수정해야 하고,
속성 로직이 확장될수록 시스템 간 의존성이 커질 위험이 있었다.

그래서 강화 시스템과 동일하게 '입력 → 상태 변경 → 시스템 처리 → UI 출력' 구조를 선택했고,
이를 통해 속성 부여 시스템 역시 확장과 유지보수에 유리한 구조를 확보할 수 있었다.


속성 부여 시스템은 강화 시스템과 달리 하나의 아이템에 대해 여러 번 반복적으로 접근하는 구조다.

그래서 한 번의 입력 처리보다 항상 신뢰할 수 있는 상태 동기화 구조가 더 중요하다고 판단했다.

입력은 상태만 변경하고, 시스템은 그 상태를 기준으로 판단하며, UI는 판단 결과만 출력한다.

이 구조를 통해 속성 재료 계산, 확률 미니게임, 속성 결과 처리와 같은 기능이 추가되더라도 입력 처리 방식 자체는 변경되지 않는다.

속성 부여 시스템 역시 강화 시스템과 동일한 설계 철학 위에서 확장 가능하도록 구성했다.

강화 시스템이 한 번의 선택과 결과가 중심인 구조라면, 속성 부여 시스템은 하나의 아이템에 대해 여러 번 반복적으로 상태가 누적되는 구조다.

따라서 속성 시스템에서는 단일 이벤트 처리보다 항상 현재 상태를 기준으로 동작하는 구조가 더 중요하다고 판단했다.