22.02.14 Shop 메뉴 구현하기

2022. 2. 14. 18:35Unity3D/수업 내용

총 3가지의 재화를 구입할 수 있는 Shop 메뉴를 구현해보자.

 

우선 나는 재화 종류마다 팝업 창 오브젝트를 만들어 주어서,

버튼이 눌린상태 , 안눌린 상태 구분하는 코드를 생략했다.

덕분에 수작업은 조금 늘었지만, 할 게 줄어서 좋기도 하다.

 

전체적인 구조는 다음과 같다.

 

캔버스의 자식으로 3개의 팝업 창 오브젝트가 있고,

각 팝업 창은 스크롤뷰와 슬롯 프리팹을 가지고 있다.

팝업 창을 열면 팝업창 오브젝트가 자신의 스크롤뷰 안에 슬롯 프리팹을 생성한다.


실행 화면


소스 코드

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

public class UIShopControl : MonoBehaviour
{
    [SerializeField] GameObject[] goPopUps;
    bool[] isGen = new bool[3];

    void Start()
    {
        isGen[0] = false;
        isGen[1] = false;
        isGen[2] = false;
    }

    public void ClosePopUp()
    {
        foreach (GameObject popUp in goPopUps)
        {
            popUp.SetActive(false);
        }
    }

    public void OpenGoldPopUp()
    {
        foreach(GameObject popUp in goPopUps)
        {
            popUp.SetActive(false);
        }
        if (!isGen[0])
        {
            goPopUps[0].GetComponent<UIShopPopUpInfoControl>().InitPopUp(0);
            isGen[0] = true;
        }
        goPopUps[0].SetActive(true);
    }

    public void OpenGemPopUp()
    {
        foreach (GameObject popUp in goPopUps)
        {
            popUp.SetActive(false);
        }
        if (!isGen[1])
        {
            goPopUps[1].GetComponent<UIShopPopUpInfoControl>().InitPopUp(1);
            isGen[1] = true;
        }
        goPopUps[1].SetActive(true);
    }

    public void OpenSoulGemPopUp()
    {
        foreach (GameObject popUp in goPopUps)
        {
            popUp.SetActive(false);
        }
        if (!isGen[2])
        {
            goPopUps[2].GetComponent<UIShopPopUpInfoControl>().InitPopUp(2);
            isGen[2] = true;
        }
        goPopUps[2].SetActive(true);
    }
}

3개의 팝업창을 가지고 있는 캔버스의 스크립트다.

배열로 가지고 있으며,

슬롯을 인스턴스화해서 생성하는 작업은 처음 한번만 하기 위해

동일한 크기의 bool 배열을 만들었다.


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

public class UIShopPopUpInfoControl : MonoBehaviour
{
    int type;
    [SerializeField] GameObject goShopSlot;
    [SerializeField] GameObject grid;

    public void InitPopUp(int type)
    {
        this.type = type;
        LoadShopSlot();
    }

    void LoadShopSlot()
    {
        Dictionary<int, ShopData> dict = DataManager.GetInstance().GetDictShopData();
        List<ShopData> datas = new List<ShopData>();

        foreach(ShopData data in dict.Values)
        {
            if(data.type == type)
            {
                datas.Add(data);
            }
        }

        for(int i = 0; i < datas.Count; i++)
        {
            GameObject go = Instantiate(goShopSlot);
            go.transform.SetParent(grid.transform);
            go.GetComponent<UIShopSlotControl>().InitShopSlot(datas[i].id);
        }
    }
}

각각의 팝업창이 가지고 있는 스크립트다.

이전의 캔버스 스크립트에서 InitPopUp()메서드를 통해 이곳으로 흘러들어오게 된다.

그리고 LoadShopSlot()메서드를 통해 슬롯프리팹이 가지고 있는 스크립트로 넘어가게 된다.


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.U2D;

public class UIShopSlotControl : MonoBehaviour
{
    int id;
    [SerializeField] SpriteAtlas atlas;
    [SerializeField] Image icon;
    [SerializeField] Text rewardText;
    [SerializeField] Text bonusText;
    [SerializeField] Image purchaseIcon;
    [SerializeField] Text purchaseText;

    public void InitShopSlot(int id)
    {
        this.id = id;
        LoadSlotInfo();
    }

    void LoadSlotInfo()
    {
        ShopData data = DataManager.GetInstance().GetShopData(id);
        this.icon.sprite = atlas.GetSprite(data.spriteName);
        this.icon.SetNativeSize();
        this.rewardText.text = string.Format("{0:#,###}", int.Parse(data.name));
        if (data.bonus > 0)
        {
            this.bonusText.text = "bonus +" + data.bonus + "%";
        }
        else
        {
            this.bonusText.gameObject.SetActive(false);
        }
        this.purchaseIcon.sprite = atlas.GetSprite(DataManager.GetInstance().GetBudgetData(data.budget_id).spriteName);
        this.purchaseIcon.SetNativeSize();
        this.purchaseText.text = data.price;
    }
}

최종적으로 이 곳에서 팝업창의 모든 정보를 표기해준다.

 


피드백

  • 캔버스 스크립트에서 같은 기능의 함수를 중복해서 만들었는데, 이럴 거면 굳이 팝업창을 3개 만들지 않아도 될 것 같다는 생각이 들었다. 

이 코드의 장점은 팝업창이 재화 종류별로 있어서 처음 인스턴스화 하고 난 후에는

오브젝트 활성/비활성화로 간단하고 빠르게 각 팝업창을 키고 닫을 수 있다는 것이다.

 

그러나 이 장점은 굳이 팝업창을 종류별로 만들지 않고도 얻을 수 있는 다른 방법이 있다.

예를 들어 생성한 슬롯프리팹들을 리스트에 담아놓고, 

다른 재화의 팝업창으로 이동할 때는 그 재화의 타입과 동일한 슬롯프리팹만 활성화시키고 나머지는

비활성화 시켜둔다던지 하는 식으로 말이다.

 

다음엔 이 방법으로 해보자.