- Project Explain | A top-down combat prototype inspired by Eternal Return, focused on implementing core gameplay systems
- Engine | Unity 6000.3.7f1
- Development Period | X weeks
- GitHub | Links
ScriptableObject 기반 데이터 관리
아이템의 이름, 아이콘, 설명, 최대 스택 수와 같은 정보는 게임 전체에서 공유되는 정적 데이터이므로 ScriptableObject를 사용하여 관리했다.
게임 플레이 중 실제로 필요한 정보는 현재 플레이어가 아이템을 몇 개 보유하고 있는가와 같은 런타임 상태 데이터이다. 이러한 값은 플레이 과정에서 계속 변하므로 ScriptableObject에 직접 저장하지 않도록 설계했다.
ItemStack 구조 설계
런타임 상태를 관리하기 위해 ItemStack 클래스를 별도로 정의했다.
ItemStack은 특정 아이템의 보유 상태를 표현하는 역할을 하며, 아이템 정의 자체가 아니라 아이템 소지 상태를 관리하는 구조체 개념으로 사용했다.
이를 통해 다음과 같은 기능을 구현할 수 있다.
예를 들어 최대 스택이 3인 아이템을 4개 획득하면 3개 스택과 1개 스택으로 분리되어 저장되도록 구현했다.
Inspector 직렬화 처리도 같이 해주었는데
Unity는 기본적으로 MonoBehaviour, ScriptableObject, 그리고 일부 기본 자료형만 자동 직렬화를 지원한다.
따라서 ItemStack 클래스에 직렬화 특성을 추가하여 런타임 데이터 구조를 Inspector에서도 확인할 수 있도록 했다.
슬롯 기반 구조로 구현했다.
초기 생성 시 ScriptableObject 설정값을 기준으로 슬롯을 생성하며, 랜덤 아이템 테이블을 통해 아이템을 배치했다.
하지만 내가 구현한 초기 UI와 비교했을 때 상자 UI 구조가 다소 차이가 있었고
상자에서 아이템을 클릭했을 때와 인벤토리에서 아이템을 클릭했을 때 이후 처리 로직이 서로 달라지는 문제가 발생해서
결국 단일 슬롯 구조로는 기능 확장이 어렵다고 판단하여 UI 구조를 분리하는 방향으로 수정 작업을 진행했다.
원본 UI의 레이아웃과 상호작용 방식을 분석하며 작업 방향을 잡았다.
아이템 획득 시 슬롯을 제거하지 않고 빈 슬롯을 리스트 뒤로 이동시키는 방식으로 구현했다.
이를 통해 UI 슬롯 개수를 일정하게 유지하면서 자연스러운 정렬이 가능하도록 했다.
또한 슬롯 상태를 Filled / Empty Sprite로 구분하여 아이템 존재 여부를 시각적으로 표현했다.

인벤토리 구조 설계
Inventory 역시 Chest와 동일하게 슬롯 기반 구조로 설계했다.
최대 소지 개수 제한도 적용하였다.
아이템 획득 시 기존 스택을 우선 채우고, 부족한 수량은 새로운 스택으로 분리하여 저장하도록 구현했다.
인벤토리 UI 갱신 구조
아이템 획득, 사용, 또는 제거 이벤트가 발생하면 UI Manager를 통해 화면을 갱신하도록 했다.
인벤토리가 닫혀있는 상태에서는 UI 갱신을 수행하지 않도록 조건을 추가하여 불필요한 객체 생성과 렌더링 비용을 줄였다.
인벤토리 최대 소지 제한
인벤토리 최대 슬롯 수를 10개로 제한했다.
슬롯이 가득 찬 상태에서는 아이템 획득 자체를 차단하고 경고 UI를 출력하도록 했다.
경고 메시지는 Coroutine 기반으로 일정 시간 후 자동으로 사라지도록 구현했다.
또한 경고 메시지가 중복 호출될 경우 타이머가 초기화되지 않도록 상태 기반 관리 구조를 적용했다.
Tooltip UI는 싱글톤 패턴으로 구현하여 게임 내 Tooltip이 하나만 존재하도록 설계했다.
ScriptableObject로 관리하는 아이템 고유의 등급, 타입에 따른 차별 적용
Tooltip 패널은 Update에서 마우스 위치를 기준으로 이동하도록 처리했고,
Tooltip은 Pointer Enter 이벤트에서 활성화되며 Pointer Exit 이벤트에서 비활성화된다.
Inventory와 Chest에서 공통 Tooltip을 사용하되, Tooltip Owner Enum을 통해 UI 창 간 충돌을 방지했다.
Tooltip Owner 상태 관리
public enum TooltipOwner
{
None,
Inventory,
Chest
}
Tooltip Owner를 기준으로 다음 동작을 구분했다.
이를 통해 서로 다른 UI 영역 간 상태 충돌을 방지했다.
플레이어 이동이 발생하지 않도록 EventSystem 기반 입력 검사를 추가했다.
bool IsPointerOverBlockUI()
{
if (EventSystem.current == null) return false;
return EventSystem.current.IsPointerOverGameObject();
}
입력 발생 판단을 위해 PlayerInput 내부에 EventSystem.current.IsPointerOverGameObject()를 활용하는 유틸리티 함수를 추가했다.
void Update()
{
// UI에는 이동 안되게
if (EventSystem.current != null && EventSystem.current.IsPointerOverGameObject()) return;
// UI가 아닌 곳을 왼클릭할때 상자 닫히게
if (Input.GetMouseButtonDown(0))
{
if (!EventSystem.current.IsPointerOverGameObject())
{
ChestUIManager.Instance.CloseChestUI();
}
}
...
이를 통해 다음 문제를 해결했다.