내일배움캠프 31일차 TIL <Unity 아이템 창 만들기> 05/21

정광훈(Unity_9기)·2025년 5월 21일

TIL (Today I Learned)

목록 보기
41/110
post-thumbnail

개인 프로젝트 진행 중 인벤토리 만드는 게 있었는데
강의에서 만들었던 인벤토리보다
화면 아래에 상시로 아이템 창이 보이게 하고 싶었다.

기본적으로 강의를 따라했다.
소비 아이템을 장착한 것처럼 오른손에 든 것처럼 보이게 하고 싶었는데
장착 여부 로직 때문에 많이 꼬이고 문제가 많이 생겼다.

아이템 장착시 아웃라인으로 표시하고 싶었는데 포기하고
다시 돌아가 탭을 눌러 선택 중인 아이템 슬롯에 아웃라인이 뜨게 하는 작업부터 했다.

아이템을 먹으면 슬롯에 아이콘과 개수가 생기며 다 사용하면
슬롯에서 아이콘이 삭제되게 만들었다.


<class PlayerController>

    public void OnUse(InputAction.CallbackContext context) // 아이템 사용(마우스 좌클릭)
    {
        if (context.phase == InputActionPhase.Started)
        {
            if (uiInven != null && uiInven.selectedItem != null) // 인벤토리와 선택한 아이템이 존재할 때
            {
                for (int i = 0; i < uiInven.selectedItem.consumables.Length; i++)
                {
                    switch (uiInven.selectedItem.consumables[i].type) // 소모 아이템 타입에 따른 조건문
                    {
                        case ConsumableType.Jump:
                            condition.JumpUp(uiInven.selectedItem.consumables[i].value);
                            break;
                        //case ConsumableType.Health:
                        //    condition.Heal(uiInven.selectedItem.consumables[i].value);
                        //    break;
                    }
                }

                uiInven.RemoveSelectedItem(); // 사용 시 아이템 제거
            }
        }
    }

    public void OnSelectItem(InputAction.CallbackContext context) // 인벤토리 슬롯 스위치(탭)
    {
        if (context.phase == InputActionPhase.Started)
        {
            // (uiInventory.selectedItemIndex + 1)이 uiInven.slots.Length와 같아질 때 다시 0으로 초기화 시킴
            int Index = (uiInven.selectedIndex + 1) % uiInven.slots.Length;

            uiInven.SelectedSlot(Index);
            Debug.Log("현재 선택된 슬롯 인덱스: " + uiInven.selectedIndex);
        }
    }

<class ItemSlot>

    private void Awake()
    {
        outline = GetComponent<Outline>();
    }

    private void OnEnable()
    {
        // 모든 아웃라인 비활성화
        if (outline != null)
        {
            outline.enabled = false;
        }
    }

    public void Set()
    {
        icon.gameObject.SetActive(true);
        icon.sprite = item.icon;
        quantityText.text = quantity > 0 ? quantity.ToString() : string.Empty; // 개수 표시

        // 아이템이 설정될 때 아웃라인은 항상 비활성화 상태로 시작
        if (outline != null)
        {
            outline.enabled = false;
        }
    }

    public void Clear()
    {
        icon.gameObject.SetActive(false);
        item = null;
        quantityText.text = string.Empty;

        if (outline != null)
        {
            outline.enabled = false;
        }
    }

    public void SetOutlineActive(bool isActive) // 활성화를 선택하는 메서드
    {
        if (outline != null)
        {
            outline.enabled = isActive;
        }
    }
}

<class UIInventory>

    private void Awake()
    {
        if (CharacterManager.Instance != null && CharacterManager.Instance.Player != null)
        {
            controller = CharacterManager.Instance.Player.controller;
            condition = CharacterManager.Instance.Player.condition;
            dropPosition = CharacterManager.Instance.Player.dropPosition;

            // CharacterManager의 AddItem 이벤트 구독
            CharacterManager.Instance.Player.addItem += AddItem;
        }

        if (slots != null)
        {
            // 아이템 슬롯 칸을 slotPanel 오브젝트의 자식의 개수를 불러옴
            slots = new ItemSlot[slotPanel.childCount];

            for (int i = 0; i < slots.Length; i++)
            {
                Transform child = slotPanel.GetChild(i);
                if (child != null)
                {
                    // 슬롯판넬의 자식오브젝트 아이템 슬롯 컴포넌트를 가져와 저장
                    slots[i] = child.GetComponent<ItemSlot>();

                    if (slots[i] != null)
                    {
                        slots[i].index = i;
                        slots[i].inventory = this;

                        // 모든 슬롯의 아웃라인을 기본적으로 비활성화
                        slots[i].SetOutlineActive(false);
                    }
                    else
                    {
                        Debug.LogWarning($"Slot {i} under {slotPanel.name} does not have an ItemSlot component.");
                        slots[i] = null; // null이 들어가지 않도록 명시적으로 null 할당
                    }
                }
            }
        }
        else
        {
            Debug.LogError("slotPanel is not assigned in UIInventory. Please assign it in the Inspector.");
            slots = new ItemSlot[0]; // NullReferenceException 방지를 위해 빈 배열로 초기화
        }
    }

    // Start is called before the first frame update
    void Start()
    {
        if (slots.Length > 0)
        {
            // 게임 시작 시 0번 슬롯 (첫 번째 슬롯) 선택 및 아웃라인 활성화
            SelectedSlot(0);
        }
    }

    void AddItem()
    {
        ItemData data = CharacterManager.Instance.Player.itemData;

        // 중복 가능한지 - 혹시나 해서 만들음
        if (data.canStack)
        {
            ItemSlot slot = GetItemStack(data);
            // 비어있는 슬롯 가져옴
            if (slot != null)
            {
                slot.quantity++;
                UpdateUI();
                CharacterManager.Instance.Player.itemData = null;
                return;
            }
        }

        // 비어 있는 슬롯 가져옴
        ItemSlot emptySlot = GetEmptySlot();

        // 플레이어에 있는 아이템 데이터를 비움
        CharacterManager.Instance.Player.itemData = null;

        if (emptySlot != null)
        {
            emptySlot.item = data;
            emptySlot.quantity = 1;
            UpdateUI();
            CharacterManager.Instance.Player.itemData = null;
            return;
        }

        //없다면 아이템 버림
        ThrowItem(data);
        CharacterManager.Instance.Player.itemData = null;
    }

    void UpdateUI()
    {
        for (int i = 0; i < slots.Length; i++)
        {
            if (slots[i].item != null)
            {
                // 해당 슬롯에 템 있을 때
                slots[i].Set(); // 아이템 세팅
            }
            else
            {
                // 해당 슬롯 비움
                slots[i].Clear();
            }
        }
    }
    
    public void SelectedSlot(int index)
    {
        // 이전에 슬롯의 아웃라인을 비활성화
        if (selectedIndex >= 0 && selectedIndex < slots.Length && slots[selectedIndex] != null)
        {
            slots[selectedIndex].SetOutlineActive(false);
        }

        selectedIndex = index;

        if (selectedIndex >= 0 && selectedIndex < slots.Length && slots[selectedIndex] != null)
        {
            slots[selectedIndex].SetOutlineActive(true);
            selectedItem = slots[selectedIndex].item; // 선택된 아이템 정보도 업데이트
        }
        else
        {
            selectedItem = null; // 유효하지 않은 인덱스인 경우 선택된 아이템 초기화
        }
    }

아웃라인을 기본적으로 다 비활성화시키고 시작할 때
현재 선택된 슬롯에 아웃라인이 활성화 되도록 코드를 수정하였다.

0개의 댓글