이제 인벤토리 UI는 얼추 만들었으니 플레이어가 아이템을 먹으면 해당 아이템이 인벤토리 UI에 나타나도록 해주는 작업을 해주려고 한다.
🥕 예행 작업 1. Script 생성 (Slot)
우선 드랍한 아이템을 획득하면
드랍한 아이템의 Image가 인벤토리 UI에 나타나도록 하고
인벤토리 UI 내에서 버튼을 클릭하면 아이템이 사용되는 로직을 구현해 주겠다.
using UnityEngine;
using UnityEngine.UI;
public class Slot : MonoBehaviour
{
private IItemObject item; // 슬롯에 들어올 아이템
[SerializeField] private Image itemImage; // 먹은 아이템의 이미지가 들어갈 위치
[SerializeField] private Button slotButton; // 아이템 Use()를 하기 위한 버튼
public bool isEmpty = true;
void Awake()
{
slotButton.onClick.AddListener(UseItem);
}
void OnEnable() // 오브젝트가 On될 때마다 1번 실행되는 기능
{
slotButton.interactable = !isEmpty;
itemImage.gameObject.SetActive(!isEmpty);
}
public void AddItem(IItemObject newItem)
{
item = newItem;
isEmpty = false;
itemImage.sprite = newItem.Icon;
itemImage.SetNativeSize();
slotButton.interactable = !isEmpty;
itemImage.gameObject.SetActive(!isEmpty);
}
public void UseItem()
{
if (item != null)
{
item.Use();
ClearSlot();
}
}
public void ClearSlot()
{
item = null;
isEmpty = true;
slotButton.interactable = !isEmpty;
itemImage.gameObject.SetActive(!isEmpty);
}
}
어제 IItemObject 인터페이스를 구현할 때 Get()과 Use() 함수를 만들어 두었는데
이는 인벤토리에 들어갈 아이템들이 공통적으로 가져야 할 기능을 정의해 둔 것이다.
그래서 슬롯에 들어갈 아이템도 IItemObject 타입으로 선언해 주었다. 이렇게 해두면 슬롯에서는 아이템의 종류를 몰라도 item.Use() 같은 방식으로 일관된 동작 처리가 가능하다.
▶ Slot 스크립트의 핵심
if (isEmpty) // 슬롯이 비어있을 때
{
slotButton.interactable = false;
itemImage.gameObject.SetActive(false);
}
else // 슬롯이 차있을 때
{
slotButton.interactable = true;
itemImage.gameObject.SetActive(true);
}
// 요약해서 쓴 코드
slotButton.interactable = !isEmpty;
itemImage.gameObject.SetActive(!isEmpty);
슬롯에 아이템이 있는지 isEmpty로 판단하여 슬롯이 비어있을 경우에만 버튼과 이미지의 활성화 상태를 결정해 주는 코드이다.
if문을 사용하지 않고 논리 연산자를 통해서 코드를 간략하게 적을 수 있다.
그리고 [AddItem()] 메서드에서 UI와의 연결을 수행한다.
인터페이스 기반의 아이템을 할당
아이템의 sprite 이미지를 이미지 컴포넌트에 연결
이미지의 사이즈를 원본 크기로 맞춤
슬롯이 비어있는 경우에만 슬롯 갱신
그런데 인벤토리는 말 그대로 여러 아이템을 담을 수 있는 공간이다.
위 Slot 컴포넌트는 하나의 아이템만을 저장할 수 있는 로직이기 때문에 ItemManager를 통해서 획득한 모든 아이템들이 각각의 슬롯과 직접 연결되어 저장되도록 하는 로직을 구현해주려고 한다.
public class ItemManager : MonoBehaviour
{
public GameObject inventoryUI;
public Button inventoryButton;
[SerializeField] private GameObject[] items;
[SerializeField] private Transform slotGroup;
public Slot[] slots;
void Start()
{
// 자신과 자식 중에서 Slot Component가 있는 대상을 모두 가져오는 기능
slots = slotGroup.GetComponentsInChildren<Slot>(true); // true -> 비활성화 되어있는 것도 갖고옴
// 인벤토리 버튼을 눌렀을 때 OnInventory 함수 실행
inventoryButton.onClick.AddListener(OnInventory);
}
public void OnInventory()
{
// GameObject.activeSelf = 현재 Active 상태
inventoryUI.SetActive(!inventoryUI.activeSelf);
}
public void GetItem(IItemObject item)
{
// 빈 슬롯을 찾아서 AddItem 수행
foreach (var slot in slots)
{
if (slot.isEmpty)
{
slot.AddItem(item);
break; // 브레이크를 해주지 않으면 모든 빈슬롯에 다 넣어버림
}
}
}
}
아이템의 개수는 0개 이상이 될 수 있으므로 배열로 아이템을 갖고 오도록 해주었고
슬롯 또한 배열로 선언하여 아이템이 Slot 컴포넌트를 자동으로 찾도록 구현해 주었다.
여기서 GetComponentsInChildren<Slot>(true); 로 작성해 주면 비활성화된 슬롯까지 포함해서 가져올 수 있다.
즉, 게임 첫 실행 시 인벤토리 UI가 비활성화 되어있더라도 문제없이 갖고 올 수 있다는 뜻이다.
foreach (var slot in slots)
{
if (slot.isEmpty)
{
slot.AddItem(item);
break; // 브레이크를 해주지 않으면 모든 빈슬롯에 다 넣어버림
}
}
해당 반복문 안에서 인벤토리의 슬롯을 순회하면서 빈 슬롯을 찾아 아이템을 저장한다.
이때 break 문이 없으면 여러 개의 빈 슬롯에 똑같은 아이템이 들어가는 문제가 생기니 꼭 추가해 주자
public void OnInventory()
{
// GameObject.activeSelf = 현재 Active 상태
inventoryUI.SetActive(!inventoryUI.activeSelf);
}
그리고 인벤토리 버튼을 클릭할 때마다 인벤토리를 On/Off 해주기 위하여 UI의 SetActive를 true ↔ false로 반전시켜 주었다.
3. 포탈
이제 Adventure 씬도 얼추 마무리가 되었으니 이 씬에도 포탈을 만들어줘서 Town 씬으로 이동하게 해 주겠다
IEnumerator PortalRoutine()
{
portalEffect.SetActive(true);
// Fade 코루틴이 끝날 때 까지 대기
yield return StartCoroutine(fade.Fade(3f, Color.white, true));
// 씬 변경
loadingImage.SetActive(true);
yield return StartCoroutine(fade.Fade(3f, Color.white, false));
while (progressBar.fillAmount < 1f) // 로딩 페이크
{
progressBar.fillAmount += Time.deltaTime * 0.3f;
yield return null;
}
if (sceneType == SceneType.Town)
SceneManager.LoadScene(1);
else
SceneManager.LoadScene(0);
}
포탈 스크립트를 그대로 복사해 와서 아래 씬 전환 하는 부분을 if문으로 선언해 주었다.
(음악이 이중으로 재생되는 문제가 있는데 이 부분은 아직 수정해주지 않았다.)
4. 인트로 화면
마지막으로 인트로 화면을 만들어주었다.
Start 버튼에 On Click 메서드를 활용해서 버튼을 클릭하면 Intro 화면이 비활성화되도록 설정해 주었다.