일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Unity
- 알고리즘
- 티스토리챌린지
- User Stack
- 추상클래스와인터페이스
- 핀토스
- BFS
- 크래프톤 정글 4기
- 4기
- c#
- 네트워크
- pintos
- 유니티
- 오블완
- 다익스트라
- 백준
- TiL
- project3
- KRAFTON JUNGLE
- 연결리스트
- 알고리즘수업-너비우선탐색2
- anonymous page
- 이벤트 함수 실행 순서
- 크래프톤정글4기
- 크래프톤정글
- 전쟁-전투
- 크래프톤 정글
- 파이썬
- C
- kraftonjungle
- Today
- Total
말감로그
[Unity] Valley - 아이템 리팩토링 / 인벤토리 & Toolbar 간 슬롯 이동 본문
아이템 리팩토링 확장하기
현재는 RICE_SEED와 TOMATO_SEED 아이템 뿐이다. 하지만 추후에 물뿌리개, 도끼 등등 더 많은 아이템을 확장하기 위해서는 스크립트를 변경해야 한다.
아이템 데이터를 정의하기 위해 ScriptableObject를 사용한 클래스를 만들어준다.
ScriptableObject는 Unity에서 데이터를 관리하고 저장하는 데 사용되는 클래스로, 일반적으로 게임의 상태를 저장하지 않고 데이터 자산(assed)처럼 여러 객체에서 공통으로 사용할 수 있는 데이터를 정의할 때 유용하다.
우선 ItemData 스크립트를 생성한다.
[CreateAssetMenu]는 Unity의 에디터에서 ScriptableObject를 쉽게 생성할 수 있도록 도와주는 속성이다.
// fileName = 기본 파일 이름 , menuName = Unity에디터에서 우클릭했을때 나타나는 메뉴 이름
// order = 메뉴에서 표시되는 순서, 숫자가 낮을수록 위쪽에 표시
[CreateAssetMenu(fileName = "Item Data", menuName = "Item Data", order = 50)]
public class ItemData : ScriptableObject
{
public string itemName = "Item Name";
public Sprite icon;
}
Unity에디터로 돌아가서 Project > 우클릭 > Create를 누르면 ItemData 항목이 생긴다
각 아이템에 맞게 ItemName과 Icon을 설정해주면 된다.
이렇게함으로써 여러가지 아이템 프리팹을 생성한 후 그 아이템에 맞는 Item Data를 만들어 넣어주면된다.
그리고 기존의 Collectable 스크립트와 Item 스크립트를 분리하여 코드의 구조화와 재사용성을 높였다.
기존 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);
}
}
}
수정된 Collecatble.cs
[RequireComponent(typeof(Item))]
public class Collectable : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
Player player = other.GetComponent<Player>();
if (player)
{
Item item = GetComponent<Item>();
if (item != null)
{
player.inventory.Add(item);
Destroy(this.gameObject);
}
}
}
}
ItemData ScriptObjectable로 아이템 데이터를 관리하기 때문에 CollectableType을 지우고
오직 플레이어와의 상호작용만을 담당하게 한다. 아이템이 수집될 때 어떤 동작을 해야하는지에 대한 로직을 포함한다.
RequireComponent(typeof(Item)) 는 이 스크립트가 사용될 때 반드시 Item 컴포넌트가 포함되어야 한다는 것을 말한다.
그리고 Item 스크립트에서 아이템 정보와 물리적 속성을 관리하게 한다.
[RequireComponent(typeof(Rigidbody2D))]
public class Item : MonoBehaviour
{
public ItemData data;
[HideInInspector] public Rigidbody2D rigid;
void Start()
{
rigid = GetComponent<Rigidbody2D>();
}
}
이렇게 변경해줬더니 해당 오류가 발생하면서 기존의 실행되던 아이템 드롭이 실행되지 않았다.
확인해보니 rigidbody2D가 할당되지 않아 AddForce에서 오류가 발생했던 것이었다.
public void DropItem(Item item)
{
Vector3 spawnLocation = transform.position;
Vector3 spawnOffset = Random.insideUnitCircle * 2f;
Item droppedItem = Instantiate(item, spawnLocation + spawnOffset, Quaternion.identity);
droppedItem.rigid.AddForce(spawnOffset * 0.3f, ForceMode2D.Impulse);
}
분명 rigidbody2D 컴포넌트가 할당이 잘 되어있는데 왜 오류가 뜨는거지 하고 확인해봤더니 호출 순서 때문이었다.
rigidbody가 할당되기 전에 DropItem()이 호출되어 실행되었기 때문이다.
그래서 Start() 를 Awake()로 변경하여 가장 먼저 호출되도록 해결하였다.
초기화 같은 경우는 Awake()에서 실행되야 함!!
[RequireComponent(typeof(Rigidbody2D))]
public class Item : MonoBehaviour
{
public ItemData data;
[HideInInspector] public Rigidbody2D rigid;
void Awake()
{
rigid = GetComponent<Rigidbody2D>();
}
}
이렇게 스크립트를 변경해줬기 때문에 Inventory_UI, Inventory ,Player 스크립트 등에서 CollectableType으로 설정되었던 것들은 모두 Item으로 변경해줘야 한다.
기존엔 아이템을 드랍하는 거까지 했으면 이젠 Inventory의 슬롯을 이동시키고 또 Toolbar로 이동시킬 수 있게 해야 한다.
// Inventory_UI.cs
public void SlotDrop(Slot_UI slot)
{
if (UIManager.dragSingle)
{
UIManager.draggedSlot.inventory.MoveSlot(UIManager.draggedSlot.slotID, slot.slotID, slot.inventory);
}
else
{
UIManager.draggedSlot.inventory.MoveSlot(UIManager.draggedSlot.slotID, slot.slotID, slot.inventory,
UIManager.draggedSlot.inventory.slots[UIManager.draggedSlot.slotID].count);
}
GameManager.instance.uiManager.RefreshAll();
}
드래그한 슬롯의 SlotID를 Drop한 Slot으로 Move시켜야 한다.
// Inventory.cs
public void MoveSlot(int fromIndex, int toIndex, Inventory toInventory, int numToMove = 1)
{
Slot fromSlot = slots[fromIndex];
Slot toSlot = toInventory.slots[toIndex];
if (toSlot.isEmpty || toSlot.CanAddItem(fromSlot.itemName))
{
for(int i = 0; i < numToMove; i++)
{
toSlot.AddItem(fromSlot.itemName, fromSlot.icon, fromSlot.maxAllowed);
fromSlot.RemoveItem();
}
}
}
점점 스크립트가 많아지면서 헷갈려지고 있다. 정리해보자면
Inventory.cs -> 인벤토리 시스템 구현
Inventory_UI.cs -> 개별 인벤토리 UI 담당
InventoryManager.cs -> 게임 내 다양한 인벤토리 관리 (Backpack, Toolbar)
Toolbar도 숫자 1~9를 누르면 해당 슬롯의 하이라이트가 되게 설정하고 마찬가지로 Toolbar_slot에도 Slot_UI 스크립트와 Event Trigger 컴포넌트를 달아주면 Inventory와 마찬가지로 슬롯간 이동이 가능하게 된다.
'TIL' 카테고리의 다른 글
[Unity] Valley - 식물 성장 코드 분리 및 확장성 개선 (0) | 2024.10.24 |
---|---|
[Unity] Valley - DayCycle & 식물 성장 시스템 (1) | 2024.10.24 |
[Unity] Valley - 인벤토리 시스템 (0) | 2024.10.16 |
[Unity] Valley - 플레이어 이동 & 애니메이션(Blend Tree) (0) | 2024.10.14 |
2024.10.04 Unity - 수류탄 효과, 몬스터 AI (NavMeshAgent) (0) | 2024.10.04 |