게임에서 상점 시스템은 플레이어들이 게임 내 아이템이나 장비를 구매하고 업그레이드하는 방법을 제공하여 게임의 새로운 경험과 도전을 제공합니다. 상점 시스템을 구현하여 플레이어가 아이템을 구매할 수 있도록 하였습니다.

 

💬 목차

  • 총 세개의 목차로 구성되어 있습니다. 글 별로 아직 언급되지 않은 클래스의 호출이 있을 수 있습니다. 모든 글을 참조하면 충분히 이해할 수 있습니다.

1. [유니티] 상점 시스템(1) - 상점 슬롯
2. [유니티] 상점 시스템(2) - 상점
[📌현재 글]  3. [유니티] 상점 시스템(3) - 상점 매니저

 

📖 구현 내용

  • 플레이어는 화폐를 가지고 해당 아이템을 구매할 수 있습니다.
  • 에디터에서 상점에서 판매하는 아이템을 미리 등록합니다.
  • 각 상점별로 상점 진척도 레벨을 이용하여 구매할 수 있는 아이템을 제한할 수 있습니다.
  • 각 상점별로 판매하는 아이템은 재고가 있어 재고를 모두 소진할경우 해당 아이템을 더 이상 구매할 수 없습니다.
  • 상점의 재고 및 진척도 레벨은 저장되어 나중에 게임을 로드하면 현 상태를 불러옵니다.

 

✅ 구현

  • 이번 글의 목적은 직전 글에서 다뤘던 상점 기능을 열고 닫는 상점 매니저를 다룹니다.
  • 상점 매니저는 씬 내의 모든 상점의 상점 열기 요청을 수행하여 해당 상점의 정보를 읽어 판매할 아이템들을 보여주는 역할을 수행합니다.
  • UI 요소와 함께 구현합니다.

 

· ItemShopManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ItemShopManager : Singleton<ItemShopManager>
{
    private static bool mIsItemShopActive = false;
    public static bool IsItemShopActive
    {
        get
        {
            return mIsItemShopActive;
        }
    }

    [Header("상점 오브젝트 루트 오브젝트")]
    [SerializeField] public GameObject mShopRootGo;

    [Header("상점 오브젝트의 프리팹 인스턴스 트랜스폼")]
    [SerializeField] public Transform mSlotInstantiateTransform;

    [Header("상점 슬롯 프리팹")]
    [SerializeField] public GameObject mShopSlotPrefab;

    private List<ItemShopSlot> mCurrentSlots = new List<ItemShopSlot>(); // 현재 인스턴스된 슬롯들

    private void Awake()
    {
        // 초기화시 전역 활성화상태 해제
        ItemShopManager.mIsItemShopActive = false;
    }

    /// <summary>
    /// 상점으로부터 호출되어 아이템 상점 다이얼로그를 열음
    /// </summary>
    /// <param name="sellItems">상점에서 판매하는 아이템들</param>
    /// <param name="shopLevel">상점의 진척도 레벨</param>
    public void OpenItemShop(ItemShopSlotInfo[] sellItems, int shopLevel)
    {
        foreach(ItemShopSlotInfo sellItem in sellItems)
        {
            ItemShopSlot slot = Instantiate(mShopSlotPrefab, Vector3.zero, Quaternion.identity, mSlotInstantiateTransform).GetComponent<ItemShopSlot>();
            slot.InitSlot(sellItem, shopLevel);

            mCurrentSlots.Add(slot);
        }
        
        mShopRootGo.SetActive(true);

        // 모든 슬롯을 갱신
        ItemShopManager.Instance.RefreshSlots();

        // 활성화 토글
        mIsItemShopActive = true;

        UtilityManager.UnlockCursor();
    }

    /// <summary>
    /// 상점 다이얼로그를 닫음
    /// </summary>
    public void CloseItemShop()
    {
        foreach(ItemShopSlot slot in mCurrentSlots)
            Destroy(slot.gameObject);
        
        mCurrentSlots.Clear();
        mShopRootGo.SetActive(false);

        // 비활성화 토글
        mIsItemShopActive = false;

        UtilityManager.TryLockCursor();
    }

    /// <summary>
    /// 상점 다이얼로그를 갱신
    /// </summary>
    public void RefreshSlots()
    {
        // 각 슬롯 갱신 호출
        foreach(ItemShopSlot slot in mCurrentSlots)
            slot.RefreshSlot();

        // 라벨 갱신
        InventoryMain.Instance.RefreshLabels();
    }
}

 

private static bool mIsItemShopActive = false;
public static bool IsItemShopActive
{
    get
    {
        return mIsItemShopActive;
    }
}
  • 현재 상점 다이얼로그창이 활성화 되어있는지 확인하기위한 변수입니다.

 

[Header("상점 오브젝트 루트 오브젝트")]
[SerializeField] public GameObject mShopRootGo;
  • 다이얼로그 창을 열고 닫기 위한 UI요소 루트 게임오브젝트입니다.

 

[Header("상점 오브젝트의 프리팹 인스턴스 트랜스폼")]
[SerializeField] public Transform mSlotInstantiateTransform;
  • 상점에서 판매하는 아이템을 슬롯으로 보여주기 위해 슬롯을 인스턴스할때 위치시킬 부모 트랜스폼입니다.

 

[Header("상점 슬롯 프리팹")]
[SerializeField] public GameObject mShopSlotPrefab;
  • 상점에서 판매하는 아이템을 슬롯으로 보여주기위해 인스턴스를 할 프리팹입니다.

 

/// <summary>
/// 상점으로부터 호출되어 아이템 상점 다이얼로그를 열음
/// </summary>
/// <param name="sellItems">상점에서 판매하는 아이템들</param>
/// <param name="shopLevel">상점의 진척도 레벨</param>
public void OpenItemShop(ItemShopSlotInfo[] sellItems, int shopLevel)
{
    foreach(ItemShopSlotInfo sellItem in sellItems)
    {
        ItemShopSlot slot = Instantiate(mShopSlotPrefab, Vector3.zero, Quaternion.identity, mSlotInstantiateTransform).GetComponent<ItemShopSlot>();
        slot.InitSlot(sellItem, shopLevel);

        mCurrentSlots.Add(slot);
    }

    mShopRootGo.SetActive(true);

    // 모든 슬롯을 갱신
    ItemShopManager.Instance.RefreshSlots();

    // 활성화 토글
    mIsItemShopActive = true;

    UtilityManager.UnlockCursor();
}
  • ItemShop.cs로부터 호출되어 상점 매니저인 이 클래스에게 상점 다이얼로그를 열도록 요청합니다.
  • sellItems를 이용하여 판매할 아이템들을 가지고오고 슬롯을 생성하여 해당 슬롯을 초기화합니다.

 

/// <summary>
/// 상점 다이얼로그를 닫음
/// </summary>
public void CloseItemShop()
{
    foreach(ItemShopSlot slot in mCurrentSlots)
        Destroy(slot.gameObject);

    mCurrentSlots.Clear();
    mShopRootGo.SetActive(false);

    // 비활성화 토글
    mIsItemShopActive = false;

    UtilityManager.TryLockCursor();
}
  • 상점 다이얼로그를 닫습니다.

 

/// <summary>
/// 상점 다이얼로그를 갱신
/// </summary>
public void RefreshSlots()
{
    // 각 슬롯 갱신 호출
    foreach(ItemShopSlot slot in mCurrentSlots)
        slot.RefreshSlot();

    // 라벨 갱신
    InventoryMain.Instance.RefreshLabels();
}
  • 필요한경우 상점 내부의 슬롯을 갱신합니다.
  • 예를 들어 아이템을 구매하여 아이템 재고 등을 갱신하기위해 사용할 수 있습니다.

 

· UI

  • 스크롤 뷰를 이용하여 판매할 아이템을 보여줄 수 있도록 합니다.

 

  • 사용할 UI와 매니저입니다.
  • 매니저는 싱글턴으로 구현하여 런타임 도중 비활성화되지 않도록 합니다.
  • M Shop Slot Prefab은 첫번째 글에서 구현하는 프리팹입니다.

 

📺 결과

bonnate