3 분 소요

Intro

이번 포스팅에서는

인벤토리 슬롯을 일부만 활성화 시키고, 나머지는 비활성화 시켜놓는 작업과

인벤토리에 아이템을 추가하기위한 밑작업을 해볼예정입니다.

Inventory 클래스

Inventory 클래스는 인벤토리의 전반적인 기능들을 담당할 클래스입니다.

인벤토리에 아이템을 추가하거나 삭제, 아이템의 위치변경 등 주요 기능들을 관리합니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Inventory : MonoBehaviour
{
    public ItemData[] ItemDataArraty;           // 인벤토리의 아이템 데이터 배열

    public int Capacity { get; private set; }   // 인벤토리 수용한도

    [SerializeField] InventoryUI inventoryUI;
    [SerializeField] GameObject inventoryGo;

    private bool inventoryKeydown;              // 인벤토리 키(I)
    private int initCapacity = 24;              // 초기 인벤토리 수용한도
    private int maxCapacity = 36;               // 최대 인벤토리 수용한도

    private void Awake()
    {
        Capacity = initCapacity;
        inventoryUI.SetInventoryRef(this);
    }

    private void Start()
    {
        UpdateAccessibleSlots();
    }

    private void Update()
    {
        inventoryKeydown = Input.GetButtonDown("Inventory");
        SetActiveUI();
    }

    // 인벤토리 UI 활성/비활성화
    private void SetActiveUI()
    {
        if(inventoryKeydown)
        {
            if (inventoryGo.activeSelf)
                inventoryGo.SetActive(false);
            else
                inventoryGo.SetActive(true);
        }

    }

    // 활성화 시킬 슬롯범위 업데이트
    public void UpdateAccessibleSlots()
    {
        inventoryUI.SetAccessibleSlotRange(Capacity);
    }
}


  • 인벤토리 크기는 6X6 이고, 초기에 활성화 시킬 슬롯은 24개로 하였습니다.(나머지는 비활성화)
  • 인벤토리키(I)를 통해 인벤토리를 껐다 켰다 할 수 있습니다.

InventoryUI 클래스

추가되는 내용은 다음과 같습니다.

  1. 게임시작시 인벤토리는 비활성화되도록 하였습니다.

  2. Inventory 클래스가 InventoryUI, ItemSlotUI 클래스를 참조할 수 있도록하는 초기화함수를 추가했습니다.

  3. Inventory 클래스에서 지정한 유효 Capacity 만큼 슬롯을 활성화 시키는 함수를 추가했습니다.

    private void Start()
    {
        HideUI();
    }

    // 인벤토리 UI 비활성화
    private void HideUI()
    {
        this.gameObject.SetActive(false);
    }

    // 인벤토리 참조등록
    public void SetInventoryRef(Inventory inv)
    {
        inventory = inv;
    }

    // 접근 가능한 슬롯 범위 설정(활성화될 슬롯)
    public void SetAccessibleSlotRange(int accessibleSlotCount)
    {
        // 총 36칸 중
        for(int i = 0;i<slotUIList.Count; i++)
        {
            // accessibleCount 갯수 만큼만 슬롯 활성화
            slotUIList[i].SetSlotAccessibleState(i < accessibleCount);
        }
    }

ItemSlotUI

비활성화 슬롯은 마우스 커서가 올라가더라도 하이라이트 효과가 발생하지 않도록 수정했습니다.

// 슬롯 하이라이트 표시 및 해제
    public void Highlight(bool show)
    {
        // 비활성화 슬롯은 무시
        if (!this.IsAccessible) return;

        if (show)
            StartCoroutine(nameof(HighlightFadeIn));
        else
            StartCoroutine(nameof(HighlightFadeOut));
    }


아이템에 아이콘 붙이기

현재 아이템에 대한 정보(무기 아이템)은 WeaponData.json 파일로 작성되어있습니다.

하지만 JSON 파일에서는 Sprite 형태의 정보는 저장할 수 없습니다.

저는 아이템에 아이콘을 매칭시키기 위해서 아이콘 이름을 저장할 필드를 String 으로 만든뒤, 어드레서블 에셋을 활용하여 매칭시켜주는 방법을 사용하기로 했습니다.

image

클래스에 데이터 추가


먼저, ItemData 클래스에 아이템 아이콘 필드를 추가합니다.

/// ItemData.cs ///
[SerializeField] protected string itemIcon;     // 아이템 아이콘 이름

public string ItemIcon => itemIcon;


WeaponItemDTO 클래스 및 WeaponItemData 클래스에도 추가합니다.

/// WeaponItemData.cs ///
public WeaponItemData(WeaponItemDTO dto)
    {
        this.id = dto.id;
        this.itemName = dto.itemName;
        this.itemToolTip = dto.itemToolTip;
        this.itemIcon = dto.itemIcon;
        this.Damage = dto.damage;
        this.Rate = dto.rate;
    }

/// WeaponItemDTO.cs ///
public string itemIcon;             // 아이템 아이콘 이름


어드레서블 에셋 추가

프로젝트에 Sprites 폴더를 만들어 그안에 아이템 아이콘을 넣었습니다.

아이콘을 클릭하여 인스펙터창에서 Addressable 항목을 체크합니다.

Window - Asset Management - Addressables - Group 을 선택하여 Addressable Group 창을 열어줍니다.

image


마우스 우클릭하여 새로운 그룹을 생성해주었습니다. 에셋을 추가한 뒤 그룹아래로 넣어주었습니다.


중요

  1. 에셋을 추가했다면 Build - New Build - Default Build Script 를 눌러 빌드를 갱신해주어야합니다.

  2. 추가한 에셋의 이름을 key로 함수를 호출할것이므로 JSON 파일상의 IconName과 어드레서블 에셋의 이름이 같아야합니다.
    • 확장자(.png, .jpeg, .mp3 등)까지도 같아야합니다.
  3. 리소스의 타입이 Sprite로 되어있는지 확인합니다.

ResourceManager

ResouceManager 클래스는 우선 아이템 아이콘을 Load하여 반환하는 기능을 작성했습니다.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class ResourceManager : MonoBehaviour
{
    // 캐싱해놓을 딕셔너리
    private Dictionary<string, Sprite> cashedSpriteDictionary = new Dictionary<string, Sprite>();

    // 어드레서블 Sprite 경로
    private const string assetRef = "Assets/Sprites/";           
 
    public void LoadIcon(string spriteName, System.Action<Sprite> onLoaded)
    {
        // 캐시에 이미 있을 때
        if (cashedSpriteDictionary.TryGetValue(spriteName, out var cachedSprite))
        {
            onLoaded?.Invoke(cachedSprite);
            return;
        }

        // 어드레서블에서 Sprite 로드(이름으로)
        Addressables.LoadAssetAsync<Sprite>(assetRef + spriteName).Completed += handle =>
        {
            // 성공
            if (handle.Status == AsyncOperationStatus.Succeeded)
            {
                Sprite loadedSprite = handle.Result;
                cashedSpriteDictionary[spriteName] = loadedSprite;   // 딕셔너리에 저장
                onLoaded?.Invoke(loadedSprite);
            }
            // 실패
            else
            {
                Debug.LogError($"다음 Sprite를 가져오는데 실패함. { spriteName }");
                onLoaded?.Invoke(null);
            }
        };
    }

}

테스트해보기

일단 동작하는 지 확인합니다.

버튼을 하나 생성하여 아이콘 이미지를 불러와보도록 했습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ButtonTest : MonoBehaviour
{
    // 테스트용 아이템 id
    int testId = 1001;

    [SerializeField] ResourceManager resourceManager;


    void Start()
    {
        // 아이템 id로 데이터 가져오기
        WeaponItemData data = DataManager.Instance.GetDataById(testId);
        if (data == null)
        {
            Debug.LogError($"Item with ID {testId} not found");
            return;
        }

        Text itemNameText = GetComponentInChildren<Text>();
        Image itemIconImage = GetComponent<Image>();

        // 아이템 이름 설정
        itemNameText.text = data.ItemName;

        // 아이콘 데이터 가져오기
        resourceManager.LoadIcon(data.ItemIcon, sprite =>
        {
            // 성공
            if (sprite != null)
            {
                // 아이콘 설정
                itemIconImage.sprite = sprite;
            }
            else
            {
                Debug.Log($"Failed to load icon for item : {data.ItemIcon}");
            }
        });
    }
}

image


우측 상단 아이콘에 검 이미지가 불러와진것을 확인할 수 있습니다.

이제 인벤토리에 아이템을 추가할 때 아이콘을 불러올 방법이 생겼습니다.

댓글남기기