스파르타코딩클럽 게임개발
오늘은 스파르타 코딩 클럽 unity 게임 개발 과정 45일차(인벤토리 시스템 2)
코드천자문
2024. 1. 4. 13:54
반응형
유니티 인벤토리 시스템 2
이번에는 저번의 인벤토리 시스템을 이어서 작성한다.
인벤토리 슬롯을 클릭하거나 이동시키거나 디스플레이에 보이도록 하는 스크립트를 작성하였다.
1. InventoryDisplay
스크립트
InventoryDisplay
는 인벤토리 UI를 관리하는 추상 클래스다. 이 클래스는 인벤토리 시스템(InventorySystem
)과 UI 슬롯(InventorySlot_Ui
)을 연결하고, UI 업데이트를 처리한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Events;
public abstract class InventoryDisplay : MonoBehaviour
{
[SerializeField] InventoryMouseItemData mouseInventoryItem;
protected InventorySystem inventorySystem;
protected Dictionary<InventorySlot_Ui, InventorySlot> slotDictionary;
public InventorySystem InventorySystem => inventorySystem;
public Dictionary<InventorySlot_Ui, InventorySlot> SlotDictionary => slotDictionary;
protected virtual void Start()
{
}
public abstract void AssignSlot(InventorySystem invToDisplay);
protected virtual void UpdateSlot(InventorySlot updateSlot)
{
foreach (var slot in slotDictionary)
{
if (slot.Value == updateSlot)
{
slot.Key.UpdateUISlot(updateSlot);
}
}
}
public void SlotClicked(InventorySlot_Ui clickedUISlot)
{
bool isShiftPressed = Keyboard.current.leftShiftKey.isPressed;
if (clickedUISlot.AssignedInventorySlot.ItemData != null && mouseInventoryItem.AssignedInventorySlot.ItemData == null)
{
if (isShiftPressed && clickedUISlot.AssignedInventorySlot.SplitStack(out InventorySlot halfStackSlot)) // 분할할려고 할때
{
mouseInventoryItem.UpdateMouseSlot(halfStackSlot);
clickedUISlot.UpdateUISlot();
return;
}
else
{
mouseInventoryItem.UpdateMouseSlot(clickedUISlot.AssignedInventorySlot);
clickedUISlot.ClearSlot();
return;
}
}
if (clickedUISlot.AssignedInventorySlot.ItemData == null && mouseInventoryItem.AssignedInventorySlot.ItemData != null)
{
clickedUISlot.AssignedInventorySlot.AssignItem(mouseInventoryItem.AssignedInventorySlot);
clickedUISlot.UpdateUISlot();
mouseInventoryItem.ClearSlot();
return;
}
if (clickedUISlot.AssignedInventorySlot.ItemData != null && mouseInventoryItem.AssignedInventorySlot.ItemData != null)
{
bool isSameItem = clickedUISlot.AssignedInventorySlot.ItemData == mouseInventoryItem.AssignedInventorySlot.ItemData;
if (isSameItem && clickedUISlot.AssignedInventorySlot.EnuoughRoomLeftInStack(mouseInventoryItem.AssignedInventorySlot.StackSize))
{
clickedUISlot.AssignedInventorySlot.AssignItem(mouseInventoryItem.AssignedInventorySlot);
clickedUISlot.UpdateUISlot();
mouseInventoryItem.ClearSlot();
}
else if (isSameItem &&
!clickedUISlot.AssignedInventorySlot.EnuoughRoomLeftInStack(mouseInventoryItem.AssignedInventorySlot.StackSize, out int leftInStack))
{
if (leftInStack < 1) SwapSlot(clickedUISlot);
else
{
int remainingOnMouse = mouseInventoryItem.AssignedInventorySlot.StackSize - leftInStack;
clickedUISlot.AssignedInventorySlot.AddToStack(leftInStack);
clickedUISlot.UpdateUISlot();
var newItem = new InventorySlot(mouseInventoryItem.AssignedInventorySlot.ItemData, remainingOnMouse);
mouseInventoryItem.ClearSlot();
mouseInventoryItem.UpdateMouseSlot(newItem);
return;
}
}
else if (!isSameItem)
{
SwapSlot(clickedUISlot);
return;
}
}
}
private void SwapSlot(InventorySlot_Ui clickdeUISlot)
{
var cloneSlot = new InventorySlot(mouseInventoryItem.AssignedInventorySlot.ItemData, mouseInventoryItem.AssignedInventorySlot.StackSize);
mouseInventoryItem.ClearSlot();
mouseInventoryItem.UpdateMouseSlot(clickdeUISlot.AssignedInventorySlot);
clickdeUISlot.ClearSlot();
clickdeUISlot.AssignedInventorySlot.AssignItem(cloneSlot);
clickdeUISlot.UpdateUISlot();
}
}
AssignSlot
메서드: 이 추상 메서드는 인벤토리 시스템을 UI 슬롯과 연결하는 데 사용된다. 구체적인 연결 로직은 상속받은 클래스에서 구현한다.UpdateSlot
메서드: 인벤토리 슬롯의 변경 사항을 UI에 반영한다. 이 메서드는 인벤토리의 상태가 변경될 때마다 호출된다.SlotClicked
메서드: 사용자가 인벤토리 슬롯을 클릭할 때 호출된다. 이는 아이템을 선택하거나 이동하는 데 사용된다.
2. StaticInventoryDisplay
스크립트
StaticInventoryDisplay
는 InventoryDisplay
를 구체화한 클래스다. 이 클래스는 특정한 InventoryHolder
에서 인벤토리 데이터를 가져와 UI에 표시한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StaticInventoryDisplay : InventoryDisplay
{
[SerializeField] private InventoryHolder inventoryHolder;
[SerializeField] private InventorySlot_Ui[] slots;
protected override void Start()
{
base.Start();
if (inventoryHolder != null)
{
inventorySystem = inventoryHolder.PrimaryInventorySystem;
inventorySystem.OnIventorySlotChanged += UpdateSlot;
}
else Debug.LogWarning($"인벤토리에 할당되지 않았습니다 {this.gameObject}");
AssignSlot(inventorySystem);
}
public override void AssignSlot(InventorySystem invToDisplay)
{
slotDictionary = new Dictionary<InventorySlot_Ui, InventorySlot>();
if (slots.Length != inventorySystem.InventroySize) Debug.Log($"인벤토리 슬롯이 백엔드와 동기화 되지 않앗스빈다. {this.gameObject}");
for (int i = 0; i < inventorySystem.InventroySize; i++)
{
slotDictionary.Add(slots[i],inventorySystem.InventorySlots[i]);
slots[i].Init(inventorySystem.InventorySlots[i]);
}
}
}
Start
메서드: 인벤토리 시스템을 초기화하고, UI 슬롯을 설정한다.AssignSlot
메서드: 인벤토리 시스템의 각 슬롯을 UI 슬롯과 연결한다. 이 메서드는 부모 클래스의AssignSlot
을 구체적으로 구현한다.
3. InventorySlot_Ui
스크립트
InventorySlot_Ui
는 개별 인벤토리 슬롯의 UI를 관리한다. 이 클래스는 아이템의 이미지와 수량을 UI에 표시한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class InventorySlot_Ui : MonoBehaviour
{
[SerializeField] private Image itemSprite;
[SerializeField] private TextMeshProUGUI itemCount;
[SerializeField] private InventorySlot assignedInventorySolt;
private Button button;
public InventorySlot AssignedInventorySlot
{
get { return assignedInventorySolt; }
set { assignedInventorySolt = value; }
}
public Image ItemSprite
{
get { return itemSprite; }
set { itemSprite = value; }
}
public InventoryDisplay ParentDisplay { get; private set; }
private void Awake()
{
ClearSlot();
button = GetComponent<Button>();
button?.onClick.AddListener(OnUISlotClick);
ParentDisplay = transform.parent.GetComponent<InventoryDisplay>();
}
public void Init(InventorySlot slot)
{
assignedInventorySolt = slot;
UpdateUISlot(slot);
}
public void UpdateUISlot(InventorySlot slot)
{
if (slot.ItemData != null)
{
itemSprite.sprite = slot.ItemData.Icon;
itemSprite.color = Color.white;
if (slot.StackSize > 1) itemCount.text = slot.StackSize.ToString();
else itemCount.text = "";
}
else
{
ClearSlot();
}
}
public void UpdateUISlot()
{
if (assignedInventorySolt != null) UpdateUISlot(assignedInventorySolt);
}
public void ClearSlot()
{
assignedInventorySolt?.ClearSlot();
itemSprite.sprite = null;
itemSprite.color = Color.clear;
itemCount.text = "";
}
public void OnUISlotClick()
{
ParentDisplay?.SlotClicked(this);
}
}
UpdateUISlot
메서드: 지정된 인벤토리 슬롯의 정보를 UI에 표시한다.ClearSlot
메서드: 슬롯을 비웠을 때 UI를 초기화한다.OnUISlotClick
메서드: 슬롯이 클릭되었을 때 해당하는 동작을 수행한다. 이는 상위InventoryDisplay
의SlotClicked
메서드를 호출한다
.
4. InventoryMouseItemData
스크립트
InventoryMouseItemData
는 마우스로 드래그 중인 인벤토리 아이템을 관리한다. 이 스크립트는 드래그 중인 아이템의 이미지와 수량을 UI에 표시한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using TMPro;
using System;
public class InventoryMouseItemData : MonoBehaviour
{
public Image ItemSprite;
public TextMeshProUGUI ItemCount;
public InventorySlot AssignedInventorySlot;
private void Awake()
{
ItemSprite.color = Color.clear;
ItemCount.text = "";
}
public void UpdateMouseSlot(InventorySlot invSlot)
{
AssignedInventorySlot.AssignItem(invSlot);
ItemSprite.sprite = invSlot.ItemData.Icon;
ItemCount.text = invSlot.StackSize.ToString();
ItemSprite.color = Color.white;
}
private void Update()
{
if (AssignedInventorySlot.ItemData != null)
{
transform.position = Mouse.current.position.ReadValue();
if (Mouse.current.leftButton.wasPressedThisFrame && !IsPointerOverUIObject())
{
ClearSlot();
}
}
}
public void ClearSlot()
{
AssignedInventorySlot.ClearSlot();
ItemCount.text = "";
ItemSprite.sprite = null;
ItemSprite.color = Color.clear;
}
public static bool IsPointerOverUIObject()
{
PointerEventData eventDataCurruntPosition = new PointerEventData(EventSystem.current);
eventDataCurruntPosition.position = Mouse.current.position.ReadValue();
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurruntPosition, results);
return results.Count > 0;
}
}
Update
메서드: 마우스의 위치를 추적하고, 아이템이 드래그되고 있을 때 해당 아이템을 화면에 표시한다. 마우스 클릭이 감지되면 드래그를 종료한다.IsPointerOverUIObject
메서드: 현재 마우스 포인터가 UI 오브젝트 위에 있는지 확인한다.
반응형