게임에서 상점 시스템은 플레이어들이 게임 내 아이템이나 장비를 구매하고 업그레이드하는 방법을 제공하여 게임의 새로운 경험과 도전을 제공합니다. 상점 시스템을 구현하여 플레이어가 아이템을 구매할 수 있도록 하였습니다.
📺 미리보기
💬 목차
- 총 세개의 목차로 구성되어 있습니다. 글 별로 아직 언급되지 않은 클래스의 호출이 있을 수 있습니다. 모든 글을 참조하면 충분히 이해할 수 있습니다.
- 이번 글에서는 아이템 상점에서 사용될 "아이템 상점 슬롯"을 구현합니다.
[📌현재 글] 1. [유니티] 상점 시스템(1) - 상점 슬롯
2. [유니티] 상점 시스템(2) - 상점
3. [유니티] 상점 시스템(3) - 상점 매니저
📖 구현 내용
- 플레이어는 화폐를 가지고 해당 아이템을 구매할 수 있습니다.
- 에디터에서 상점에서 판매하는 아이템을 미리 등록합니다.
- 각 상점별로 상점 진척도 레벨을 이용하여 구매할 수 있는 아이템을 제한할 수 있습니다.
- 각 상점별로 판매하는 아이템은 재고가 있어 재고를 모두 소진할경우 해당 아이템을 더 이상 구매할 수 없습니다.
- 상점의 재고 및 진척도 레벨은 저장되어 나중에 게임을 로드하면 현 상태를 불러옵니다.
✅ 구현
- 이번 글의 목적은 아이템 상점에서 판매하고자 하는 아이템을 각각 보여줄 수 있는 아이템 상점 슬롯을 다룹니다.
- 아이템 상점 슬롯에는 "[유니티] 인벤토리 시스템(3) - 아이템 슬롯(인벤토리 슬롯)" 글에서 다루는 아이템 슬롯 시스템을 함께 사용합니다.
· ItemShopSlot.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class ItemShopSlot : MonoBehaviour
{
[SerializeField] private InventorySlot mItemSlot;
[SerializeField] private TextMeshProUGUI mNameLabel, mCostLabel;
[SerializeField] private Button mBuyButton;
private ItemShopSlotInfo mSellInfo; // 현재 판매중인 아이템의 정보
private int mCalledShopLevel; // 현재 상점의 판매 단계
public void RefreshSlot()
{
// 아이템의 요구 단계가 현재 상점의 판매 단계가 보다 높으면?
if (mSellInfo.NeedShopLevel > mCalledShopLevel)
{
mCostLabel.text = "지금은 구매할 수 없습니다.";
mBuyButton.interactable = false;
return;
}
// 구매버튼 비활성화
if (InventoryMain.Instance.CurrentCoin < mSellInfo.Cost
|| mSellInfo.ItemAmount <= 0)
mBuyButton.interactable = false;
else
mBuyButton.interactable = true;
// 텍스트 갱신
mCostLabel.text = $"{mSellInfo.Cost} ({mSellInfo.ItemAmount}개 남음)";
}
public void InitSlot(ItemShopSlotInfo sellItem, int shopLevel)
{
// 정보 가져오기
mCalledShopLevel = shopLevel;
mSellInfo = sellItem;
// 슬롯 초기화
mItemSlot.ClearSlot();
// 슬롯 설정
InventoryMain.Instance.AcquireItem(mSellInfo.SellItem, mItemSlot, mSellInfo.GiveAmountPerTrade);
mNameLabel.text = ItemDataManager.Instance.GetName(mSellInfo.SellItem.ID);
}
public void BTN_BuyItem()
{
// 가격 지불
InventoryMain.Instance.CurrentCoin -= mSellInfo.Cost;
// 인벤토리에 아이템 추가(구매)
InventoryMain.Instance.AcquireItem(mSellInfo.SellItem, mSellInfo.GiveAmountPerTrade < mSellInfo.ItemAmount ? mSellInfo.GiveAmountPerTrade : mSellInfo.ItemAmount);
// 개수 갱신
mSellInfo.ItemAmount -= mSellInfo.GiveAmountPerTrade;
mSellInfo.ItemAmount = Mathf.Clamp(mSellInfo.ItemAmount, 0, int.MaxValue);
// 모든 슬롯을 갱신
ItemShopManager.Instance.RefreshSlots();
// 사운드 재생
SoundManager.Instance.PlaySound2D("Item purchase " + SoundManager.Range(1, 3));
}
}
[SerializeField] private InventorySlot mItemSlot;
- 판매할 아이템을 보여주기 위한 인벤토리 슬롯입니다.
[SerializeField] private TextMeshProUGUI mNameLabel, mCostLabel;
- 판매할 아이템의 이름과 가격을 크게 보여주기위한 라벨입니다.
[SerializeField] private Button mBuyButton;
- 아이템을 구매하기위한 버튼입니다.
- 만약 아이템을 구매할 수 없는경우, 해당 버튼을 비활성화합니다.
private ItemShopSlotInfo mSellInfo; // 현재 판매중인 아이템의 정보
- 슬롯에서 현재 판매중인 아이템의 정보를 담습니다.
private int mCalledShopLevel; // 현재 상점의 판매 단계
- 현재 상점의 진척도 레벨입니다.
- 이 값이 판매 아이템 정보의 요구 레벨보다 크거나 같으면 아이템을 판매할 수 있게 합니다.
public void RefreshSlot()
{
// 아이템의 요구 단계가 현재 상점의 판매 단계가 보다 높으면?
if (mSellInfo.NeedShopLevel > mCalledShopLevel)
{
mCostLabel.text = "지금은 구매할 수 없습니다.";
mBuyButton.interactable = false;
return;
}
// 구매버튼 비활성화
if (InventoryMain.Instance.CurrentCoin < mSellInfo.Cost
|| mSellInfo.ItemAmount <= 0)
mBuyButton.interactable = false;
else
mBuyButton.interactable = true;
// 텍스트 갱신
mCostLabel.text = $"{mSellInfo.Cost} ({mSellInfo.ItemAmount}개 남음)";
}
- 해당 슬롯을 갱신합니다.
- 플레이어가 다른 아이템을 구매하여 소지금이 줄거나, 해당 아이템의 재고가 모두 떨어진경우 아이템 구매 버튼을 비활성화 할 수 있습니다.
public void InitSlot(ItemShopSlotInfo sellItem, int shopLevel)
{
// 정보 가져오기
mCalledShopLevel = shopLevel;
mSellInfo = sellItem;
// 슬롯 초기화
mItemSlot.ClearSlot();
// 슬롯 설정
InventoryMain.Instance.AcquireItem(mSellInfo.SellItem, mItemSlot, mSellInfo.GiveAmountPerTrade);
mNameLabel.text = ItemDataManager.Instance.GetName(mSellInfo.SellItem.ID);
}
- 아이템 상점 다이얼로그 열릴 때 상점 매니저로부터 호출되며 슬롯에 판매할 아이템을 초기화해줍니다.
public void BTN_BuyItem()
{
// 가격 지불
InventoryMain.Instance.CurrentCoin -= mSellInfo.Cost;
// 인벤토리에 아이템 추가(구매)
InventoryMain.Instance.AcquireItem(mSellInfo.SellItem, mSellInfo.GiveAmountPerTrade < mSellInfo.ItemAmount ? mSellInfo.GiveAmountPerTrade : mSellInfo.ItemAmount);
// 개수 갱신
mSellInfo.ItemAmount -= mSellInfo.GiveAmountPerTrade;
mSellInfo.ItemAmount = Mathf.Clamp(mSellInfo.ItemAmount, 0, int.MaxValue);
// 모든 슬롯을 갱신
ItemShopManager.Instance.RefreshSlots();
// 사운드 재생
SoundManager.Instance.PlaySound2D("Item purchase " + SoundManager.Range(1, 3));
}
- 버튼을 이용하여 해당 아이템을 구매합니다.
- 아이템을 지급하는 방식은 인벤토리 시스템을 이용합니다.
· ItemShopSlotInfo
- 이 클래스는 판매할 아이템 정보를 정의하기위해 사용합니다. 이 글 이외에도 매니저 및 아이템 상점에서도 사용됩니다.
- 클래스의 정의 및 각 변수의 사용 목적은 다음과 같습니다.
[System.Serializable]
public class ItemShopSlotInfo
{
[Header("판매할 아이템")]
[SerializeField] public Item SellItem; // 판매할 아이템
[Header("거래 한번당 아이템의 비용")]
[SerializeField] public int Cost; // 아이템의 비용
[Header("아이템의 총 개수 (재고)")]
[SerializeField] public int ItemAmount; // 아이템의 총 개수(재고량)
[Header("거래 1회당 지급할 아이템 개수")]
[SerializeField] public int GiveAmountPerTrade; // 거래 한번당 넘겨줄 아이템 개수
[Header("아이템 판매 가능 단계 (상점의 진척도 단계)")]
[SerializeField] public int NeedShopLevel; // 요구 단계
public ItemShopSlotInfo(ItemShopSlotInfo origin)
{
this.SellItem = origin.SellItem;
this.Cost = origin.Cost;
this.ItemAmount = origin.ItemAmount;
this.GiveAmountPerTrade = origin.GiveAmountPerTrade;
this.NeedShopLevel = origin.NeedShopLevel;
}
}
· UI
- 아이템 상점 슬롯에는 "[유니티] 인벤토리 시스템(3) - 아이템 슬롯(인벤토리 슬롯)" 글에서 다루는 아이템 슬롯 시스템을 사용한다는 점을 꼭 알아둬야합니다.
- 이 사항은 ItemSlot이라는 GameObject에 해당합니다.
- 판매할 아이템은 가장 왼쪽에 표시되며, 아이템의 이름 및 비용 및 구매 버튼이 함께 있습니다.
- 프리팹 하나에 ItemShopSlot.cs을 사용하고 인스펙터에서 사용할 멤버변수들도 하위 구성 요소로 이루어져있습니다.
- 프리팹의 UI 요소 구성입니다.
'unity game modules' 카테고리의 다른 글
[유니티] 상점 시스템(3) - 상점 매니저 (0) | 2023.04.02 |
---|---|
[유니티] 상점 시스템(2) - 상점 (0) | 2023.04.02 |
[유니티] 경사면 미끄러짐 (0) | 2023.03.27 |
[유니티] 대화 시스템(3) - 말풍선 (1) | 2023.03.27 |
[유니티] 대화 시스템(2) - 선택지 (0) | 2023.03.27 |