속성 부여 시도 검증 및 확률 미니 게임 진입 구조

목차

1. 요구 사항

2. 설계 목표

3. 흐름도

4. 구현

        4.1. 속성 부여 시도 진입 조건 분기

       4.2. 재화 및 재료 검증 구조

       4.3. 확률 미니 게임 초기화 및 진입

5. 개발 의도

1. 시스템 요구 사항

속성 부여 시스템의 세 번째 핵심은 조건이 충족되지 않은 상태에서 속성 부여 시도가 실행되는 상황을 구조적으로 차단하는 것이었다.

속성 부여는 아이템 선택 여부, 최대 속성 상태, 재화 보유량 등 여러 조건을 동시에 만족해야만 가능한 시도다.

이 중 하나라도 어긋난 상태에서 시도가 이루어질 경우, 재화 차감 오류나 잘못된 상태 전이가 발생할 수 있다.

따라서 버튼 클릭 시점에는 UI 상태를 신뢰하지 않고, 시스템 내부 상태를 기준으로 한 번 더 검증하는 단계가 필요했다.

2. 설계  목표

- 속성 부여 가능 여부를 시스템 기준으로 검증할 것

- 검증 실패 사유를 명확히 구분할 것

- 조건 만족 시 즉시 미니 게임으로 진입할 것

- 이후 자동 실행, 확률 시스템과 자연스럽게 연결될 수 있는 구조를 만들 것

3. 흐름도

속성 시스템은 버튼 클릭 시 UI에 표시된 정보가 아니라, 현재 아이템과 재화의 실제 상태를 기준으로 속성 부여 가능 여부를 다시 한 번 검증한다.

이를 통해 UI와 로직이 어긋난 상태에서 잘못된 속성 부여 시도가 발생하는 상황을 방지한다.

4. 구현

4.1. 속성 부여 시도 진입 조건 분기
public void UpgradeBtnClick()
{
    if (currentItem == null) return;
    
    if (IsMaxEnhanced())
    {
        StartCoroutine(ShowError(maxWarningTxt.gameObject, 0.5f));
        return;
    }
    
    CheckAndUpgrade();
}

UpgradeBtnClick 함수는 속성 부여 버튼 클릭 시 가장 처음 호출되는 입력 처리 함수다.

이 함수는 속성 부여를 즉시 실행하지 않고, 시도가 가능한 상태인지 여부를 1차적으로 판별하는 역할을 한다.

함수가 호출되면 먼저 currentItem이 존재하는지 확인하여, 속성 부여 대상 아이템이 선택되지 않은 상태에서는 아무 처리도 하지 않고 즉시 종료한다.

이는 아이템이 선택되지 않은 상태에서 속성 부여 로직이 실행되는 것을 구조적으로 차단하기 위함이다.

다음으로 IsMaxEnhanced를 호출하여, 선택된 아이템이 이미 최대 속성 상태인지 여부를 확인한다.

이미 최대 속성 상태인 경우에는 재화 검증이나 미니게임 초기화와 같은 후속 로직을 전혀 실행하지 않고, 경고 UI만 표시한 뒤 즉시 흐름을 종료한다.

이 단계에서는 속성 최대 상태 여부를 가장 먼저 차단하여,이미 더 이상 속성을 부여할 수 없는 경우에는 불필요한 재화 검증이나 미니게임 초기화를 수행하지 않도록 하였다.

이 두 조건을 모두 통과한 경우에만 CheckAndUpgrade 함수를 호출하여 재화 및 재료 검증 단계로 흐름을 전달한다.

즉, UpgradeBtnClick 함수는속성 부여를 실행하는 함수가 아니라, 속성 부여 시도에 진입할 수 있는지 여부를 판단하는 1차 게이트 역할을 수행한다.

4.2. 재화 및 재료 검증 구조
private void CheckAndUpgrade()
{
    int upgradeCost = int.Parse(needCoinTxt.text);

    string rawText = needItemTxt.text;
    Match match = Regex.Match(rawText, @"\d+");
    int requiredCrystals = match.Success ? int.Parse(match.Value) : 0;

    Item crystalItem = im.GetItem(CrystalItemId);

    bool hasEnoughCrystals = crystalItem != null &&
                             crystalItem.count >= requiredCrystals;
    bool hasEnoughCoins = im.coin >= upgradeCost;

    bool canUpgrade = currentItem != null &&
                      hasEnoughCoins &&
                      hasEnoughCrystals;

    if (canUpgrade)
    {
        im.coin -= upgradeCost;
        crystalItem.count -= requiredCrystals;

        InitializeMiniGame();
    }
    else
    {
        StartCoroutine(ShowError(warningTxt.gameObject, 0.2f));
    }
}

CheckAndUpgrade 함수는 속성 부여 시도가 실제로 가능한지를 시스템 기준으로 최종 검증하는 함수다.

이 단계에서는 UI 상태를 신뢰하지 않고, 현재 재화와 재료의 실제 보유 상태를 기준으로 판단한다.

함수는 먼저 UI에 표시된 비용 정보를 기준으로 필요한 코인 비용과 크리스탈 수량을 각각 숫자 값으로 추출한다.

크리스탈 수량은 UI 텍스트 포맷과 무관하게 숫자 정보만 안정적으로 분리하기 위해 정규식을 사용하여 파싱한다.

이후 ItemManager를 통해 실제 보유 중인 크리스탈 아이템과 코인 수량을 조회하고, 코인과 크리스탈이 모두 충분한 경우에만 canUpgrade를 true로 판단한다.

비용 정보는 UI 텍스트를 그대로 신뢰하지 않고, 필요 수량만 추출해 시스템 로직에서 재검증한다.

이를 통해 UI 포맷이 변경되더라도 속성 부여 검증 로직이 영향을 받지 않도록 구성하였다.

초기 구현에서는 UI 텍스트를 그대로 파싱해 속성 부여 가능 여부를 판단했지만, UI 표현 방식 변경 시 로직이 함께 깨질 수 있는 구조였다.

이를 보완하기 위해 UI 텍스트를 그대로 신뢰하지 않고, 정규식을 사용해 숫자 값만 추출하였다.

Regex.Match(@"\\d+")는 문자열 포맷이 “/ 1”, “필요 수량 : 2개”처럼 변경되더라도, 숫자 정보만 안정적으로 분리할 수 있게 해준다.

이 방식은 UI를 데이터 소스로 삼는 것이 아니라, 상태 기반으로 갱신된 UI를 검증 단계에서 참고하는 구조이기 때문에, MVC 관점에서도 표현 계층과 로직 계층의 책임이 충돌하지 않는다.

이를 통해 UI 표현 형식이 변경되더라도 내부 속성 부여 로직은 영향을 받지 않도록 설계되었다.

이 시스템에서는 UI가 항상 상태 기반으로 갱신되기 때문에, UI 텍스트를 표현용 캐시로 활용하더라도 상태 불일치가 발생하지 않는다.

따라서 정규식을 통해 숫자 정보만 추출하는 방식은표현 계층과 로직 계층의 책임을 침범하지 않으면서도 UI 변경에 유연하게 대응할 수 있는 현실적인 선택이었다.

또한 재화 검증 로직을 코인 검증과 크리스탈 검증으로 나누어 처리하였다.

이를 통해 속성 부여 가능 여부 판단 과정이 보다 명확하고 읽기 쉬운 흐름으로 개선되었다.

속성 부여 시도 시점에 재화를 즉시 차감하도록 설계하여, 부여 실패 또한 하나의 비용이 드는 선택으로 인식되도록 구성하였다.

이를 통해 속성 부여 시스템의 긴장감과 선택의 무게를 유지하였다.

canUpgrade가 true인 경우에는 속성 부여 시도가 하나의 선택으로 완료되었다고 판단하여, 필요한 코인과 크리스탈을 즉시 차감한 뒤 확률 미니게임 초기화 단계로 흐름을 넘긴다.

반대로 재화나 재료가 하나라도 부족한 경우에는 속성 부여 시도를 실행하지 않고, 부족 경고 UI만 일정 시간 표시한 뒤 종료한다.

이 함수는 재화가 충분한가를 묻는 함수가 아니라, 이 시도가 실행 가능한가를 최종적으로 확정하는 단계이며, 이후 단계에서는 재화 부족을 다시 검사할 필요가 없도록 흐름을 정리해준다.

4.3. 확률 미니 게임 초기화 및 진입
private void InitializeMiniGame()
{
    probabilityButtonManager.InitializeMiniGame();
    miniGame.SetActive(true);

    randomIndex = Random.Range(0, upgradelist.Count);
    upgradeInfoTxt.text = upgradelist[randomIndex];

    warningTxt.gameObject.SetActive(false);
}

InitializeMiniGame 함수는 속성 부여 시도가 확정된 이후, 확률 미니게임을 시작하기 위한 초기 상태를 구성하는 함수다.

이 함수가 호출되는 시점은 이미 아이템 선택, 최대 속성 여부, 재화 보유 여부가 모두 검증되고 필요한 재화까지 차감된 상태다.

함수 내부에서는 먼저 확률 미니게임의 버튼 상태와 확률 값을 초기화한 뒤, 미니게임 패널을 활성화하여 플레이어가 즉시 상호작용할 수 있도록 한다.

이후 랜덤 인덱스를 통해 이번 시도에서 부여될 속성을 미리 결정하고, 해당 속성을 UI에 표시한다.

이 단계에서 속성을 먼저 결정하는 이유는, 확률 미니게임의 역할을 어떤 속성을 부여할 것인가가 아니라 이미 결정된 속성이 실제로 적용되는가를 판단하는 단계로 제한하기 위함이다.

즉, 속성 결정은 시도 시점에 완료되고, 미니게임은 성공 여부만 판정하는 구조다.

이를 통해 확률 시스템의 책임을 명확히 분리하고, 속성 종류가 늘어나더라도 미니게임 로직은 영향을 받지 않도록 구성하였다.

5. 개발 의도

속성 부여 시스템에서는 버튼 클릭을 속성 부여 실행으로 보지 않고, 속성 부여 시도에 진입하기 위한 요청으로 해석했다.

그래서 버튼 클릭 이후에도 아이템 상태, 최대 속성 여부, 재화 보유량을 시스템 기준으로 다시 한 번 검증하도록 구성했다.

이 구조를 통해 UI 표시 오류나 상태 불일치로 인한 잘못된 속성 부여 시도를 구조적으로 차단할 수 있었다.

속성 부여 시도 검증과 미니게임 진입은 다음 단계인 확률 변화, 자동 실행, 최종 속성 결과 처리의 기준점 역할을 한다.

이로 인해 속성 부여 시스템은 '시도 → 검증 → 실행' 이라는 단계가 명확히 분리된 구조를 갖게 되었다.