1. 결과 시연 영상

2. Hierarchy 오브젝트 목록
3. 프리팹과 Recources 파일 목록
4. 스크립트 목록

 

5. 스크롤 뷰의 이동과 버튼을 통한 스크롤뷰 활성화/비활성화
6. 젬(Gem)이 구매하고자 하는 상자의 가격보다 적다면 구매 불가
7. 골드(Gold)와 젬(Gem) 구매시 현재 골드 및 젬 업데이트
8. 현재 골드/젬 데이터 연동(저장)
9. 저장된 골드/젬 로드

 

**전체 코드**

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

public class UserData
{
    public int id;
    public string player_name;
    public int gold_amount;
    public int gem_amount;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ChestData
{
    public int id;
    public string name;
    public int type;
    public int price;
    public string sprite_name;
}
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;

public class GoldData
{
    public int id;
    public string name;
    public int type;
    public int value;
    public float price;
    public string sprite_name;
}
using JetBrains.Annotations;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GemData
{
    public int id;
    public string name;
    public int type;
    public int value;
    public float price;
    public string sprite_name;
    
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UserData
{
    public int id;
    public string player_name;
    public int gold_amount;
    public int gem_amount;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test05UIMain : MonoBehaviour
{
    [SerializeField]
    private UIChestScrollView scrollView;
    [SerializeField]
    private UIGoldScrollView scrollViewGold;
    [SerializeField]
    private UIGemScrollView scrollViewGem;
    void Start()
    {
        AtlasManager.instance.LoadAtlases();
        DataManager.instance.LoadChestData();
        DataManager.instance.LoadGoldData();
        DataManager.instance.LoadGemData();
        DataManager.instance.LoadUserData();
        this.scrollView.Init();
        this.scrollViewGold.Init();
        this.scrollViewGem.Init();
    }
}
using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;

public class DataManager
{
    public static readonly DataManager instance = new DataManager();
    private Dictionary<int, ChestData> dicChestDatas = new Dictionary<int, ChestData>();
    private Dictionary<int, GoldData> dicGoldDatas = new Dictionary<int, GoldData>();
    private Dictionary<int, GemData> dicGemDatas = new Dictionary<int, GemData>();
    private Dictionary<int, UserData> dicUserDatas = new Dictionary<int, UserData>();
    private DataManager()
    {
    }

    public void LoadChestData()
    {
        var asset = Resources.Load<TextAsset>("Data/chest_data");
        var json = asset.text;
        var chestDatas = JsonConvert.DeserializeObject<ChestData[]>(json);
        foreach (var chestData in chestDatas)
        {
            this.dicChestDatas.Add(chestData.id, chestData);
        }
        Debug.LogFormat("<color=red>chest_data 로드 완료 {0}</color>", this.dicChestDatas.Count);
    }

    public void LoadGoldData()
    {
        var asset = Resources.Load<TextAsset>("Data/gold_data");
        var json = asset.text;
        var goldDatas = JsonConvert.DeserializeObject<GoldData[]>(json);
        foreach (var goldData in goldDatas)
        {
            this.dicGoldDatas.Add(goldData.id, goldData);
        }

        Debug.LogFormat("<color=green>gold_data 로드 완료 {0}</color>", this.dicGoldDatas.Count);
    }
    public void LoadGemData()
    {
        var asset = Resources.Load<TextAsset>("Data/gem_data");
        var json = asset.text;
        var gemDatas = JsonConvert.DeserializeObject<GemData[]>(json);
        foreach (var gemData in gemDatas)
        {
            this.dicGemDatas.Add(gemData.id, gemData);
        }

        Debug.LogFormat("<color=blue>gem_data 로드 완료 {0}</color>", this.dicGemDatas.Count);
    }

    public void LoadUserData()
    {
        string path = Path.Combine(Application.persistentDataPath, "user_data.json");
        if (File.Exists(path))
        {
            var json = File.ReadAllText(path);
            var userDatas = JsonConvert.DeserializeObject<UserData[]>(json);
            foreach (var userData in userDatas)
            {
                this.dicUserDatas.Add(userData.id, userData);
            }
        }
        else
        {
            Debug.LogError("user_data.json 파일이 존재하지 않습니다.");
        }

        Debug.Log("<color=white>user_data 로드 완료</color>");
    }

    public void SaveUserData()
    {
        var userDatas = this.dicUserDatas.Values.ToArray();
        var json = JsonConvert.SerializeObject(userDatas);
        string path = Path.Combine(Application.persistentDataPath, "user_data.json");
        File.WriteAllText(path, json);
        Debug.Log("<color=white>user_data 저장 완료 {0}</color>");
    }



    public List<ChestData> GetChestDataList()
    {
        return this.dicChestDatas.Values.ToList();
    }

    public List<GoldData> GetGoldDataList()
    {
        return this.dicGoldDatas.Values.ToList();
    }
    public List<GemData> GetGemDataList()
    {
        return this.dicGemDatas.Values.ToList();
    }
    public List<UserData> GetUserDataList()
    {
        return this.dicUserDatas.Values.ToList();
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.U2D;

public class AtlasManager : MonoBehaviour
{
    [SerializeField]
    private string[] arrAtlasNames;

    private Dictionary<string, SpriteAtlas> dicAtlases = new Dictionary<string, SpriteAtlas>();
    public static AtlasManager instance;

    private void Awake()
    {
        if (instance != null && instance != this)
        {
            Destroy(this);
        }
        else
        {
            instance = this;
        }

        DontDestroyOnLoad(gameObject);
    }

    public void LoadAtlases()
    {
        foreach (var atlasName in arrAtlasNames)
        {
            var atlas = Resources.Load<SpriteAtlas>(atlasName);
            this.dicAtlases.Add(atlasName, atlas);
        }

        Debug.LogFormat("{0}개의 아틀라스를 로드", this.dicAtlases.Count);
    }

    public SpriteAtlas GetAtlas(string atlasName)
    {
        return this.dicAtlases[atlasName];
    }
}
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class StatusUserController : MonoBehaviour
{
    [SerializeField]
    private TMP_Text txtGem; 
    [SerializeField]
    private TMP_Text txtGold;
    [SerializeField]
    private Button btnGemAdd;
    [SerializeField]
    private Button btnGoldAdd;
    [SerializeField]
    private TabMenuController tabMenuController;

    private void Start()
    {
       
        btnGemAdd.onClick.AddListener(() => tabMenuController.OnTabSelected(TabMenuController.TabType.GemPacks));
        btnGoldAdd.onClick.AddListener(() => tabMenuController.OnTabSelected(TabMenuController.TabType.GoldPacks));

       
        UpdateUserStatus();
    }

    public void UpdateUserStatus()
    {
        UserData userData = DataManager.instance.GetUserDataList()[0];

        txtGem.text = userData.gem_amount.ToString();
        txtGold.text = userData.gold_amount.ToString();
    }
}
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class TabMenuController : MonoBehaviour
{
    public GameObject chestScrollView;
    public GameObject goldScrollView;
    public GameObject gemScrollView;

    private Color selectedColor = new Color(246f / 255f, 225f / 255f, 156f / 255f);
    private Color defaultColor = Color.white;
    public enum TabType
    {
        ChestPacks = 0,
        GoldPacks = 1,
        GemPacks = 2
    }

    private void Start()
    {
        // 모든 Tap_Text의 LineFocus를 비활성화
        foreach (Transform child in transform)
        {
            var lineFocus = child.Find("LineFocus");
            if (lineFocus != null)
            {
                lineFocus.gameObject.SetActive(false);
            }
        }


        int index = 0;
        foreach (Transform child in transform)
        {
            var text = child.GetComponent<TMP_Text>();
            if (text != null)
            {
                text.color = defaultColor;

                TabType tabType = (TabType)index;
                Button button = child.gameObject.AddComponent<Button>(); // 버튼 컴포넌트 추가
                button.onClick.AddListener(() => OnTabSelected(tabType));
            }
            index++;
        }

        // 초기 상태 설정 (ChestPacks가 선택된 상태)
        OnTabSelected(TabType.ChestPacks);
    }

    public void OnTabSelected(TabType selectedTab)
    {
        foreach (Transform child in transform)
        {
            var text = child.GetComponent<TMP_Text>();
            var lineFocus = child.Find("LineFocus");
            TabType tabType = (TabType)child.GetSiblingIndex();

            if (tabType == selectedTab)
            {
                text.color = selectedColor;
                lineFocus.gameObject.SetActive(true);
            }
            else
            {
                text.color = defaultColor;
                lineFocus.gameObject.SetActive(false);
            }
        }

        // ScrollView 활성화/비활성화 처리
        switch (selectedTab)
        {
            case TabType.ChestPacks:
                chestScrollView.SetActive(true);
                goldScrollView.SetActive(false);
                gemScrollView.SetActive(false);
                break;
            case TabType.GoldPacks:
                chestScrollView.SetActive(false);
                goldScrollView.SetActive(true);
                gemScrollView.SetActive(false);
                break;
            case TabType.GemPacks:
                chestScrollView.SetActive(false);
                goldScrollView.SetActive(false);
                gemScrollView.SetActive(true);
                break;
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.U2D;
public class UIChestScrollView : MonoBehaviour
{
    [SerializeField]
    private GameObject uiChestCellAdPrefab;
    [SerializeField]
    private GameObject uiChestCellPrefab;
    [SerializeField]
    private GameObject uiChestCellBestPrefab;
    [SerializeField]
    private Transform content;

    [SerializeField] private StatusUserController statusUserController;

    private List<UIChestCell> cellList = new List<UIChestCell>();
    public void Init()
    {
        var chestDatas = DataManager.instance.GetChestDataList();
        foreach (var data in chestDatas)
        {
            UIChestCell cell = null;

            if ((UIChestCell.eChestType)data.type == UIChestCell.eChestType.Wooden) //UIChestCellAd
            {
                
                var go = Instantiate<GameObject>(this.uiChestCellAdPrefab, content);
                cell = go.GetComponent<UIChestCellAd>();
                var cellAd = cell as UIChestCellAd;
                cellAd.onClickAd = () =>
                {
                    Debug.LogFormat("{0}, 광고보기", cellAd.ChestType);
                };
            }
            else if ((UIChestCell.eChestType)data.type == UIChestCell.eChestType.Golden) //UIChestCellBest
            {

                var go = Instantiate<GameObject>(this.uiChestCellBestPrefab, content);
                cell = go.GetComponent<UIChestCell>();
               
            }
            else //UIChestCell
            {
                
                var go = Instantiate<GameObject>(this.uiChestCellPrefab, content);
                cell = go.GetComponent<UIChestCell>();
            }

            cell.onClickPrice = () => {
                int curruntGem = DataManager.instance.GetUserDataList()[0].gem_amount;

                if((curruntGem-cell.Price) < 0)
                {
                    Debug.Log("<color=red>Gem이 부족합니다. 구매를 할 수 없습니다.</color>");
                }
                else
                {
                    DataManager.instance.GetUserDataList()[0].gem_amount -= cell.Price;
                    Debug.LogFormat("{0} Chest 구매, 현재 Gem: {1}", cell.ChestType, DataManager.instance.GetUserDataList()[0].gem_amount);
                    statusUserController.UpdateUserStatus();
                    DataManager.instance.SaveUserData();
                }
               
            };

            cell.Init(data);

            this.cellList.Add(cell);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIGoldScrollView : MonoBehaviour
{
    [SerializeField] private GameObject uiTinyGoldCellPrefab;
    [SerializeField] private GameObject uiFistfulGoldCellPrefab;
    [SerializeField] private GameObject uiPouchGoldCellPrefab;
    [SerializeField] private GameObject uiBoxGoldCellPrefab;
    [SerializeField] private GameObject uiChestGoldCellPrefab;
    [SerializeField] private GameObject uiVaultGoldCellPrefab;

    [SerializeField]
    private Transform content;

    [SerializeField] private StatusUserController statusUserController;

    private List<UIGoldCell> cellList = new List<UIGoldCell>();
    public void Init()
    {
        var goldDatas = DataManager.instance.GetGoldDataList();
        foreach (var data in goldDatas)
        {
            UIGoldCell cell = null;

            
            if ((UIGoldCell.eGoldType)data.type == UIGoldCell.eGoldType.Tiny) //uiTinyGoldCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiTinyGoldCellPrefab, content);
                cell = go.GetComponent<UIGoldCell>();

            }
            else if ((UIGoldCell.eGoldType)data.type == UIGoldCell.eGoldType.Fistful) //uiFistfulGoldCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiFistfulGoldCellPrefab, content);
                cell = go.GetComponent<UIGoldCell>();

            }
            else if ((UIGoldCell.eGoldType)data.type == UIGoldCell.eGoldType.Pouch) //uiPouchGoldCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiPouchGoldCellPrefab, content);
                cell = go.GetComponent<UIGoldCell>();

            }
            else if ((UIGoldCell.eGoldType)data.type == UIGoldCell.eGoldType.Box) //uiBoxGoldCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiBoxGoldCellPrefab, content);
                cell = go.GetComponent<UIGoldCell>();

            }
            else if ((UIGoldCell.eGoldType)data.type == UIGoldCell.eGoldType.Chest) //uiChestGoldCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiChestGoldCellPrefab, content);
                cell = go.GetComponent<UIGoldCell>();

            }
            else if ((UIGoldCell.eGoldType)data.type == UIGoldCell.eGoldType.Vault) //uiVaultGoldCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiVaultGoldCellPrefab, content);
                cell = go.GetComponent<UIGoldCell>();

            }

            cell.onClickPrices = () => {
                DataManager.instance.GetUserDataList()[0].gold_amount += cell.Value;
                Debug.LogFormat("{0} of Gold 구매, 현재 Gold: {1}", cell.GoldType, DataManager.instance.GetUserDataList()[0].gold_amount);
                statusUserController.UpdateUserStatus();
                DataManager.instance.SaveUserData();
            };

            cell.Init(data);

            this.cellList.Add(cell);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIGemScrollView : MonoBehaviour
{
    [SerializeField] private GameObject uiTinyGemCellPrefab;
    [SerializeField] private GameObject uiFistfulGemCellPrefab;
    [SerializeField] private GameObject uiPouchGemCellPrefab;
    [SerializeField] private GameObject uiBoxGemCellPrefab;
    [SerializeField] private GameObject uiChestGemCellPrefab;
    [SerializeField] private GameObject uiVaultGemCellPrefab;

    [SerializeField]
    private Transform content;

    [SerializeField] private StatusUserController statusUserController;

    private List<UIGemCell> cellList = new List<UIGemCell>();
    public void Init()
    {
        var gemDatas = DataManager.instance.GetGemDataList();
        foreach (var data in gemDatas)
        {
            UIGemCell cell = null;


            if ((UIGemCell.eGemType)data.type == UIGemCell.eGemType.Tiny) //uiTinyGemCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiTinyGemCellPrefab, content);
                cell = go.GetComponent<UIGemCell>();

            }
            else if ((UIGemCell.eGemType)data.type == UIGemCell.eGemType.Fistful) //uiFistfulGemCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiFistfulGemCellPrefab, content);
                cell = go.GetComponent<UIGemCell>();

            }
            else if ((UIGemCell.eGemType)data.type == UIGemCell.eGemType.Pouch) //uiPouchGemCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiPouchGemCellPrefab, content);
                cell = go.GetComponent<UIGemCell>();

            }
            else if ((UIGemCell.eGemType)data.type == UIGemCell.eGemType.Box) //uiBoxGemCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiBoxGemCellPrefab, content);
                cell = go.GetComponent<UIGemCell>();

            }
            else if ((UIGemCell.eGemType)data.type == UIGemCell.eGemType.Chest) //uiChestGemCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiChestGemCellPrefab, content);
                cell = go.GetComponent<UIGemCell>();

            }
            else if ((UIGemCell.eGemType)data.type == UIGemCell.eGemType.Vault) //uiVaultGemCellPrefab
            {

                var go = Instantiate<GameObject>(this.uiVaultGemCellPrefab, content);
                cell = go.GetComponent<UIGemCell>();

            }

            cell.onClickPrices = () => {
                DataManager.instance.GetUserDataList()[0].gem_amount += cell.Value;
                Debug.LogFormat("{0} of Gem 구매, 현재 Gem: {1}", cell.GemType, DataManager.instance.GetUserDataList()[0].gem_amount);
                statusUserController.UpdateUserStatus();
                DataManager.instance.SaveUserData();
            };

            cell.Init(data);

            this.cellList.Add(cell);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class UIChestCell : MonoBehaviour
{
    public enum eChestType
    {
        Wooden,
        Silver,
        Golden,
        Epic,
        Legendary
    }

    [SerializeField]
    protected Button btnPrice;

    [SerializeField]
    protected eChestType chestType;

    [SerializeField]
    protected int price;

    [SerializeField]
    private TMP_Text txtName;

    [SerializeField]
    private Image icon;


    [SerializeField]
    private TMP_Text txtPrice;


    public eChestType ChestType
    {
        get
        {
            return chestType;
        }
    }


    public int Price => price;
    //public int Price  -> 동일한 기능을 하는 코드
    //{
    //    get { return this.price; }
    //}


    public System.Action onClickPrice;

    public virtual void Init(ChestData data)
    {
        Debug.LogFormat("[UIChestCell] Init : {0}", this.chestType);

        price = data.price;
        txtName.text = data.name;
        txtPrice.text = price.ToString();
        chestType = (eChestType)data.type;

        var atlas = AtlasManager.instance.GetAtlas("UIAtlas");
        icon.sprite = atlas.GetSprite(data.sprite_name);
        icon.SetNativeSize();

        btnPrice.onClick.AddListener(() => {
            onClickPrice();
        });
    }


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

public class UIGoldCell : MonoBehaviour
{
    public enum eGoldType
    {
        Tiny,
        Fistful,
        Pouch,
        Box,
        Chest,
        Vault
    }

    [SerializeField]
    public Button btnPrice;

    [SerializeField]
    protected eGoldType goldType;

    [SerializeField]
    protected int value;

    [SerializeField]
    protected float price;

    [SerializeField]
    private TMP_Text txtName;

    [SerializeField]
    private Image icon;

    [SerializeField]
    private TMP_Text txtValue;

    [SerializeField]
    private TMP_Text txtPrice;


    public eGoldType GoldType
    {
        get
        {
            return goldType;
        }
    }


    public int Value => value;

    public float Price => price;
    
    //public int Price  -> 동일한 기능을 하는 코드
    //{
    //    get { return this.price; }
    //}


    public System.Action onClickPrices;

    public virtual void Init(GoldData data)
    {
        Debug.LogFormat("[UIGoldCell] Init : {0}", this.GoldType);

        price = data.price;
        value = data.value;
        txtName.text = data.name;
        txtPrice.text = "US $" + price.ToString();
        txtValue.text = value.ToString() + " Gold";
        goldType = (eGoldType)data.type;

        var atlas = AtlasManager.instance.GetAtlas("UIAtlasGold");
        icon.sprite = atlas.GetSprite(data.sprite_name);
        icon.SetNativeSize();

        btnPrice.onClick.AddListener(() =>
        {
            onClickPrices();
        });

    }

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

public class UIGemCell : MonoBehaviour
{
    public enum eGemType
    {
        Tiny,
        Fistful,
        Pouch,
        Box,
        Chest,
        Vault
    }

    [SerializeField]
    public Button btnPrice;

    [SerializeField]
    protected eGemType gemType;

    [SerializeField]
    protected int value;

    [SerializeField]
    protected float price;

    [SerializeField]
    private TMP_Text txtName;

    [SerializeField]
    private Image icon;

    [SerializeField]
    private TMP_Text txtValue;

    [SerializeField]
    private TMP_Text txtPrice;


    public eGemType GemType
    {
        get
        {
            return gemType;
        }
    }


    public int Value => value;

    public float Price => price;


    public System.Action onClickPrices;

    public virtual void Init(GemData data)
    {
        Debug.LogFormat("[UIGemCell] Init : {0}", this.GemType);

        price = data.price;
        value = data.value;
        txtName.text = data.name;
        txtPrice.text = "US $" + price.ToString();
        txtValue.text = value.ToString();
        gemType = (eGemType)data.type;

        var atlas = AtlasManager.instance.GetAtlas("UIAtlasGem");
        icon.sprite = atlas.GetSprite(data.sprite_name);
        icon.SetNativeSize();

        btnPrice.onClick.AddListener(() =>
        {
            onClickPrices();
        });

    }
}

 

+ Recent posts