Chapter 5-2. 인벤토리 : 인벤토리 구현, Grid Layout Group
카테고리: Unity Lesson 3
태그: Unity Game Engine
인프런에 있는 케이디님의 [유니티 3D] 실전! 생존게임 만들기 - Advanced 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click
Chapter 5. 인벤토리
🚖 인벤토리 UI 만들기
위와 같은 인벤 토리를 만들어 볼 것이다.
필요한 Sprite
- 인벤토리 배경이 될 이미지
- 아이템 슬롯들이 이 위에 배치된다.
Inventory_Base
- 인벤토리의 슬롯 하나의 배경이 될 이미지
- 슬롯에 아이템이 들어오면 이 위에 아이템 이미지가 올라갈 것이다.
Slot
- 슬롯마다 아이템 개수를 표시할 이미지
- 이 이미지 위에 아이탬 갯수 숫자 텍스트를 표시할 것이다.
Item_Count_Image
위 3 가지 이미지의 Max Size를 알맞게 수정하고 Texture Type을 Sprite(2D and UI)로 만들어 Sprite 로 만든다.
인벤토리 UI 구조
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 수정은 불가능해진다.
- Cell Size
- 격자 한칸 당 크기
- 모든 자식 오브젝트의 크기가 이 사이즈로 정해진다.
- 2️⃣ 슬롯 배경 이미지의 사이즈와 동일하게 66 X 66
- 격자 한칸 당 크기
- Spacing
- X, Y축 간의 간격
- Y 에 15 값을 주어 세로 간격, 즉 한 줄의 간격을 15 로 하였다.
- Start Corner
- Upper Left
- Grid Layout Component 컴포넌트가 현재 붙어 있는 이 부모 오브젝트의 왼쪽 윗부분을 시작 코너로 하여 여기를 시작점으로 자식 오브젝트들을 배치하기 시작
- Upper Left
- Start Axis
- Horizontal
- 수평 👉 방향으로 자식 오브젝트들을 차례로 배치
- Horizontal
- Child Alignment
- Upper Center
- 자식 오브젝트들을 윗부분 정렬 + 가운데 정렬
- Start Corner을 기준으로 하여 정렬
- Upper Center
- Constraint
- 행이나 열을 특정 수로 제한할 때 사용한다.
- Fixed Column Count
- 열을 10 으로 제한 해주어 한 줄에 열개가 채워지면 자동으로 줄이 바뀌게 하였다.
Slot 의 구조
Slot
- 2️⃣ 슬롯 배경 이미지
- 🟦 프리팹으로 만들어 20개 추가했다.
- 인벤토리에 20 종류의 아이템이 들어갈 수 있도록
Slot
들은 부모인Grid Setting
의 Grid Layout Component 컴포넌트에 의해 배치된다.- 슬롯 하나를 추가 하고 삭제하는 기능을 가지는 📜Slot.cs 가 붙을 것.
Item_Image
- 슬롯에 아이템이 들어오면 할당될 아이템 이미지.
Slot
의 자식으로서 슬롯 배경 이미지 위에 그려지게 된다.
- 컬러 값을 알파 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
타입으로서 가져옴
- 아이탬 개수 이미지를 게임 중 비활성화/활성화 하기 위하여
- private GameObject go_CountImage
- 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_Count
는go_CountImage
의 자식이기 때문에go_CountImage
을 먼저 비활성화 하면text_Count
도 비활성화 되서 text_Count.text 을 실행할 때 에러가 발생한다.go_CountImage.SetActive(false); text_Count.text = "0";
- 무기는 아이템 개수를 표시하지 않을 것!
- 불투명하게 바꿔 아이템 이미지를 그린다.
- SetColor(1)
- 아이템, 아이템 이미지 Sprite, 아이템 개수
- 👉 해당 슬롯에 새로운 아이템 추가 (슬롯에 아이템 없는 상태였다가 처음으로 들어오는 것일 때)
- SetSlotCount(int _count)
- 👉 해당 슬롯의 아이탬 갯수 업데이트 (이미 있는 아이템을 또 추가했을 땐 갯수를 업데이트)
- 갯수 더해주기
- 텍스트 업데이트
- 아이템이 하나도 없을 땐 해당 슬롯을 삭제해야 한다.
- ClearSlot()
- 👉 해당 슬롯 하나를 삭제한다.
- 아이템 이미지 초기화
- 투명도는 다시 0 으로 투명하게
- 3️⃣ 슬롯마다 아이템 개수를 표시할 이미지를 비활성화
- 👉 해당 슬롯 하나를 삭제한다.
- ClearSlot()
- 👉 해당 슬롯의 아이탬 갯수 업데이트 (이미 있는 아이템을 또 추가했을 땐 갯수를 업데이트)
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;
}
}
}
}
- UI든 뭐든 게임 도중 비활성화/활성화 시킬 오브젝트는
GameObject
타입으로서 가져와야 한다.- private GameObject go_InventoryBase;
- 인벤토리 베이스 이미지 UI를 게임 중
I
키를 통하여 비활성화/활성화 하기 위하여GameObject
타입으로서 가져옴- SetActive
- 인벤토리 베이스 이미지 UI를 게임 중
- private GameObject go_InventoryBase;
- Start()
- 슬롯들
slots
배열에 할당- GetComponentsInChildren 을 사용하여 자식들 중에
Slot
인 애들을 모두 찾아 배열로 할당해준다.
- GetComponentsInChildren 을 사용하여 자식들 중에
- 슬롯들
- TryOpenInventory()
- 👉 매 프레임마다
I
키 입력을 검사한다.I
키가 들어 오면invectoryActivated
값 반전 시킨다.I
키를 누르면 인벤토리가 켜지고 다시 누르면 인벤토리가 꺼지게끔!
invectoryActivated
가 True면 인벤토리 열기- OpenInventory()
- 👉
Inventory_Base
인벤토리 활성화
- 👉
- CloseInventory()
- 👉
Inventory_Base
인벤토리 비활성화
- 👉
- OpenInventory()
- 👉 매 프레임마다
- AcquireItem(Item _item, int _count = 1)
- 👉 아이템 습득하기
- 같은 종류의 아이템이 이미 있는지를 검사한다. 있다면 아이템 갯수를 더해 주기 위하여.
- 무기가 아닌 경우에만 진행한다. 인벤토리에서의 무기는 아이템 갯수를 표시해주지 않을 것이기 떄문에.
- 같은 종류의 아이템 슬롯을 인벤토리에서 찾았다면(이름이 같다면)
- 해당 슬롯의 아이탬 갯수 업데이트 한다. 해당 슬롯의 📜Slot.cs SetSlotCount 호출
return
- 같은 종류의 아이템이 없다면 아이템을 저장할 새로운 슬롯을 마련해야 한다.
- 빈 슬롯을 찾는다.
- 빈 슬롯을 찾았다면 📜Slot.cs AddItem 호출
- 해당 슬롯에 새로운 아이템 추가 (슬롯에 아이템 없는 상태였다가 처음으로 들어오는 것일 때)
return
- 빈 슬롯을 찾았다면 📜Slot.cs AddItem 호출
- 빈 슬롯을 찾는다.
- 같은 종류의 아이템이 이미 있는지를 검사한다. 있다면 아이템 갯수를 더해 주기 위하여.
- 👉 아이템 습득하기
📜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)
theInventory
에 📜Inventory.cs 할당
🚔 테스트
📜ItemPickUp 과 Item 태그와 레이어 설정이 완료 된 서브 머신건을 주우려 할 때!
무기는 갯수가 표시되지 않고, 일반 아이템은 갯수가 표시된다.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기