일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 추상클래스와인터페이스
- kraftonjungle
- 오블완
- C
- c#
- 4기
- pintos
- project3
- 네트워크
- KRAFTON JUNGLE
- 크래프톤정글
- 전쟁-전투
- 핀토스
- 연결리스트
- 이벤트 함수 실행 순서
- 백준
- 알고리즘
- 파이썬
- 유니티
- TiL
- BFS
- User Stack
- 크래프톤 정글 4기
- anonymous page
- 크래프톤정글4기
- 티스토리챌린지
- 크래프톤 정글
- Unity
- 알고리즘수업-너비우선탐색2
- 다익스트라
- Today
- Total
말감로그
[Unity] Valley - 인벤토리 시스템 본문
인벤토리 시스템
인벤토리 클래스를 정의해서 인벤토리 시스템을 관리할 것이다.
//Inventory.cs
[System.Serializable]
public class Inventory
{
public List<Slot> slots = new List<Slot>();
[System.Serializable]
public class Slot
{
public CollectableType type;
public Sprite icon;
public int count;
public int maxAllowed;
public Slot()
{
type = CollectableType.NONE;
count = 0;
maxAllowed = 99;
}
}
public Inventory(int numSlots)
{
for (int i = 0; i < numSlots; i++)
{
Slot slot = new Slot();
slots.Add(slot);
}
}
List<Slot> slots
Slot 객체들의 리스트로, 인벤토리에 들어갈 각 슬롯을 나타낸다.
Slot 클래스
인벤토리의 각 슬롯을 정의하는 내부 클래스로, 각 슬롯이 어떤 아이템을 담고 있는지, 아이템의 갯수, 아이콘 등을 저장한다.
Slot() 생성자
Slot 객체가 생성될 때 기본적으로 저 값으로 초기화된다.
Inventory(int numSlots) 생성자
인벤토리의 슬롯 수를 받아서 Slot 객체들을 해당 개수만큼 생성하여 slots 리스트에 추가한다.
인벤토리를 초기화할 때 이 생성자를 사용하여 빈 슬롯들이 채워진 인벤토리가 생성된다.
// Player.cs
void Awake()
{
inventory = new Inventory(24);
}
실제 Player.cs에서 24개의 슬롯들이 채워진 인벤토리를 생성한다.
기본적인 설정을 마쳤으니 이제 아이템을 추가하고 삭제하는 일을 해야 한다.
슬롯에 아이템을 추가하고 삭제하는 역할을 하는 메서드들이다.
public class Slot
{
:
public bool CanAddItem()
{
if (count < maxAllowed)
{
return true;
}
return false;
}
public void AddItem(Collectable item)
{
this.type = item.type;
this.icon = item.icon;
count++;
}
public void RemoveItem()
{
if(count > 0)
{
count--;
if(count == 0)
{
icon = null;
type = CollectableType.NONE;
}
}
}
}
인벤토리에 아이템을 추가하고 삭제하는 메서드들
:
public void Add(Collectable item)
{
// 슬롯의 타입이 추가하려는 아이템의 타입과 같고 maxAllowed보다 적은 count이면
foreach (Slot slot in slots)
{
if (slot.type == item.type && slot.CanAddItem())
{
slot.AddItem(item);
return;
}
}
// 같은 타입의 슬롯이 없거나 슬롯이 꽉차서 아이템으 추가할 수 없는 경우
foreach (Slot slot in slots)
{
// 빈 슬롯이면
if (slot.type == CollectableType.NONE)
{
slot.AddItem(item);
return;
}
}
}
public void Remove(int index)
{
slots[index].RemoveItem();
}
public void Remove(int index, int numToRemove)
{
if(slots[index].count >= numToRemove)
{
for(int i = 0; i < numToRemove; i++)
{
Remove(index);
}
}
}
슬롯에도 해당 아이템의 아이콘과 개수를 나타내기 위한 스크립트를 작성해서 붙여준다.
// Slot_UI.cs
using UnityEngine;
using UnityEngine.UI;
public class Slot_UI : MonoBehaviour
{
public int slotID;
public Image itemIcon;
public Text quantityText;
public void SetItem(Inventory.Slot slot)
{
if (slot != null)
{
itemIcon.sprite = slot.icon;
itemIcon.color = new Color(1, 1, 1, 1);
quantityText.text = slot.count.ToString();
}
}
public void EmptyItem()
{
itemIcon.sprite = null;
itemIcon.color = new Color(1, 1, 1, 0);
quantityText.text = "";
}
}
수집 가능한 아이템을 나타내는 스크립트를 작성해서 오브젝트의 타입을 정의하고, 플레이어에 닿으면 해당 오브젝트를 인벤토리에 추가하도록 한다.
// Collectable.cs
using UnityEngine;
public enum CollectableType { NONE, RICE_SEED }
public class Collectable : MonoBehaviour
{
public CollectableType type;
public Sprite icon;
public Rigidbody2D rigid;
void Start()
{
rigid = GetComponent<Rigidbody2D>();
}
void OnTriggerEnter2D(Collider2D other)
{
Player player = other.GetComponent<Player>();
if (player)
{
player.inventory.Add(this);
Destroy(this.gameObject);
}
}
}
인벤토리를 Tab 키로 껐다 키고 킬때마다 갱신을 시켜줘야 하기 때문에 Refresh() 함수를 통해서 인벤토리의 슬롯을 갱신해준다.
public class Inventory_UI : MonoBehaviour
{
public Player player;
public GameObject inventory;
public List<Slot_UI> slots = new List<Slot_UI>();
void Awake()
{
canvas = FindObjectOfType<Canvas>();
inventory.SetActive(false);
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
ToggleInventory();
}
}
public void ToggleInventory()
{
if (!inventory.activeSelf)
{
inventory.SetActive(true);
Refresh();
}
else
{
inventory.SetActive(false);
}
}
// 인벤토리 갱신
void Refresh()
{
if (slots.Count == player.inventory.slots.Count)
{
for (int i = 0; i < slots.Count; i++)
{
if (player.inventory.slots[i].type != CollectableType.NONE)
{
slots[i].SetItem(player.inventory.slots[i]);
}
else
{
slots[i].EmptyItem();
}
}
}
}
}
여기까지 하면 플레이어가 아이템을 먹으면 인벤토리에 갯수와 함께 잘 들어가 있는 모습을 볼 수 있다.
이제 드래그앤 드랍으로 슬롯을 끌어다가 밖에 놓으면 플레이어 주변으로 아이템이 떨어져있는 모습을 구현할 것이다.
그러기 위해선 Slot 프리팹에 Event Trigger 컴포넌트를 추가해줘야 한다.
Event Trigger는 다양한 UI 이벤트를 감지하고 이에 대응할 수 있게 도와준다.
1. SlotBeginDrag(Slot_UI slot)
슬롯 드래그 시작시 호출되며, 드래그할 슬롯과 아이콘을 준비한다.
public void SlotBeginDrag(Slot_UI slot)
{
draggedSlot = slot; //드래그할 슬롯 저장
draggedIcon = Instantiate(draggedSlot.itemIcon); // 슬롯의 아이콘 복사
draggedIcon.transform.SetParent(canvas.transform); // 캔버스의 자식으로 설정
draggedIcon.raycastTarget = false; // 아이콘이 레이캐스트를 받지 않도록 설정
draggedIcon.rectTransform.sizeDelta = new Vector2(100, 100); // 아이콘 크기
MoveToMousePosition(draggedIcon.gameObject); // 아이콘을 마우스 위치로 이동
Debug.Log("Start Drag:" + draggedSlot.name);
}
2. SlotDrag()
드래그 중 아이콘의 위치를 업데이트한다.
public void SlotDrag()
{
MoveToMousePosition(draggedIcon.gameObject); // 드래그 중 아이콘 위치 업데이트
Debug.Log("Dragging:" + draggedSlot.name); // 드래그 중인 슬롯 로그 출력
}
3. SlotEndDrag()
드래그가 끝났을 때 호출되며, 드래그된 아이콘을 정리한다.
public void SlotEndDrag()
{
Destroy(draggedIcon.gameObject); // 드래그가 끝나면 아이콘 삭제
draggedIcon = null; // 드래그된 아이콘 변수 초기화
}
4.SlotDrop(Slot_UI Slot)
아이콘이 다른 슬롯에 드롭될 때 호출된다.
아직 이건 구현 X
public void SlotDrop(Slot_UI slot)
{
Debug.Log("Dropped :" + draggedSlot.name + " on " + slot.name); // 드롭된 슬롯 로그 출력
}
5. MoveToMousePosition(GameObject toMove)
주어진 게임 오브젝트를 마우스 위치로 이동한다.
public void MoveToMousePosition(GameObject toMove)
{
if (canvas != null)
{
Vector2 position;
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, Input.mousePosition, null, out position); // 마우스 위치를 로컬 좌표로 변환
toMove.transform.position = canvas.transform.TransformPoint(position); // 변환된 위치로 이동
}
}
RectTransformUtility.ScreenPointToLocalPointInRectangle
스크린상의 마우스 위치를 캔버스의 로컬 좌표로 변환한다. 이 방법은 UI 요소를 정확한 위치에 배치하는 데 필요하다.
TransformPoint
변환된 로컬 위치를 다시 세계 좌표로 변환
캔버스에서 아이템 제거 패널 오브젝트를 만들고 캔버스에 가득차게 설정한다.
UI 배경이 보이게끔 알파값은 0으로 설정하고,
Event Trigger - Drop - Inventory_UI.Remove() 함수를 추가한다.
RemoveItem_Panel에 드랍한 아이템을 플레이어 주변으로 떨어트리고 인벤토리에서 제거시킨다.
public void Remove()
{
Collectable itemToDrop = GameManager.instance.itemManager.GetItemByType(player.inventory.slots[draggedSlot.slotID].type);
if (itemToDrop != null)
{
if (dragSingle)
{
player.DropItem(itemToDrop);
player.inventory.Remove(draggedSlot.slotID);
}
else
{
player.DropItem(itemToDrop, player.inventory.slots[draggedSlot.slotID].count);
player.inventory.Remove(draggedSlot.slotID, player.inventory.slots[draggedSlot.slotID].count);
}
Refresh();
}
draggedSlot = null;
}
플레이어 주변에서 점차 멀어지게끔 떨어지는 효과를 주기 위한
// Player.cs
public void DropItem(Collectable item)
{
Vector3 spawnLocation = transform.position;
Vector3 spawnOffset = Random.insideUnitCircle * 2f;
Collectable droppedItem = Instantiate(item, spawnLocation + spawnOffset, Quaternion.identity);
droppedItem.rigid.AddForce(spawnOffset * 0.3f, ForceMode2D.Impulse);
}
'TIL' 카테고리의 다른 글
[Unity] Valley - DayCycle & 식물 성장 시스템 (1) | 2024.10.24 |
---|---|
[Unity] Valley - 아이템 리팩토링 / 인벤토리 & Toolbar 간 슬롯 이동 (0) | 2024.10.18 |
[Unity] Valley - 플레이어 이동 & 애니메이션(Blend Tree) (0) | 2024.10.14 |
2024.10.04 Unity - 수류탄 효과, 몬스터 AI (NavMeshAgent) (0) | 2024.10.04 |
24.10.02 Unity - 물리 충돌 수정, Raycast (0) | 2024.10.02 |