유니티 심화

주말과제(Goldshop)

노재두내 2023. 9. 11. 02:42

1. 정적 스크롤뷰

<버튼 클릭하면 타입과 가격 나오기(가장기본)>

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

public class UIGoldCell : MonoBehaviour
{
    public enum eGoldType
    {
        Tiny,Fistful,Pouch,Box,Chest,Vault
    }
    [SerializeField]
    protected Button btnPrice;
    [SerializeField]
    protected eGoldType goldType;
    [SerializeField]
    protected float price;
    // Start is called before the first frame update
    void Start()
    {
        this.btnPrice.onClick.AddListener(() =>
        {
            Debug.LogFormat("타입:{0}, 가격:{1}", this.goldType, this.price);
        });
        
    }
    
}

전에 할 때는 왜 하는지 잘 모르겠었는데 집에서 천천히 하니까 확실히 이해되는느낌


<Init()을 이용해서 가격과 타입 출력하기>

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

public class UIGoldCell : MonoBehaviour
{
    public enum eGoldType
    {
        Tiny,Fistful,Pouch,Box,Chest,Vault
    }
    [SerializeField]
    protected Button btnPrice;
    [SerializeField]
    protected eGoldType goldType;
    [SerializeField]
    protected float price;
    // Start is called before the first frame update
    public void Init()
    {
        this.btnPrice.onClick.AddListener(() =>
        {
            Debug.LogFormat("타입:{0}, 가격:{1}", this.goldType, this.price);
        });
        
    }
    
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIGoldScrollView : MonoBehaviour
{
    [SerializeField]
    private UIGoldCell[] goldCells;
    // Start is called before the first frame update
    void Start()
    {
        for(int i = 0; i < goldCells.Length; i++)
        {
            UIGoldCell cell = goldCells[i];
            cell.Init();
        }
    }

    
}

결과는 첫번째(Init 사용x 가장기본) 과 같음 

init을 왜 하는지 이해되지 않았었는데 scollview 에서 관리하기 위함이라는것을 알게 되었음


<대리자를 이용>

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

public class UIGoldScrollView : MonoBehaviour
{
    [SerializeField]
    private UIGoldCell[] goldCells;
    // Start is called before the first frame update
    void Start()
    {
        for(int i = 0; i < goldCells.Length; i++)
        {
            UIGoldCell cell = goldCells[i];
            cell.onClickPrice = () =>
            {
                Debug.LogFormat("<color=blue>타입: {0},가격 {1}</color>", cell.GoldType, cell.Price);
            };
            cell.Init();
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIGoldCell : MonoBehaviour
{
    public enum eGoldType
    {
        Tiny,Fistful,Pouch,Box,Chest,Vault
    }
    [SerializeField]
    protected Button btnPrice;
    [SerializeField]
    protected eGoldType goldType;
    [SerializeField]
    protected float price;

    public System.Action onClickPrice;
    public eGoldType GoldType
    {
        get
        {
            return this.goldType;
        }
    }
    public float Price
    {
        get
        {
            return this.price;
        }
    }
    // Start is called before the first frame update
    public void Init()
    {
        this.btnPrice.onClick.AddListener(() =>
        {
            Debug.LogFormat("타입:{0}, 가격:{1}", this.goldType, this.price);
            this.onClickPrice();
        });
        
    }
    
}


 

<데이터 연동>

DataManager.cs

private Dictionary<int, GoldData> dicGoldDatas;
    public void LoadGoldData()
    {
        TextAsset asset = Resources.Load<TextAsset>("gold_data");
        Debug.Log(asset.text);
        GoldData[] arrGoldDatas = JsonConvert.DeserializeObject<GoldData[]>(asset.text);
        Debug.LogFormat("arrGoldDatas:{0}", arrGoldDatas.Length);
        this.dicGoldDatas = arrGoldDatas.ToDictionary(x => x.id);
    }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test07Main : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        DataManager.instance.LoadGoldData();
    }

   
}


Main만들고, this.chestScrollview.Init();

UIGoldScrollView컴포넌트 Init 메서드에서 상자정보를 출력

List<ChestData> chestDatas = DataManager.instance.GetChestDatas();

 

DataManager.cs에서 추가된 코드

public List<GoldData> GetGoldDatas()
    {
        return this.dicGoldDatas.Values.ToList();
    }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test07Main : MonoBehaviour
{
    [SerializeField]
    private UIGoldScrollView scrollView;
    // Start is called before the first frame update
    void Start()
    {
        DataManager.instance.LoadGoldData();
        this.scrollView.Init();
    }

}

 

MonoBehaviour 지움

 

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

public class GoldData
{
    public int id;
    public string name;
    public int type;
    public float price;
    public int amount;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIGoldScrollView : MonoBehaviour
{
    [SerializeField]
    private UIGoldCell[] goldCells;
    // Start is called before the first frame update
    public void Init()
    {
        List<GoldData> goldDatas = DataManager.instance.GetGoldDatas();
        
        foreach(GoldData data in goldDatas)
        {
            Debug.LogFormat("<color=yellow>id:{0}</color>,name:{1},type:{2},price:{3},amount:{4}", data.id, data.name, data.type, data.price, data.amount);
        }
    }
}

 

버튼 클릭하면 타입과 가격이 나오는 것이 안나왔는데 UIScrollView를 수정하면서 UI.GoldCell의 Init() 함수를 호출하지 않아 안나왔다 -> Start로 바꿈 

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

public class UIGoldCell : MonoBehaviour
{
    public enum eGoldType
    {
        Tiny,Fistful,Pouch,Box,Chest,Vault
    }
    [SerializeField]
    protected Button btnPrice;
    [SerializeField]
    protected eGoldType goldType;
    [SerializeField]
    protected float price;

    public eGoldType GoldType
    {
        get
        {
            return this.goldType;
        }
    }
    public float Price
    {
        get
        {
            return this.price;
        }
    }
    // Start is called before the first frame update
    void Start()
    {
        
        this.btnPrice.onClick.AddListener(() =>
        {
            Debug.LogFormat("타입:{0}, 가격:{1}", this.goldType, this.price);
            
        });
        
    }
    
}

 

ScrollView의 Init에서 상자정보를 출력하고 버튼 출력하면 상자 타입과 가격을 출력 

 



2. 동적 스크롤뷰

- UIGoldCell 프리팹 등록

<초기화 메서드 호출 (Data를 매개변수로 넘김)>

이름,가격 출력

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

public class UIGoldCell : MonoBehaviour
{
    public enum eGoldType
    {
        Tiny,Fistful,Pouch,Box,Chest,Vault
    }
    [SerializeField]
    protected Button btnPrice;
    [SerializeField]
    protected eGoldType goldType;
    [SerializeField]
    protected float price;
    [SerializeField]
    protected TMP_Text txtName;

    public eGoldType GoldType
    {
        get
        {
            return this.goldType;
        }
    }
    public float Price
    {
        get
        {
            return this.price;
        }
    }
    // Start is called before the first frame update
    public void Init(GoldData data)
    {
        this.price = data.price;
        this.txtName.text = data.name;
        this.btnPrice.onClick.AddListener(() =>
        {
            Debug.LogFormat("타입:{0}, 가격:{1}", this.txtName.text, this.price);
            
        });
        
    }
    
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIGoldScrollView : MonoBehaviour
{
    [SerializeField]
    private UIGoldCell[] goldCells;
    [SerializeField]
    private GameObject uiGoldPrefab;
    [SerializeField]
    private Transform content;
    // Start is called before the first frame update
    public void Init()
    {
        List<GoldData> goldDatas = DataManager.instance.GetGoldDatas();
        
        foreach(GoldData data in goldDatas)
        {
            Debug.LogFormat("<color=yellow>id:{0}</color>,name:{1},type:{2},price:{3},amount:{4}", data.id, data.name, data.type, data.price, data.amount);
            UIGoldCell cell = null;
            GameObject go = Instantiate<GameObject>(this.uiGoldPrefab, content);//content위치에 
            cell = go.GetComponent<UIGoldCell>();
            cell.Init(data);
            
        }
    }
}

이름과 가격은 잘 출력되는데 ui에서는 제대로 표현되지 않음 

다른분꺼 블로그 참고하여 했더니 제대로 표현됨

[SerializeField] 
    protected TMP_Text txtPrice;
this.txtPrice.text = string.Format("US${0}", this.price);

왜 그냥 price를 쓰면 안되는지 잘은 이해안되지만 이렇게 추가하니 해결됨

추가로 

Debug.LogFormat("이름:{0}, 가격:{1}", this.txtName.text, this.txtPrice);

왜 .text를 쓰는지 궁금해서 txtPrice.text라 안쓰고 그냥 txtprice라고만 치니 

이렇게 나옴 


+amount도 표시하기(log출력은 X)

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

public class UIGoldCell : MonoBehaviour
{
    public enum eGoldType
    {
        Tiny,Fistful,Pouch,Box,Chest,Vault
    }
    [SerializeField]
    protected Button btnPrice;
    [SerializeField]
    protected eGoldType goldType;
    [SerializeField] 
    protected TMP_Text txtPrice;
    [SerializeField]
    protected TMP_Text txtAmount;
    [SerializeField]
    protected TMP_Text txtName;
    [SerializeField]
    protected float price;

    public eGoldType GoldType
    {
        get
        {
            return this.goldType;
        }
    }
    public float Price
    {
        get
        {
            return this.price;
        }
    }
    // Start is called before the first frame update
    public void Init(GoldData data)
    {
        this.price = data.price;
        this.txtName.text = data.name;
        this.txtAmount.text = string.Format("{0} Gold",data.amount.ToString());
        this.txtPrice.text = string.Format("US ${0}", this.price);
        this.btnPrice.onClick.AddListener(() =>
        {
            Debug.LogFormat("이름:{0}, 가격:{1}", this.txtName.text, this.txtPrice.text);
            
        });
        
    }
    
}


<아틀라스>

 

ㅎsprite_name이 왜 필요한지 이제 깨달았다 .. ㅎ

계속 this.icon.sprite = atlas.GetSprite(data.sprite_name); 이부분에서 null exception이 나서 몇시간동안 계속 찾았는데 .. Atlas위치가 Resources아래에 있지 않았다 ..

 

[전체코드]

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.U2D;
using System;
public class AtlasManager : MonoBehaviour
{
    [SerializeField]
    private string[] arrAtlasNames;

    private Dictionary<string, SpriteAtlas> dicAtlases = new Dictionary<string, SpriteAtlas>();
    public static AtlasManager instance;
    // Start is called before the first frame update
    private void Awake()
    {
        if(instance!=null&& instance != this)
        {
            Destroy(this);
            throw new System.Exception("An instance of this singleton already exits.");
        }
        else
        {
            instance = this;
        }
        DontDestroyOnLoad(this.gameObject);
    }
    public void LoadAtlases()
    {
        foreach(var atlasName in this.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 System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
using System.Runtime.InteropServices.WindowsRuntime;
using Newtonsoft.Json.Bson;
using System.Linq;


public class DataManager :MonoBehaviour
{
    public static readonly DataManager instance = new DataManager();
    private Dictionary<int, ChestData> dicChestDatas = new Dictionary<int, ChestData>();
    
    // Start is called before the first frame update
    private DataManager()
    {

    }
    public void LoadChestData()
    {
        TextAsset asset = Resources.Load<TextAsset>("chest_data");
        Debug.Log(asset.text);

        ChestData[] chestDatas = JsonConvert.DeserializeObject<ChestData[]>(asset.text);
        foreach (ChestData data in chestDatas)
        {
            this.dicChestDatas.Add(data.id, data);
        }
        Debug.LogFormat("dicchestDatas:{0}", dicChestDatas.Count); 
    }

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

    private Dictionary<int, MissionData> dicMissionDatas;
    public void LoadMissionData()
    {
        //Resources 폴더에서 mossion_data에셋(Test asset)을 로드
        TextAsset asset = Resources.Load<TextAsset>("mission_data");
        //가져오기
        //string json = asset.text;
        Debug.Log(asset.text);
        //역직렬화
        MissionData[] arrMissionDatas = JsonConvert.DeserializeObject<MissionData[]>(asset.text);
        Debug.LogFormat("arrMissionDatas:{0}", arrMissionDatas.Length);
        //사전에 넣기
        this.dicMissionDatas = arrMissionDatas.ToDictionary(x => x.id);
    }
    public List<MissionData> GetMissionDatas()
    {
        return this.dicMissionDatas.Values.ToList();
    }
    private Dictionary<int, GoldData> dicGoldDatas;
    public void LoadGoldData()
    {
        TextAsset asset = Resources.Load<TextAsset>("gold_data");
        Debug.Log(asset.text);
        GoldData[] arrGoldDatas = JsonConvert.DeserializeObject<GoldData[]>(asset.text);
        Debug.LogFormat("arrGoldDatas:{0}", arrGoldDatas.Length);
        this.dicGoldDatas = arrGoldDatas.ToDictionary(x => x.id);
    }
    public List<GoldData> GetGoldDatas()
    {
        return this.dicGoldDatas.Values.ToList();
    }
}​
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityEngine.U2D;

public class UIGoldCell : MonoBehaviour
{
    public enum eGoldType
    {
        Tiny,Fistful,Pouch,Box,Chest,Vault
    }
    [SerializeField]
    protected Button btnPrice;
    [SerializeField]
    protected eGoldType goldType;
    [SerializeField] 
    protected TMP_Text txtPrice;
    [SerializeField]
    protected TMP_Text txtAmount;
    [SerializeField]
    protected TMP_Text txtName;
    [SerializeField]
    protected float price;

    [SerializeField]
    protected Image icon;
    public eGoldType GoldType
    {
        get
        {
            return this.goldType;
        }
    }
    public float Price
    {
        get
        {
            return this.price;
        }
    }
    // Start is called before the first frame update
    public void Init(GoldData data)
    {
        this.price = data.price;
        this.txtName.text = data.name;
        this.txtAmount.text = string.Format("{0} Gold",data.amount.ToString());
        this.txtPrice.text = string.Format("US ${0}", this.price);
        var atlas = AtlasManager.instance.GetAtlas("GoldAtlas");
        this.icon.sprite = atlas.GetSprite(data.sprite_name);

        this.btnPrice.onClick.AddListener(() =>
        {
            Debug.LogFormat("이름:{0}, 가격:{1}", this.txtName.text, this.txtPrice.text);
            
        });
    }
    
}

 

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

public class UIGoldScrollView : MonoBehaviour
{
    [SerializeField]
    private GameObject uiGoldPrefab;
    [SerializeField]
    private Transform content;
    [SerializeField]
    private SpriteAtlas atlas;
    
    // Start is called before the first frame update
    public void Init()
    {
        List<GoldData> goldDatas = DataManager.instance.GetGoldDatas();
        
        foreach(GoldData data in goldDatas)
        {
            Debug.LogFormat("<color=yellow>id:{0}</color>,name:{1},type:{2},price:{3},amount:{4},{5}", data.id, data.name, data.type, data.price, data.amount,data.sprite_name);
            UIGoldCell cell = null;
            GameObject go = Instantiate<GameObject>(this.uiGoldPrefab, content);//content위치에 
            cell = go.GetComponent<UIGoldCell>();
            cell.Init(data);
            
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test07Main : MonoBehaviour
{
    [SerializeField]
    private UIGoldScrollView scrollView;
    // Start is called before the first frame update
    void Start()
    {
        DataManager.instance.LoadGoldData();
        AtlasManager.instance.LoadAtlases();
        this.scrollView.Init();
    }

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

public class GoldData
{
    public int id;
    public string name;
    public int type;
    public float price;
    public int amount;
    public string sprite_name;
}