본문 바로가기
KDT/유니티 심화

23/09/11 LearnUGUI (Mission 저장하고 불러오기)

by 잰쟁 2023. 9. 11.
728x90

나는 말하는 감자.............

 

실행하는데 오류나서 무슨 문제인가 선생님도 몇 분동안 계속 봐주셨는데...

MissionData에 MonoBehaviour를 붙여놔서 그랬다,,,ㅜㅡㅠ 

 

**MonoBehaviour

- 컴포넌트에 필요한 기본 기능을 제공

- MonoBehaviour를 상속 받아야지만 컴포넌트 기능을 쓸 수 있음

=> 컴포넌트로 필요하지 않은 클래스는 MonoBehaviour가 필요 없음

나는 바보

 

Test06Main

using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
using UnityEditor;
using System.Linq;

public class Test06Main : MonoBehaviour
{
    [SerializeField] private UIMissionScrollview uIMissionScrollview;
    [SerializeField] private Button btnSave;

    private string fileName = "mission_infos.json";
    private string path;
    private List<MissionInfo> missionInfos;

    void Start()
    {
        //경로
        this.path = string.Format("{0}/{1}", Application.persistentDataPath, fileName);

        //missionData 불러오기
        DataManager.instance.LoadMissionData();

        //this.uIMissionScrollview.Init();

        //이벤트 부착
        this.btnSave.onClick.AddListener(() =>
        {
            this.Save();
        });


        //신규유저 판단 후
        if (this.IsNewbie())
        {
            //파일이 없다면 Data를 기반으로 MissionInfo
            List<MissionData> missionDatas = DataManager.instance.GetMissionDataList();

            //컬렉션 인스턴스화
            this.missionInfos = new List<MissionInfo>();

            foreach(MissionData data in missionDatas)
            {
                MissionInfo info = new MissionInfo(data.id, 0);
                this.missionInfos.Add(info);
            }

            Debug.Log("<color=yellow>신규유저임</color>");
        }
        else
        {
            Debug.Log("<color=yellow>기존유저임</color>");
            //파일이 있다면 불러와서 역직렬화(MissionInfo)
            this.LoadMissionInfos();
        }

        this.uIMissionScrollview.Init(this.missionInfos);
    }

    private bool IsNewbie()
    {
        Debug.Log(path);

        Debug.LogFormat("<color=yellow>File.Exists: {0}</color>", File.Exists(path));

        if (File.Exists(path))
        {
            //파일이 있다 = 기존유저
            return false;
        }
        else
        {
            //파일이 없다 = 신규유저
            return true;
        }
    }

    private void LoadMissionInfos()
    {
        Debug.LogFormat("path: {0}", path);
        string json = File.ReadAllText(path);

        //역직렬화
        this.missionInfos = JsonConvert.DeserializeObject<MissionInfo[]>(json).ToList();
    }

    //게임 정보 저장하기
    private void Save()
    {
        Debug.Log("Save!");
        Debug.Log(Application.persistentDataPath);

        //직렬화
        //대상: MissionCell의 id와 count
        List<UIMissionCell> cells = this.uIMissionScrollview.GetUIMissionCells();

        //직렬화 대상 객체 만들기
        List<MissionInfo> missionInfos = new List<MissionInfo>();
        foreach(UIMissionCell cell in cells)
        {
            Debug.LogFormat("Id: {0}, Count: {1}", cell.Id, cell.Count);
            MissionInfo info = new MissionInfo(cell.Id, cell.Count);
            missionInfos.Add(info);
        }

        //직렬화하기
        string json = JsonConvert.SerializeObject(missionInfos);
        Debug.Log(json);

        //파일로 저장하기
        Debug.Log(this.path);

        File.WriteAllText(path, json);
        Debug.Log("<color=yellow>Saved!</color>");

        EditorUtility.RevealInFinder(Application.persistentDataPath);
    }
}

UIMIssionScrollView

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

//UIMissionCell들을 관리
public class UIMissionScrollview : MonoBehaviour
{
    [SerializeField] private GameObject uiMissionCellPrefab;
    [SerializeField] private SpriteAtlas atlas;
    [SerializeField] private Transform content;

    //객체를 그룹화하고 관리하는 2가지 방법
    //1. 배열, 2. 컬렉션
    private List<UIMissionCell> uiMissionCells;

    public void Init(List<MissionInfo> missionInfos)
    {
        //컬렉션 사용하기 전에 반드시 인스턴스화
        this.uiMissionCells = new List<UIMissionCell>();

        Debug.LogFormat("icon_coin_pouch : <color=lime>{0}</color>", this.atlas.GetSprite("icon_coin_pouch"));

        //List<MissionData> missionDatas = DataManager.instance.GetMissionDataList();
        //for(int i =0; i < missionDatas.Count; i++)
        //{
        //    MissionData data = missionDatas[i];
        //    this.CreateUIMissionCell(data);           
        //}

        foreach(MissionInfo missionInfo in missionInfos)
        {
            this.CreateUIMissionCell(missionInfo);
        }
    }

    //info를 매개변수로 MissionCell 생성하는 메서드
    private void CreateUIMissionCell(MissionInfo info)
    {
        //content에 자식으로 uiMissionPrefab 게임오브젝트 생성
        GameObject go = Instantiate(this.uiMissionCellPrefab, this.content);
        UIMissionCell cell = go.GetComponent<UIMissionCell>();
        //UIMissionCell 초기화
        cell.Init(info,atlas);

        //컬렉션에 추가
        this.uiMissionCells.Add(cell);
    }

    //data를 매개변수로 MissionCell 생성하는 메서드
    private void CreateUIMissionCell(MissionData data)
    {
        //content에 자식으로 uiMissionPrefab 게임오브젝트 생성
        GameObject go = Instantiate(this.uiMissionCellPrefab, this.content);
        UIMissionCell cell = go.GetComponent<UIMissionCell>();
        //UIMissionCell 초기화
        cell.Init(data, atlas);

        //컬렉션에 추가
        this.uiMissionCells.Add(cell);
    }

    public List<UIMissionCell> GetUIMissionCells()
    {
        return uiMissionCells;
    }
}

UIMissionCell

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

public class UIMissionCell : MonoBehaviour
{
    public enum eState
    {
        Doing, Complete
    }

    [SerializeField] private GameObject doingGo;
    [SerializeField] private GameObject completeGo;
    [SerializeField] private TMP_Text txtMissionName;
    [SerializeField] private TMP_Text txtMissionDesc;
    [SerializeField] private Image icon;
    [SerializeField] private Button btn;
    [SerializeField] private TMP_Text txtProgress;
    [SerializeField] private Slider slider;
    [SerializeField] private TMP_Text[] arrRewardAmountTexts;
    [SerializeField] private Image[] arrRewardIcons;

    private eState state = eState.Doing;
    private MissionData data;
    private MissionInfo info;
    //Progress의 doingAmount
    //private int doingAmount = 0;


    public int Count => this.info.count;
    
    public int Id => this.data.id;

    public eState State
    {
        get
        {
            return this.state;
        }
        set
        {
            this.state = value;
            switch (this.state)
            {
                case eState.Doing:
                    this.doingGo.SetActive(true);
                    this.completeGo.SetActive(false);
                    break;
                case eState.Complete:
                    this.doingGo.SetActive(false);
                    this.completeGo.SetActive(true);
                    break;
            }
        }
    }

    public void Init(MissionInfo info, SpriteAtlas atlas)
    {
        this.info = info;

        this.data = DataManager.instance.GetMissionData(info.id);

        //---------------------------이게 왜 null 이야? ---------------------------

        Debug.LogFormat("data : {0}", this.data);

        //-------------------------------------------------------------------------

        this.state = eState.Doing;

        this.txtMissionName.text = data.name;
        this.txtProgress.text = string.Format("{0}/{1}",info.count, data.goal);

        string desc = string.Format(data.desc, data.goal);
        Debug.Log(desc);
        this.txtMissionDesc.text = desc;

        Sprite sp = atlas.GetSprite(data.icon_name);
        Debug.LogFormat("sp : {0}", sp);
        this.icon.sprite = sp;
        this.icon.SetNativeSize();
        //icon 크기 조정
        this.icon.rectTransform.sizeDelta = new Vector2(data.mission_icon_width, data.mission_icon_height);

        foreach (TMP_Text txtAmount in this.arrRewardAmountTexts)
            txtAmount.text = data.reward_amount.ToString();

        foreach (Image rewardIcon in this.arrRewardIcons)
        {
            rewardIcon.sprite = atlas.GetSprite(data.reward_icon_name);
            rewardIcon.SetNativeSize();

            //rewardIcon 사이즈 조정
            rewardIcon.rectTransform.sizeDelta = new Vector2(data.reward_icon_width, data.reward_icon_height);
        }

        float progress = (float)this.info.count / this.data.goal;
        Debug.LogFormat("{0}, {1}. <color=lime>{2}%</color>", this.data.id, this.data.name, progress * 100f);

        this.slider.value = progress;
    }

    public void Init(MissionData data, SpriteAtlas atlas)
    {

        this.data = data;


        Debug.LogFormat("data : {0}", this.data);

        this.state = eState.Doing;

        this.txtMissionName.text = data.name;
        this.txtProgress.text = string.Format("{0}/{1}",info.count, data.goal);

        string desc = string.Format(data.desc, data.goal);
        Debug.Log(desc);
        this.txtMissionDesc.text = desc;

        Sprite sp = atlas.GetSprite(data.icon_name);
        Debug.LogFormat("sp : {0}", sp);
        this.icon.sprite = sp;
        this.icon.SetNativeSize();
        //icon 크기 조정
        this.icon.rectTransform.sizeDelta = new Vector2(data.mission_icon_width, data.mission_icon_height); //this.rewardIcon.sprite = atlas.GetSprite(data.reward_icon_name);

        foreach (TMP_Text txtAmount in this.arrRewardAmountTexts)
            txtAmount.text = data.reward_amount.ToString();

        foreach (Image rewardIcon in this.arrRewardIcons)
        {
            rewardIcon.sprite = atlas.GetSprite(data.reward_icon_name);
            rewardIcon.SetNativeSize();

            //rewardIcon 사이즈 조정
            rewardIcon.rectTransform.sizeDelta = new Vector2(data.reward_icon_width, data.reward_icon_height);
        }

        float progress = (float)this.info.count / this.data.goal;
        Debug.LogFormat("{0}, {1}. <color=lime>{2}%</color>", this.data.id, this.data.name, progress * 100f);

        this.slider.value = progress;
    }

    public void ApplyCount(int count)
    {
        this.info.count = count;
        Debug.LogFormat("{0}({1})미션을 {2}개 진행 했습니다.", this.data.name, this.data.id, this.info.count);

        //0~1
        float percent = (float)this.info.count / this.data.goal;
        this.slider.value = percent;

        this.txtProgress.text = string.Format("{0}/{1}", info.count, data.goal);
    }

    public int GetGoal()
    {
        Debug.LogFormat("GetGoal : {0}", this.data);

        if (this.data == null) return -1;

        return this.data.goal;
    }
}

MissionData

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

public class MissionData
{
    public int id;
    public string name;
    public string desc;
    public int goal;
    public string icon_name;
    public int mission_icon_width;
    public int mission_icon_height;
    public int reward_amount;
    public string reward_icon_name;
    public int reward_icon_width;
    public int reward_icon_height;
}

MissionInfo

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

public class MissionInfo
{
    public int id;  //미션의 ID
    public int count; //수행한 미션의 수

    //생성자
    public MissionInfo(int id, int count)
    {
        this.id = id;
        this.count = count;
    }
}

UIMissionCellOnInspector

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.TerrainTools;

[CustomEditor(typeof(UIMissionCell))]
public class UIMissionCellOnInspector : Editor
{
    private int sliderValue;

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();  //기존꺼

        UIMissionCell cell = this.target as UIMissionCell;  //커스텀 에디트 대상 컴포넌트

        GUILayout.Space(10);  //10픽셀 띠고

        //플레이를 했을때만 보여주기
        if (Application.isPlaying) 
        {
            EditorGUILayout.BeginHorizontal();

            GUILayout.Label("0");

            this.sliderValue = EditorGUILayout.IntSlider(this.sliderValue, 0, cell.GetGoal());  //cell.GetGoal()

            GUILayout.Label(cell.GetGoal().ToString());

            GUILayout.EndHorizontal();

            if (GUILayout.Button("Apply Count"))
            {
                Debug.Log("미션 진행수를 반영합니다");
                cell.ApplyCount(this.sliderValue);  //UIMissionCell의 ApplyCount 메서드 호출
            }
        }
    }
}