1. 초기 세팅 화면
2. 프리팹을 Hierarchy창으로 드래그해서 인스턴스화한 후, Unpack
3. 이름 수정 후, 비활성화
4. 줄에 맞추어 Image(UIStageController) 생성
5. 빈 오브젝트를 생성 (grid)
6. 왼쪽 상단으로 Alt+Shift를 통해 피벗과 위치 이동
7. grid에 Content Size Fiter 컴포넌트 부착, Preferred Size로 설정
7. grid에 Content Size Fiter와 Horizontal Layout Group 컴포넌트를 부착하고 Preferred Size로 설정
8. Image(UIStage) 생성 후, 아까 비활성 해 놓았던 btn들 자식객체로 설정, Alt+Shift로 위치 설정(중앙)
9. 한 줄의 스테이지 갯수에 맞추어 추가 생성
10. UIStage간에 공간 설정을 위해 grid의 Spacing 48.8로 설정
11. 데이터 연동을 위해 stage_info.json 파일 생성
12. 프로젝트의 Application.persistentDataPath에 저장(C:/Users/user/AppData/LocalLow/DefaultCompany/LearnUGUI/stage_info.json)
13. json 파일 연동을 위해 Newtonsoft Json 인스톨
14. 파일 역직렬화를 위한 StageData 스크립트 작성

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

public class UIStage : MonoBehaviour
{
    public enum eState
    {
        Lock, Doing, Complete
    }

    public TMP_Text[] arrTxtStageNum;

   
    public GameObject[] arrStateGo;    //0: lock, 1: doing, 2: complete

    public eState state;

    public int starCount = 0;

    [SerializeField]
    private GameObject[] starOn;


    public void Init(int stageNum)
    {
        foreach (var tmpText in this.arrTxtStageNum)
        {
            tmpText.text = stageNum.ToString();
        }

        this.ChangeState(eState.Lock);
    }
    public void ChangeState(eState state)
    {
        this.InActiveAll();
        this.state = state;
        int index = (int)this.state;
        this.arrStateGo[index].SetActive(true);
    }

    private void InActiveAll()
    {
        foreach (var go in this.arrStateGo)
        {
            go.SetActive(false);
        }
    }

    public void UpdateStars()
    {
        if (state == eState.Doing)
        {
            ChangeState(eState.Complete);
            starCount = 1;

            for(int i = 0; i < 3; i++)
            {
                starOn[i].SetActive(false);
            }

            starOn[starCount-1].SetActive(true);


            return;
        }

        if (state == eState.Complete && starCount < 3)
        {
            starCount++;
            starOn[starCount - 1].SetActive(true);

        }

    }

}
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
using Newtonsoft.Json;

public class UIStageController : MonoBehaviour
{
    [SerializeField]
    private UIStage[] arrUIStages;

    private List<StageData> stageDatas = new List<StageData>();

    private void Start()
    {
        LoadStageData();
        InitStages();
    }

    private void LoadStageData()
    {
        string path = Path.Combine(Application.persistentDataPath, "stage_info.json");
        if (File.Exists(path))
        {
            string json = File.ReadAllText(path);
            stageDatas = JsonConvert.DeserializeObject<List<StageData>>(json);
        }
        else
        {
            Debug.LogError("stage_info.json을 찾을 수 없습니다!");
        }
    }

    private void InitStages()
    {
        for (int i = 0; i < stageDatas.Count && i < arrUIStages.Length; i++)
        {
            arrUIStages[i].Init(stageDatas[i].stageNum);
            arrUIStages[i].ChangeState((UIStage.eState)stageDatas[i].state);

            int currentIndex = i; //클로저

            // 클릭을 위한 EventTrigger 설정
            EventTrigger trigger = arrUIStages[i].gameObject.GetComponent<EventTrigger>();
            if (trigger == null)
            {
                trigger = arrUIStages[i].gameObject.AddComponent<EventTrigger>();
            }
            EventTrigger.Entry entry = new EventTrigger.Entry();
            entry.eventID = EventTriggerType.PointerClick;
            entry.callback.AddListener((data) => { OnStageClicked((PointerEventData)data, arrUIStages[currentIndex]); });
            trigger.triggers.Add(entry);
        }
    }

    private void OnStageClicked(PointerEventData data, UIStage uiStage)
    {
        if (uiStage.state == UIStage.eState.Lock) // Lock
            return;

        // 현재 클릭한 스테이지의 인덱스
        int clickedStageIndex = System.Array.IndexOf(arrUIStages, uiStage);

        // 첫 번째 스테이지가 아니라면, 바로 전 스테이지의 상태를 확인
        if (clickedStageIndex > 0 && arrUIStages[clickedStageIndex - 1].state != UIStage.eState.Complete)
            return; // 바로 전 스테이지가 Complete 상태가 아니라면 리턴

        uiStage.UpdateStars();

        if (uiStage.state == UIStage.eState.Complete && uiStage.starCount == 3 && clickedStageIndex < arrUIStages.Length - 1)
        {
            arrUIStages[clickedStageIndex + 1].ChangeState(UIStage.eState.Doing);
        }

        // 현재 스테이지의 상태와 별의 수를 stageDatas에 업데이트
        stageDatas[clickedStageIndex].state = (int)uiStage.state;
        stageDatas[clickedStageIndex].starCount = uiStage.starCount;

        SaveStageData();  // stageDatas의 변경 내용을 stage_info.json파일에 저장
    }

    private void SaveStageData()
    {
        string path = Path.Combine(Application.persistentDataPath, "stage_info.json");
        string json = JsonConvert.SerializeObject(stageDatas);
        File.WriteAllText(path, json);
    }



}

15. UIStage 클릭을 통한 이미지 전환과 별(Star_On) 활성화를 위한 스크립트 수정

16. 씬 실행 직후의 화면 확인
17. 클릭시 다음와 같이 변환된다.
18. stage_info.json 파일을 열어보면 state와 starCount가 변경된 것을 확인 할 수 있다.
19. jsonViewer에서 Format후, 확인
20. 전체적인 실행 확인

 

*** StarCount 확인을 위해 클릭마다 별이 증가하며, 3개가 됬을시에 다음 Stage 오픈

*** Image에 Raycast Target 기능으로  Event Trigger를 통한 클릭 이벤트를 설정할때, Image 또는 자식 객체에 Button 컴포넌트가 있다면 Event Trigger가 작동하지 않는다.

+ Recent posts