Chapter 5-2. 인벤토리 : 인벤토리 구현, Grid Layout Group

Date:     Updated:

카테고리:

태그:

인프런에 있는 케이디님의 [유니티 3D] 실전! 생존게임 만들기 - Advanced 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click

Chapter 5. 인벤토리

🚖 인벤토리 UI 만들기

image

위와 같은 인벤 토리를 만들어 볼 것이다.

필요한 Sprite

image

  1. 인벤토리 배경이 될 이미지
    • 아이템 슬롯들이 이 위에 배치된다.
    • Inventory_Base
  2. 인벤토리의 슬롯 하나의 배경이 될 이미지
    • 슬롯에 아이템이 들어오면 이 위에 아이템 이미지가 올라갈 것이다.
    • Slot
  3. 슬롯마다 아이템 개수를 표시할 이미지
    • 이 이미지 위에 아이탬 갯수 숫자 텍스트를 표시할 것이다.
    • Item_Count_Image

위 3 가지 이미지의 Max Size를 알맞게 수정하고 Texture Type을 Sprite(2D and UI)로 만들어 Sprite 로 만든다.


인벤토리 UI 구조

image

Inventory

  • 빈 오브젝트. 단순히 인벤토리와 관련된 UI 를 묶어주는 역할.
  • 📜Inventory.cs 가 여기에 붙게 될 것.
  • 따라서 활성화 상태


Inventroy_Base

  • 1️⃣ 인벤토리 배경 이미지
    • Source Image에 할당
    • 적절한 위치에 배치하고 크기 동일하게 맞품
  • 비활성화 해둔다.
    • 그 아래 자식들도 자동으로 모두 비활성화 된다.
    • 평소엔 안보이게 하다가 I 키 입력이 들어올 때만 활성화 할 것이라서
      • 따라서 위와 같은 기능을 할 📜Inventory.cs 가 여기에 붙어 버리면 아예 동작하지 않는다. 처음부터 비활성화 되있는 오브젝트라.


Grid Setting

  • 슬롯들을 배경 이미지 위에 격자 방식으로 정렬하는 것을 도와줄 Grid Layout Component 컴포넌트를 추가해준다.
Grid Layout Component 컴포넌트

👉 이 컴포넌트가 붙는 Grid Setting 오브젝트의 자식들인 Slot 오브젝트들을 부모인 자신을 기준으로 하여 Grid 로 관리할 수 있다.

  • 자식 오브젝트들은 부모 오브젝트에 붙은 Grid Layout Component 컴포넌트 설정을 통해 알아서 자동으로 위치가 정해지고 크기가 정해진다.
    • 따라서 자식 오브젝트의 Rect Transform 수정은 불가능해진다.

image

  • Cell Size
    • 격자 한칸 당 크기
      • 모든 자식 오브젝트의 크기가 이 사이즈로 정해진다.
    • 2️⃣ 슬롯 배경 이미지의 사이즈와 동일하게 66 X 66
  • Spacing
    • X, Y축 간의 간격
    • Y 에 15 값을 주어 세로 간격, 즉 한 줄의 간격을 15 로 하였다.
  • Start Corner
    • Upper Left
      • Grid Layout Component 컴포넌트가 현재 붙어 있는 이 부모 오브젝트의 왼쪽 윗부분을 시작 코너로 하여 여기를 시작점으로 자식 오브젝트들을 배치하기 시작
  • Start Axis
    • Horizontal
      • 수평 👉 방향으로 자식 오브젝트들을 차례로 배치
  • Child Alignment
    • Upper Center
      • 자식 오브젝트들을 윗부분 정렬 + 가운데 정렬
      • Start Corner을 기준으로 하여 정렬
  • Constraint
    • 행이나 열을 특정 수로 제한할 때 사용한다.
    • Fixed Column Count
      • 열을 10 으로 제한 해주어 한 줄에 열개가 채워지면 자동으로 줄이 바뀌게 하였다.

image


Slot 의 구조

image

  • Slot
    • 2️⃣ 슬롯 배경 이미지
    • 🟦 프리팹으로 만들어 20개 추가했다.
      • 인벤토리에 20 종류의 아이템이 들어갈 수 있도록
    • Slot들은 부모인 Grid Setting의 Grid Layout Component 컴포넌트에 의해 배치된다.
    • 슬롯 하나를 추가 하고 삭제하는 기능을 가지는 📜Slot.cs 가 붙을 것.
Item_Image
  • 슬롯에 아이템이 들어오면 할당될 아이템 이미지.
  • Slot의 자식으로서 슬롯 배경 이미지 위에 그려지게 된다.

image

  • 컬러 값을 알파 0 으로 하여 투명하게 만든다.
    • 👉 아이템이 아직 할당하지 않은 상태라면 슬롯 배경 이미지만 보여야 하는데, 아이템이 아직 안들어와 아이템 이미지가 null인 상태면 위와 같이 하얀 이미지로 떠서 슬롯 배경 이미지를 가리기 때문이다.
    • 따라서 평소엔 투명하게 만들어 주고 해당 슬롯에 아이템이 들어올 때만 불투명하게 바꾸도록 한다.
Item_Count_Image
  • 3️⃣ 슬롯마다 아이템 개수를 표시할 이미지
    • 비활성화 상태가 디폴트
      • 아이템이 해당 슬롯에 들어와있을 때만 보여야 한다.
Item_Count_Text
  • 슬롯마다 아이템 개수를 표시할 이미지 위에서 슬롯마다 아이템 개수를 표시할 텍스트


🚖 인벤토리에 아이템 추가하고 활성화하기

📜Slot.cs

Slot 프리팹에 붙인다. 슬롯 1 개에 대한 관리.

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

public class Slot : MonoBehaviour
{
    public Item item; // 획득한 아이템
    public int itemCount; // 획득한 아이템의 개수
    public Image itemImage;  // 아이템의 이미지

    [SerializeField]
    private Text text_Count;
    [SerializeField]
    private GameObject go_CountImage;

    // 아이템 이미지의 투명도 조절
    private void SetColor(float _alpha)
    {
        Color color = itemImage.color;
        color.a = _alpha;
        itemImage.color = color;
    }

    // 인벤토리에 새로운 아이템 슬롯 추가
    public void AddItem(Item _item, int _count = 1)
    {
        item = _item;
        itemCount = _count;
        itemImage.sprite = item.itemImage;

        if(item.itemType != Item.ItemType.Equipment)
        {
            go_CountImage.SetActive(true);
            text_Count.text = itemCount.ToString();
        }
        else
        {
            text_Count.text = "0";
            go_CountImage.SetActive(false);
        }

        SetColor(1);
    }

    // 해당 슬롯의 아이템 갯수 업데이트
    public void SetSlotCount(int _count)
    {
        itemCount += _count;
        text_Count.text = itemCount.ToString();

        if (itemCount <= 0)
            ClearSlot();
    }

    // 해당 슬롯 하나 삭제
    private void ClearSlot()
    {
        item = null;
        itemCount = 0;
        itemImage.sprite = null;
        SetColor(0);

        text_Count.text = "0";
        go_CountImage.SetActive(false);
    }
}

  • UI든 뭐든 게임 도중 비활성화/활성화 시킬 오브젝트는 GameObject 타입으로서 가져와야 한다.
    • private GameObject go_CountImage
      • 아이탬 개수 이미지를 게임 중 비활성화/활성화 하기 위하여 GameObject 타입으로서 가져옴
  • SetColor(float _alpha)
    • 👉 아이템 이미지의 투명도를 조절한다.
      • 아이템이 아직 없는 슬롯이라면 아이템 이미지 Item_Image의 현재 Sprite 이미지도 할당 되어 있지 않고 투명도가 0 으로 되어 있는 상태기 때문에 아이템이 해당 슬롯에 추가 되면 투명도를 다시 불투명하게 올려주어야 해서 필요하다.
  • AddItem(Item _item, int _count = 1)
    • 👉 해당 슬롯에 새로운 아이템 추가 (슬롯에 아이템 없는 상태였다가 처음으로 들어오는 것일 때)
      • 아이템, 아이템 이미지 Sprite, 아이템 개수
        • 인수들로 item, itemCount, itemImage.sprite 할당
        • 📜Item.cs 에서 itemImage을 Sprite로 설정했었다.
      • 들어온 아이템이 무기가 아닐 때
        • 3️⃣ 슬롯마다 아이템 개수를 표시할 이미지를 활성화 한다.
        • 아이템 개수 텍스트를 itemCount로 설정
      • 들어온 아이템이 무기일 때
        • 무기는 아이템 개수를 표시하지 않을 것!
          • 3️⃣ 슬롯마다 아이템 개수를 표시할 이미지를 비활성화 한다.
          • 아래와 같이 순서를 바꾸면 런타임 에러가 발생한다 text_Countgo_CountImage의 자식이기 때문에 go_CountImage을 먼저 비활성화 하면 text_Count도 비활성화 되서 text_Count.text 을 실행할 때 에러가 발생한다.
            go_CountImage.SetActive(false);
            text_Count.text = "0";  
            
      • 불투명하게 바꿔 아이템 이미지를 그린다.
        • SetColor(1)
  • SetSlotCount(int _count)
    • 👉 해당 슬롯의 아이탬 갯수 업데이트 (이미 있는 아이템을 또 추가했을 땐 갯수를 업데이트)
      • 갯수 더해주기
      • 텍스트 업데이트
      • 아이템이 하나도 없을 땐 해당 슬롯을 삭제해야 한다.
        • ClearSlot()
          • 👉 해당 슬롯 하나를 삭제한다.
            • 아이템 이미지 초기화
            • 투명도는 다시 0 으로 투명하게
            • 3️⃣ 슬롯마다 아이템 개수를 표시할 이미지를 비활성화

image

  • item 👉 게임 중에 할당 될 아이템 (ScripableObject)
  • itemCount 👉 게임 중에 할당 됨
  • itemImage 👉 슬롯의 자식인 Item_Image UI 이미지 할당
  • text_Count 👉 슬롯의 자식인 Item_Count_Text UI 텍스트 할당
  • go_Count_Image 👉 슬롯의 자식인 Item_Count_Image UI 이미지 할당


📜Inventory.cs

Inventory에 붙는다. 인벤토리 최고 부모..

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

public class Inventory : MonoBehaviour
{
    public static bool invectoryActivated = false;  // 인벤토리 활성화 여부. true가 되면 카메라 움직임과 다른 입력을 막을 것이다.

    [SerializeField]
    private GameObject go_InventoryBase; // Inventory_Base 이미지
    [SerializeField] 
    private GameObject go_SlotsParent;  // Slot들의 부모인 Grid Setting 

    private Slot[] slots;  // 슬롯들 배열

    void Start()
    {
        slots = go_SlotsParent.GetComponentsInChildren<Slot>();
    }

    void Update()
    {
        TryOpenInventory();
    }

    private void TryOpenInventory()
    {
        if(Input.GetKeyDown(KeyCode.I))
        {
            invectoryActivated = !invectoryActivated;

            if (invectoryActivated)
                OpenInventory();
            else
                CloseInventory();

        }
    }

    private void OpenInventory()
    {
        go_InventoryBase.SetActive(true);
    }

    private void CloseInventory()
    {
        go_InventoryBase.SetActive(false);
    }

    public void AcquireItem(Item _item, int _count = 1)
    {
        if(Item.ItemType.Equipment != _item.itemType)
        {
            for (int i = 0; i < slots.Length; i++)
            {
                if (slots[i].item != null)  // null 이라면 slots[i].item.itemName 할 때 런타임 에러 나서
                {
                    if (slots[i].item.itemName == _item.itemName)
                    {
                        slots[i].SetSlotCount(_count);
                        return;
                    }
                }
            }
        }

        for (int i = 0; i < slots.Length; i++)
        {
            if (slots[i].item == null)
            {
                slots[i].AddItem(_item, _count);
                return;
            }
        }
    }
}

image

  • UI든 뭐든 게임 도중 비활성화/활성화 시킬 오브젝트는 GameObject 타입으로서 가져와야 한다.
    • private GameObject go_InventoryBase;
      • 인벤토리 베이스 이미지 UI를 게임 중 I키를 통하여 비활성화/활성화 하기 위하여 GameObject 타입으로서 가져옴
        • SetActive
  • Start()
    • 슬롯들 slots 배열에 할당
      • GetComponentsInChildren 을 사용하여 자식들 중에 Slot인 애들을 모두 찾아 배열로 할당해준다.
  • TryOpenInventory()
    • 👉 매 프레임마다 I키 입력을 검사한다. I키가 들어 오면
      • invectoryActivated 값 반전 시킨다.
        • I키를 누르면 인벤토리가 켜지고 다시 누르면 인벤토리가 꺼지게끔!
      • invectoryActivated가 True면 인벤토리 열기
        • OpenInventory()
          • 👉 Inventory_Base 인벤토리 활성화
        • CloseInventory()
          • 👉 Inventory_Base 인벤토리 비활성화
  • AcquireItem(Item _item, int _count = 1)
    • 👉 아이템 습득하기
      • 같은 종류의 아이템이 이미 있는지를 검사한다. 있다면 아이템 갯수를 더해 주기 위하여.
        • 무기가 아닌 경우에만 진행한다. 인벤토리에서의 무기는 아이템 갯수를 표시해주지 않을 것이기 떄문에.
        • 같은 종류의 아이템 슬롯을 인벤토리에서 찾았다면(이름이 같다면)
          • 해당 슬롯의 아이탬 갯수 업데이트 한다. 해당 슬롯의 📜Slot.cs SetSlotCount 호출
          • return
      • 같은 종류의 아이템이 없다면 아이템을 저장할 새로운 슬롯을 마련해야 한다.
        • 빈 슬롯을 찾는다.
          • 빈 슬롯을 찾았다면 📜Slot.cs AddItem 호출
            • 해당 슬롯에 새로운 아이템 추가 (슬롯에 아이템 없는 상태였다가 처음으로 들어오는 것일 때)
          • return


📜ActionController.cs


    [SerializeField]
    private Inventory theInventory;  // 📜Inventory.cs

    private void CanPickUp()
    {
        if(pickupActivated)
        {
            if(hitInfo.transform != null)
            {
                Debug.Log(hitInfo.transform.GetComponent<ItemPickUp>().item.itemName + " 획득 했습니다.");
                theInventory.AcquireItem(hitInfo.transform.GetComponent<ItemPickUp>().item);
                Destroy(hitInfo.transform.gameObject);
                ItemInfoDisappear();
            }
        }
    }
theInventory.AcquireItem(hitInfo.transform.GetComponent<ItemPickUp>().item);

아이템을 주우면 📜Inventory.cs의 AcquireItem 함수를 호출하여 아이템을 인벤토리 슬롯에 업데이트 한다. 아이템마다 붙어 있는 📜ItemPickUp의 item 을 인수로 넘김. (ScriptableObject)

image

theInventory에 📜Inventory.cs 할당


🚔 테스트

image

📜ItemPickUp 과 Item 태그와 레이어 설정이 완료 된 서브 머신건을 주우려 할 때!

image

무기는 갯수가 표시되지 않고, 일반 아이템은 갯수가 표시된다.



🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Unity Lesson 3 카테고리 내 다른 글 보러가기

댓글 남기기