EasyCastleUNITY

유니티 데이터 연동 본문

유니티 심화

유니티 데이터 연동

EasyCastleT 2023. 9. 1. 17:13

사용할 asset들 제작 

썸네일 제작

포토샵으로 대략적인 구상

https://www.flaticon.com/

 

Free Icons and Stickers - Millions of images to download

Download Free Icons and Stickers for your projects. Images made by and for designers in PNG, SVG, EPS, PSD and CSS formats

www.flaticon.com

여기서 썸네일이 들어갈 적당한 frame 찾기

이 프레임을 사용함

포토샵에서 ctrl + shift + alt + S 해서 각각 따로 저장

 

데이터 json 화

hero data Table

https://shancarter.github.io/mr-data-converter/

 

Mr. Data Converter

 

shancarter.github.io

https://jsonviewer.stack.hu/

 

Online JSON Viewer

 

jsonviewer.stack.hu

을 통해 json으로 변화

json 파일

[
  {
    "id": "100",
    "name": "Alien",
    "max_hp": "100",
    "damage": "5",
    "prefab_name": "AlienDefault",
    "sprite_name": "thumb_alien"
  },
  {
    "id": "101",
    "name": "Bear",
    "max_hp": "110",
    "damage": "10",
    "prefab_name": "BearDefault",
    "sprite_name": "thumb_bear"
  },
  {
    "id": "102",
    "name": "Chemicalman",
    "max_hp": "120",
    "damage": "15",
    "prefab_name": "ChemicalmanDefault",
    "sprite_name": "thumb_chemicalman"
  },
  {
    "id": "103",
    "name": "Cowboy",
    "max_hp": "140",
    "damage": "20",
    "prefab_name": "CowboyDefault",
    "sprite_name": "thumb_cowboy"
  },
  {
    "id": "104",
    "name": "Jester",
    "max_hp": "150",
    "damage": "25",
    "prefab_name": "JesterDefault",
    "sprite_name": "thumb_jester"
  }
]

Resources 아래에 저장

유니티에서 읽어오기

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

public class App : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        TextAsset aseet = Resources.Load<TextAsset>("Data/hero_data"); //json은 안 붙임
        Debug.Log(aseet);
    }

}

패키지 매니저에서 

com.unity.nuget.newtonsoft-json

 

위에 이름을 통해 newtonsoft json 설치

Json 파일 역직렬화 

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

public class HeroData //정보 저장용 스크립트
{
    //id	name	max_hp	damage	prefab_name	sprite_name
    //int string int float string string
    public int id;
    public string name;
    public int max_Hp;
    public float damage;
    public string prefab_name;
    public string sprite_name;

}

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
using UnityEditor.VersionControl;

public class App : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        TextAsset aseet = Resources.Load<TextAsset>("Data/hero_data"); //json은 안 붙임
        Debug.Log(aseet);

        //역직렬화 
        HeroData[] heroDatas = JsonConvert.DeserializeObject<HeroData[]>(aseet.text);
        foreach (HeroData data in heroDatas)
        {
            Debug.LogFormat("{0} {1} {2} {3} {4} {5}", data.id, data.name, data.max_Hp, data.damage, data.prefab_name, data.sprite_name);
        }
    }

}

순회 결과

버튼에 따라서 다른 종류의 Hero 생성

전에 생성된 Hero는 지워진다. 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
using UnityEditor.VersionControl;
using System;
using UnityEngine.UI;

public class App : MonoBehaviour
{
    [SerializeField] private List<Button> btns;

    //프리팹이 저장될 변수 
    public List<GameObject> prefabs = new List<GameObject>();
    //생성된 객체가 저장될 변수
    private GameObject go;
    private GameObject hero;
    //생성된 객체의 id가 저장될 변수 
    int goId = 0;
    int id = 0;
    // Start is called before the first frame update
    void Start()
    {
        //데이터 로드 
        DataManager.instance.LoadHeroDatas();
        //프리팹 리소스 로드 
        this.LoadPrefabs();

        foreach (Button btn in btns)
        {
            btn.onClick.AddListener(() => {
                //자식의 text 저장
                string id = btn.GetComponentInChildren<Text>().text;
                //int로 변경 
                this.id = Convert.ToInt32(id);
                //저장된 id를 통해 영웅 생성
                this.MakeHero(this.id);
            });
            
        }
    }

    private void LoadPrefabs()
    {
       List<string> heroPrefabNames =  DataManager.instance.GetHeroPrefabNames();

        foreach(string prefabName in heroPrefabNames)
        {
            string path = string.Format("Prefabs/{0}", prefabName);
            Debug.Log(path);
            GameObject prefab = Resources.Load<GameObject>(path);
            this.prefabs.Add(prefab);
        }
        Debug.LogFormat("프리팹들이 로드 되었습니다. Count:{0}",this.prefabs.Count);    
    }

    private void MakeHero(int id)
    {
        if(this.go == null) //생성이 처음이면 
        {
            this.hero = new GameObject("Hero"); //Hero라는 이름의 GameObject 생성
            this.go = Instantiate(prefabs[id - 100]);
            this.go.transform.SetParent(hero.transform);
            goId = id;
            Debug.LogFormat("id: {0} 객체 생성", this.goId);
        }
        else
        {
            Destroy(this.go);
            this.go = Instantiate(prefabs[id - 100]);
            this.go.transform.SetParent(hero.transform);
            goId = id;
            Debug.LogFormat("id: {0} 객체 생성", this.goId);
        }
    }
}

파일이 있으면 기존유저, 없으면 신규유저(데이터 저장과 불러오기는 직렬화와 역직렬화 이용)

DataManager ->Resources에서 json 파일을 읽어온다.

옆에 사진은 Resources 파일의 현화 

 

 

 

 

using Newtonsoft.Json;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class DataManager 
{
    //싱글톤
   public static readonly DataManager instance = new DataManager();
    // 키/값
    private Dictionary<int, HeroData> dicHeroDats = new Dictionary<int, HeroData>();
    //생성자
    private DataManager()
    {

    }

    public void LoadHeroDatas()
    {
        TextAsset aseet = Resources.Load<TextAsset>("Data/hero_data"); //json은 안 붙임

        //역직렬화 
        HeroData[] heroDatas = JsonConvert.DeserializeObject<HeroData[]>(aseet.text);
        foreach (HeroData data in heroDatas)
        {
            Debug.LogFormat("{0} {1} {2} {3} {4} {5}", data.id, data.name, data.max_Hp, data.damage, data.prefab_name, data.sprite_name);
            this.dicHeroDats.Add(data.id, data);
        }

        Debug.LogFormat("HeroData 로드 완료 :{0}", dicHeroDats.Count);
    }

    public HeroData GetHeroData(int id)
    {
        return dicHeroDats[id];
    }

    public List<string> GetHeroPrefabNames()
    {
        List<string> list = new List<string>();
        foreach(HeroData data in this.dicHeroDats.Values) //저장된 사전의 value값은 HeroData들
        {
            list.Add(data.prefab_name);
        }
        return list;
    }

    public List<string> GetHeroSpriteNames()
    {
        List<string> list = new List<string>();
        foreach(HeroData data in this.dicHeroDats.Values)
        {
            list.Add(data.sprite_name);
        }
        return list;
    }

    public List<HeroData> HeroDatas()
    {
        return this.dicHeroDats.Values.ToList();
    }
}

HeroData: 정보들을 저장하는 클래스

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

public class HeroData //정보 저장용 스크립트
{
    //id	name	max_hp	damage	prefab_name	sprite_name
    //int string int float string string
    public int id;
    public string name;
    public int max_Hp;
    public float damage;
    public string prefab_name;
    public string sprite_name;

}

HeroInfo: 객체의 id와 변하는 데이터들을 저장하는 클래스

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

public class HeroInfo 
{
    public int id;
    //변하는 데이터 
    public float hp;
    public float damage;
    //생성자 
    public HeroInfo(int id, float hp, float damage)
    {
        this.id = id;
        this.hp = hp;
        this.damage = damage;
    }
}

App: 실제 실행 부분

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

public class App : MonoBehaviour
{
    [SerializeField] private List<Button> btns;
    //프리팹이 저장될 변수 
    public List<GameObject> prefabs = new List<GameObject>();

    [SerializeField]
    private SpriteAtlas atlas;

    [SerializeField]
    private UISlot[] uiSlots;

    [SerializeField] private Button loadBtn;

    //생성된 객체가 저장될 변수
    private GameObject heroModel;
    private GameObject heroGo;

    private HeroInfo heroInfo;

    private Hero hero; //실제 영웅 객체 

    //생성된 객체의 id가 저장될 변수 
    int goId = 0;
    int id = 0;
    // Start is called before the first frame update
    void Start()
    {
        //데이터 로드 
        DataManager.instance.LoadHeroDatas();
        //프리팹 리소스 로드 
        this.LoadPrefabs();

        //슬롯 초기화
        List<HeroData> heroDatas = DataManager.instance.HeroDatas();
        for(int i=0; i<heroDatas.Count;i++)
        {
            UISlot slot = this.uiSlots[i];
            HeroData data = heroDatas[i];
            Sprite sprite = this.atlas.GetSprite(data.sprite_name);
            slot.onClick = (id) => {
                this.CreateHero(id);
            };
            slot.Init(data.id, sprite);
        }

        string filePath = string.Format("{0}/hero_info.json", Application.persistentDataPath);

        loadBtn.onClick.AddListener(() => {
            if(this.heroGo == null)
            {
                string json = File.ReadAllText(filePath);
                HeroInfo heroInfo = JsonConvert.DeserializeObject<HeroInfo>(json);
                this.heroGo = new GameObject("Hero");
                this.heroModel = Instantiate(prefabs[heroInfo.id - 100], this.heroGo.transform);
                this.hero = this.heroGo.AddComponent<Hero>();
                this.CreateHero(heroInfo.id);
            }
        });

        if (File.Exists(filePath)) //있다, 기존유저 
        {
            Debug.Log("기존유저");
        for (int i = 0; i < 5; i++)
        {
            uiSlots[i].gameObject.SetActive(false);
        }
        this.loadBtn.gameObject.SetActive(true);
        }
    }

    private void LoadPrefabs()
    {
       List<string> heroPrefabNames =  DataManager.instance.GetHeroPrefabNames();

        foreach(string prefabName in heroPrefabNames)
        {
            string path = string.Format("Prefabs/{0}", prefabName);
            Debug.Log(path);
            GameObject prefab = Resources.Load<GameObject>(path);
            this.prefabs.Add(prefab);
        }
        Debug.LogFormat("프리팹들이 로드 되었습니다. Count:{0}",this.prefabs.Count);    
    }

    private void CreateHero(int id)
    {
        //Info 만들기 
        //신규 유저일 경우 새로운 HeroInfo 객체를 만들고 
        //기존 유저일 경우, hero_info.json파일을 로드해서 역직렬화 해서 HeroInfo 객체를 만든다. 

    
        //저장위치
        //Application.persistentDataPath
        string filePath = string.Format("{0}/hero_info.json", Application.persistentDataPath);
        // C:/Users/user/AppData/LocalLow/DefaultCompany/SaveAndLoad
        if (File.Exists(filePath)) //있다, 기존유저 
        {
            Debug.Log("기존유저");
        }
        else
        {
            //신규유저
            Debug.Log("신규유저");
            this.loadBtn.gameObject.SetActive(false);
            HeroData heroData = DataManager.instance.GetHeroData(id);
            heroInfo = new HeroInfo(heroData.id, heroData.max_Hp, heroData.damage);
            this.CreateModelAndGo(id);
            string json = JsonConvert.SerializeObject(this.hero.GetInfo());
            Debug.LogFormat("<color=yellow>저장되는 json:{0}</color>", json);

            File.WriteAllText(filePath, json);
        }
        //HeroController 컴포넌트에 model과 info를 넘겨야 함 

    }

    private void CreateModelAndGo(int id)
    {
        //--------------------------모델 생성---------------------------------
        if (this.heroModel == null) //생성이 처음이면 
        {
            this.heroGo = new GameObject("Hero"); //Hero라는 이름의 GameObject 생성
            this.heroModel = Instantiate(prefabs[id - 100]);
            this.heroModel.transform.SetParent(heroGo.transform);

            this.hero = heroGo.AddComponent<Hero>();
            //HeroController 컴포넌트에 model과 info를 넘겨야 함 
            hero.Init(heroInfo, heroModel);
            goId = id;
            Debug.LogFormat("id: {0} 객체 생성", this.goId);
        }
        else
        {
            //Destroy(this.model);
            //this.model = Instantiate(prefabs[id - 100]);
            //this.model.transform.SetParent(heroGo.transform);
            //goId = id;
            //Debug.LogFormat("id: {0} 객체 생성", this.goId);
            Debug.LogFormat("<color=red>id : {0} 영웅이 있어 만들 수 없습니다</color>", this.goId);
        }
    }
}

Hero: 영웅들의 정보와 model에 대한 정보를 받아 저장한다.  실제 영웅 오브젝트

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

public class Hero : MonoBehaviour
{
    //영웅의 정보와, model에 대한 정보를 init으로 저장하고 있다. 
    private HeroInfo heroInfo;
    private GameObject model;

    public void Init(HeroInfo heroInfo, GameObject model)
    {
        this.heroInfo = heroInfo;
        this.model = model;

        Debug.LogFormat("Init:{0}, {1}", this.heroInfo, this.model);
    }

    public HeroInfo GetInfo()
    {
        return this.heroInfo;
    }
}

UISlot -> 슬롯에 대한 정보를 저장하는 클래스

슬롯의 인스펙터

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

public class UISlot : MonoBehaviour
{
    private int id;
    public System.Action<int> onClick;
    [SerializeField]
    private Button btn;
    [SerializeField]
    private Image img;

    public void Init(int id, Sprite sp)
    {
        this.id = id;

        //sprite_name
        //atals 
        img.sprite = sp;

        this.btn.onClick.AddListener(() => {
            this.onClick(this.id);
        });
    }

    // Update is called once per frame
    void Update()
    {

    }
}

실행하면

1. 신규유저라면, (경로의 파일이 없으면) 슬롯이 5개 나오고 슬롯을 누르면 

    해당 하는 영웅이 생성된다. 영웅을 생성하고 영웅에 대한 정보를 json 파일인 hero_info.json이라는 이름으로 저장한다.

 

2. 기존유저라면, (경로의 파일이 있다면) 기존의 슬롯이 나오지 않고,

   이미 영웅을 가지고 있으니, 버튼을 눌러 영웅을 로드하라는 버튼이 나오고 이 버튼을 누르면, 저장한 영웅이 로드 된다.  

신규유저 일 때 실행 영상
기존유저 일때 실행 상황

지금은 기존의 슬롯이 전부 사라지지만, 

조금 고쳐서, 새로운 버튼이 나오는 것이 아닌, 

저장하고 있는 영웅의 버튼만 제외하고, sprite를 자물쇠로 바꾸고, 버튼을 비활성화 시켜 동작하지 않는 방식으로 

바꾸어 보려고 한다. 

 

이 이후는 다음 포스트에서 이어서 하겠다. 

'유니티 심화' 카테고리의 다른 글

유니티 GUI  (0) 2023.09.04
Hero SHooter 개발일지 2  (0) 2023.09.03
Hero Shooter 새로운 Input System 활용한 조이스틱 이동  (0) 2023.09.01
Hero Shooter new Input System Test  (0) 2023.08.31
HeroShooter 개발일지1  (0) 2023.08.30