선택 상태 기반 제작 패널 동기화 구조
1. 시스템 요구 사항
제작 슬롯을 데이터 기반으로 동적 생성하는 구조를 만든 이후, 다음으로 해결해야 했던 문제는 어떤 아이템이 선택되었는지를 시스템 전반에서 일관되게 인식하는 방식이었다.
제작 UI는 단순히 슬롯을 나열하는 것으로 끝나지 않고, 슬롯 클릭 시 제작 패널에 아이템 이미지, 스탯 정보, 필요 재료, 보유 재화, 제작 버튼 상태까지 동시에 갱신되어야 한다.
이때 각 UI 요소가 서로 다른 기준으로 갱신되면, 특정 패널만 이전 아이템 정보를 보여주거나 재화 수량이 어긋나는 문제가 발생하기 쉽다.
초기 구현에서는 슬롯 클릭 시마다 여러 UI 요소를 개별적으로 갱신하는 방식이었는데, 이 경우 어떤 정보가 어떤 아이템 기준으로 표시되는지를 추적하기 어려웠다.
특히 검색 기능과 결합되었을 때, 선택 상태가 명확히 관리되지 않으면 잘못된 아이템 기준으로 제작이 시도될 수 있었다.
따라서 제작 시스템에서는 선택 상태를 하나의 기준 값으로 관리하고, 그 기준을 중심으로 UI와 제작 로직이 함께 움직이도록 구조를 재정리할 필요가 있었다.
2. 설계 목표
- 선택된 제작 아이템을 단일 상태 값으로 관리할 것
- UI 표시, 제작 로직, 재화 갱신이 동일한 기준을 사용하도록 할 것
- 슬롯 재생성(검색) 시 선택 상태를 명확히 초기화할 것
- 제작 패널이 선택 상태가 유효할 때만 활성화되도록 할 것
3. 흐름도

이 구조에서 중요한 점은, 선택 상태 자체가 UI에 종속되지 않는다는 점이다.
어떤 슬롯이 클릭되었는지는 버튼이나 슬롯 오브젝트가 아니라, selectedIndex라는 단일 상태 값으로만 관리된다.
제작 패널, 재화 표시, 제작 버튼 로직은 모두 이 값을 기준으로 동작하며, 슬롯은 단순히 선택 상태를 바꾸는 트리거 역할만 수행한다.
4. 구현
4.1. 선택 상태의 단일 기준화
private int selectedIndex = -1;
선택 상태는 단순한 정수 인덱스로 관리한다.
이 값은 craftableItems와 materialItems 리스트의 공통 인덱스를 의미하며, 현재 제작 패널이 어떤 아이템을 기준으로 표시되어야 하는지를 나타낸다.
초기값을 -1로 둔 이유는 아무 아이템도 선택되지 않은 상태를 명확히 표현하기 위함이다.
이 값이 유효 범위에 들어가지 않으면 제작 패널은 갱신 대상이 없다고 판단할 수 있다.
이 방식의 장점은 선택 상태가 UI 오브젝트에 묶이지 않는다는 점이다.
선택 상태를 객체 참조가 아닌 정수 인덱스로 관리한 이유는, 슬롯 재생성이나 UI 파괴 시에도 참조 무효 문제가 발생하지 않도록 하기 위함이다.
선택 기준은 단순한 값 하나로 유지되며, 필요할 경우 언제든 초기화할 수 있다.
4.2. 슬롯 클릭 시 제작 패널 동기화
private void OnItemClicked(Item item, int index)
{
selectedIndex = index;
craftPanel.SetActive(true);
itemImage.sprite = item.itemImage;
materialImage.sprite = materialItems[index].itemImage;
statTxt.text = string.Join("\n", item.stats);
haveItemTxt.text = materialItems[index].count.ToString();
haveCoinTxt.text = itemManager.coin.ToString();
bool isHpPotion = item.itemCode == "200_01_01";
needItemTxt.text = isHpPotion ? "3" : "1";
needCoinTxt.text = isHpPotion ? "100" : "50";
Button craftBtn = craftPanel.transform.Find("CraftBtn").GetComponent<Button>();
craftBtn.onClick.RemoveAllListeners();
craftBtn.onClick.AddListener(() => TryCraft(item, index));
}
슬롯 클릭 시 가장 먼저 하는 일은 selectedIndex를 갱신하는 것이다.
이후의 모든 UI 갱신은 이 선택 상태를 기준으로 이루어진다.
제작 패널은 선택과 동시에 활성화되며, 아이템 이미지와 재료 이미지, 스탯 텍스트가 즉시 갱신된다.
스탯 정보는 string.Join("\n", item.stats)를 사용해 문자열 배열을 하나의 줄바꿈 문자열로 결합했다.
string.Join은 반복적인 문자열 결합보다 가독성이 좋고, 배열 기반 데이터를 UI에 표시할 때 의도가 명확하다.
이 방식 덕분에 스탯 개수가 늘어나거나 줄어들어도 UI 코드는 변경할 필요가 없다.
제작 버튼 이벤트는 매번 RemoveAllListeners() 후 새로 등록한다.
이는 이전에 선택했던 아이템의 제작 로직이 중복 호출되는 문제를 방지하기 위함이다.
버튼이 재사용되는 구조에서는 리스너 관리가 중요하기 때문에, 선택 변경 시점에 명시적으로 초기화하는 방식을 택했다.
제작 버튼에서도 동일한 index를 전달함으로써, 이후 제작 조건 검증 및 실행 단계까지 선택 상태 기준이 유지되도록 했다.
이 구조를 통해 슬롯 UI는 상태를 저장하지 않고, 단순히 선택 이벤트만 전달하는 역할로 제한된다.
4.3. 실시간 재화/재료 UI 동기화
private void Update()
{
if (selectedIndex >= 0 && selectedIndex < materialItems.Count)
{
haveItemTxt.text = materialItems[selectedIndex].count.ToString();
haveCoinTxt.text = itemManager.coin.ToString();
}
}
제작 패널이 열려 있는 동안 인벤토리나 재화 수량은 외부 시스템에 의해 변경될 수 있다.
이를 즉시 반영하기 위해 Update()에서 선택 인덱스가 유효한 경우에만 재화 및 재료 UI를 갱신하도록 했다.
이 구조의 핵심은 UI가 상태를 저장하지 않는다는 점이다.
UI는 항상 현재 상태를 읽어와 표시할 뿐이며, 진짜 데이터는 ItemManager와 아이템 데이터에만 존재한다.
이로 인해 제작 실패, 재화 소모, 다른 시스템에 의한 아이템 변화가 발생하더라도 UI 불일치 문제가 생기지 않는다.
이 시스템에서는 재화 변경이 여러 시스템에서 발생할 수 있기 때문에, 특정 이벤트에만 의존하기보다 현재 상태를 매 프레임 읽어오는 방식이 안정적이라고 판단했다.
이 프로젝트에서는 재화 변경이 여러 시스템에서 발생할 수 있어, 특정 이벤트에 의존하기보다 현재 상태를 주기적으로 읽어오는 방식이 더 안전하다고 판단했다.
4.4. 검색 입력 시 선택 상태 초기화
검색어가 변경될 때는 슬롯이 재생성되며, 이 시점에서 선택 상태는 반드시 초기화된다.
private void OnSearchValueChanged(string searchText)
{
...
selectedIndex = -1;
craftPanel.SetActive(false);
}
이 처리는 검색 기능이 제작 로직에 영향을 주지 않도록 하기 위한 장치다.
검색 결과가 바뀌었는데 이전 선택 상태가 유지되면, 화면에 더 이상 표시되지 않는 아이템을 기준으로 제작 시도가 이루어질 수 있다.
따라서 검색은 슬롯 표시만 변경하는 기능으로 한정하고, 선택 상태와 제작 패널은 항상 명시적으로 리셋되도록 설계했다.
이 설계를 통해 검색 기능은 제작 시스템의 상태와 분리된 보조 기능으로 동작한다.
5. 개발 의도
이 게시글에서 다룬 구조의 핵심은 선택 상태를 하나의 값으로 수렴시키는 것이다.
UI 요소마다 기준을 따로 두는 대신, 제작 시스템 전체가 selectedIndex라는 단일 기준을 바라보도록 설계했다.
이 덕분에 슬롯 UI, 제작 패널, 재화 표시, 제작 버튼 로직이 서로 얽히지 않고도 자연스럽게 동기화된다.
이 구조를 기반으로 이후 제작 조건 검증과 실행 로직을 추가하더라도, 시스템의 중심인 선택 상태 기준은 흔들리지 않는다.
