본문 바로가기

내배켐 Unity TIL

Unity 58일차 TIL - Unity (2D ItemInventory1_SlotUI)

(출처 : https://rito15.github.io/posts/unity-study-rpg-inventory/)

 

위에 링크에 있는 내용을 바탕으로 제작했다.

우선 인벤토리를 제작하기 전에 인벤토리에 들어갈 SlotPrefab을 만든 후 Slot에 들어갈 SlotUI Script를 만든다.

 

SlotPrefab - Hierarchy

구조는 Background Image와 ItemIconImage 그리고 포션 같이 셀 수 있는 아이템이 있는 경우 숫자를 표시해주기 위해서 Text를 넣어주고 셀 수 있는 아이템인 경우 활성화 시켜준다.

HighlightImage는 커서가 Item Slot 위에 있을 때 활성화 시켜주기 위한 용도이다.

 

SlotUI.cs

// 슬롯 내에서 아이콘과 슬롯 사이의 여백
[SerializeField] private float padding = 1f;
// 아이템 아이콘 이미지
[SerializeField] private Image iconImage;
// 아이템 개수 텍스트
[SerializeField] private TextMeshProUGUI amountText;
// 슬롯에 마우스가 있을 때 나타나는 하이라이트 이미지
[SerializeField] private Image highlightImage;
// 하이라이트 이미지 알파 값
[SerializeField] private float highlighAlpha = 0.5f;
// 하이라이트 소요 시간
[SerializeField] private float highlightFadeDuration = 0.2f;

우선 위에 용도에 맞게 사용하기 위해서 IconImage, Text, HighlightImage를 가져와준다.

 

// Slot을 생성할 때 Index에 값을 넣어줘서 사용
public void SetSlotIndex(int slotIndex) => Index = slotIndex;
public int Index { get; private set; }
// 슬롯이 아이템을 보유하고 있는지 여부를 sprite로 확인
public bool HasItem => iconImage.sprite != null;
// 접근 가능한 슬롯인지 여부 확인
public bool IsAccessible => isAccessibleSlot && isAccessibleItem;

public RectTransform SlotRect => slotRect;
public RectTransform IconRect => iconRect;

private RectTransform slotRect;
private RectTransform iconRect;
private RectTransform highlightRect;

private GameObject iconGo;
private GameObject textGo;
private GameObject highlightGo;

private Image slotImage;

private float currentHLAlpa = 0f;

private bool isAccessibleSlot = true;
private bool isAccessibleItem = true;
private bool isNotEqualEquipmentSlot = false;

private static readonly Color InaccessibleSlotColor = new Color(0.2f, 0.2f, 0.2f, 0.5f);
private static readonly Color InaccessibleIconColor = new Color(0.5f, 0.5f, 0.5f, 0.5f);

private void ShowIcon() => iconGo.SetActive(true);
private void HideIcon() => iconGo.SetActive(false);
private void ShowText() => textGo.SetActive(true);
private void HideText() => textGo.SetActive(false);

public 변수로 사용하면서 => 람다식으로 사용하는 경우는 private 변수 값을 직접적으로 접근해서 사용하지 못하게 끔 하기 위해서 그렇게 구현한 것 같다.

 

private void InitComponents()
{
    // Rects
    slotRect = GetComponent<RectTransform>();
    iconRect = iconImage.rectTransform;
    highlightRect = highlightImage.rectTransform;

    // GameObjects
    iconGo = iconRect.gameObject;
    textGo = amountText.gameObject;
    highlightGo = highlightImage.gameObject;

    // Images
    slotImage = GetComponent<Image>();
}

private void InitValue()
{
    iconRect.pivot = new Vector2(0.5f, 0.5f);
    iconRect.anchorMin = Vector2.zero;
    iconRect.anchorMax = Vector2.one;

    iconRect.offsetMin = Vector2.one * (padding);
    iconRect.offsetMax = Vector2.one * (-padding);

    // icon 과 highlight 크기 동일하도록 설정
    highlightRect.pivot = iconRect.pivot;
    highlightRect.anchorMin = iconRect.anchorMin;
    highlightRect.anchorMax = iconRect.anchorMax;
    highlightRect.offsetMin = iconRect.offsetMin;
    highlightRect.offsetMax = iconRect.offsetMax;

    // Image
    iconImage.raycastTarget = false;
    highlightImage.raycastTarget = false;

    // Icon
    HideIcon();
    highlightGo.SetActive(false);
}

Awake 함수에서 호출해주는 초기화 함수들이다.

 

// 슬롯 자체의 활성화 / 비활성화 여부 설정
public void SetSlotsAccessibleState(bool value)
{
    // 중복 처리 지양
    if (isAccessibleSlot == value) return;

    if (value)
    {
        slotImage.color = Color.black;
    }
    else
    {
        slotImage.color = InaccessibleSlotColor;
        HideIcon();
        HideText();
    }

    isAccessibleSlot = value;
}

// 아이템 활성화 / 비활성화 여부 설정
public void SetItemAccessibleState(bool value)
{
    if (isAccessibleItem == value) return;

    if (value)
    {
        iconImage.color = Color.white;
        amountText.color = Color.white;
    }
    else
    {
        iconImage.color = InaccessibleIconColor;
        amountText.color = InaccessibleIconColor;
    }

    isAccessibleItem = value;
}

Slot들을 만들어두고서 일정 부분을 비활성화 하고 싶을 때, 또 비활성화 해둔 부분을 다시 활성화 해줄 때 사용할 수 있다.

나중에 Inventory UI에서 연결해서 사용할 예정이다. 그리고 아이템 또한 활성화 / 비활성화 여부를 설정할 수 있게 끔 만들었지만 난 사용하지 않았다.

 

// InventoryUIDragAndDrop.cs에서 사용될 함수
public void SwapOrMoveIcon(ItemSlotUIs other)
{
    if (other == null || other == this) return;
    if (!this.IsAccessible || !other.IsAccessible) return;

    // 현재 Icon Image를 저장해둠
    var temp = iconImage.sprite;

    // 드랍한 곳에 아이템이 있는 경우 : 교환
    if (other.HasItem)
        SetItem(other.iconImage.sprite);
    // 없는 경우 : 이동
    else
        RemoveItem();
    
    // 교환한 곳에 Icon Image를 현재 Icon Image로 전환
    other.SetItem(temp);
    other.SetEquipmentItemData(data);
}

// InventoryUI.cs에서도 사용될 함수
public void SetItem(Sprite itemSprite)
{
    if (itemSprite != null)
    {
        iconImage.sprite = itemSprite;
        ShowIcon();
    }
    else
        RemoveItem();
}

// InventoryUI.cs에서도 사용될 함수
public void RemoveItem()
{
    iconImage.sprite = null;
    HideIcon();
    HideText();
}

 

나중에 InventoryUIDragAndDrop.cs 에서 Slot에 아이템을 Drag And Drop 할 때 사용할 함수이다.

함수에서 매개변수로 받는 other는 Drop하는 위치에 ItemSlotUIs이다.

 

// InventoryUIDragAndDrop.cs에서 사용할 함수

public void Highlight(bool show)
{
    if (!this.IsAccessible) return;

    if (show)
        FadeIn();
    else
        FadeOut();

    void FadeIn()
    {
        while (true)
        {
            highlightGo.SetActive(true);

            float unit = highlighAlpha / highlightFadeDuration;

            for (; currentHLAlpa <= highlighAlpha; currentHLAlpa += unit * Time.deltaTime)
            {
                highlightImage.color = new Color(highlightImage.color.r, highlightImage.color.g, highlightImage.color.b, currentHLAlpa);
            }
            break;
        }
    }

    void FadeOut()
    {
        while (true)
        {
            float unit = highlighAlpha / highlightFadeDuration;

            for (; currentHLAlpa >= 0; currentHLAlpa -= unit * Time.deltaTime)
            {
                highlightImage.color = new Color(highlightImage.color.r, highlightImage.color.g, highlightImage.color.b, currentHLAlpa);
            }

            highlightGo.SetActive(false);
            break;
        }
    }
}

public void SetHighlightOnTop(bool value)
{
    if (value)
        highlightRect.SetAsLastSibling();
    else
        highlightRect.SetAsFirstSibling();
}

// InventoryUI에서 사용할 함수
public void SetItemAmount(int amount)
{
    if (HasItem && amount > 1)
        ShowText();
    else
        HideText();

    amountText.text = amount.ToString();
}

 - Highlight 함수

IsAccessible은 아까 위에서 Slot과 Item에 활성화 / 비활성화 여부에 따라서 변경되게 된다.

 

원래 기존 코드에서는 Coroutine으로 FadeIn과 FadeOut 함수 부분을 수행했지만 딱히 별 차이점을 못 느끼겠어서 그냥 while로 수정해뒀다.

만약에 while로 사용할 것이라면 굳이 저렇게 쓰기보다는 아래와 같이 한 줄로 사용하는 것이 좋을 것 같다.

highlightImage.color = new Color(highlightImage.color.r, highlightImage.color.g, highlightImage.color.b, highlighAlpha);

 

- SetHighlightOnTop 함수

뒤에 SetAsLastSibiling과 SetAsFirstSibling은 Transform이나 RectTransform에서 사용할 수 있는 함수이다.

Hierarchy 창에서 순서를 바꿔줘 HighlightImage UI가 보이거나 보이지 않게 만들어 줄 수 있다.