[UGUI연습] 스테이지 클리어 창 만들기
2023. 9. 6.

구현내용

 

-한 줄에 6개 씩 표시하므로 한 페이지에 표시되는 개수는 18개

   => 2페이지로 구현(총 28개의 스테이지가 있고 가정)

   => 이번페이지 버튼, 다음페이지 버튼 추가

-UIStage의 상태 : Lock, Doing, Complete

-닫기 버튼(팝업)

-뒤로가기 버튼(페이지)

-현재 페이지를 저장 해놔야함. 이전 페이지를 누르면 현재페이지 -1, 다음 페이지는 현재 페이지 +1

-1페이지일때는 이전 페이지로 가는 버튼이 보이면 안된다.

-마찬가지로 마지막 페이지일 경우 다음 페이지 버튼이 보이면 안된다.

 

 

 

Test04를 만들어준다.

 

grid 생성

-grid까지 만들고 grid에 grid layout Group 컴포넌트 추가

 

-UIStage를 프리팹으로 만들고 Object Pooling 해서 가져오려 한다.

오브젝트 풀링

-시작할때 오브젝트 풀을 생성해서 비활성화시켜둔다.(UIStagePool()메서드)

-필요할때마다 active해서 사용한다. 이 구현의 경우 시작할때 첫페이지는 꽉 차있으므로 전부 active시켜주기 위해 InitUIStage()메서드를 호출했다.

다음 스테이지로 넘어가는 버튼을 눌렀을 때 첫번째 페이지의 정보를 저장해둘 곳이 필요했다. 

이를 멤버 변수로 저장하며,

UpdatePage()메서드를 통해 불러오도록했다.

+) 아직 코드를 수정해야 한다. 피곤해서 여기까지ㅜㅜ

1. 다음 페이지 넘어갔을때 숫자 초기화 되지 않고 받아오기

2. 다음 페이지의 인덱스,상태도 저장하기

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

public class Test04UIStage : MonoBehaviour
{
    public enum eState{
        Lock,Doing,Complete
    }
    [SerializeField] private TMP_Text[] arrTxtStageNum;
    [SerializeField] private GameObject[] arrStateGo;    //0: lock, 1: doing, 2: complete

    public eState state;

    public void Init(int stageNum)
    {
        foreach (var tmpText in this.arrTxtStageNum)
        {
            tmpText.text = (stageNum+1).ToString();
        }
        this.InActiveAll();
        this.ChangeState(eState.Lock);
    }
    public void ChangeState(eState state)
    {
        this.state = state;
        int index = (int)this.state;
        this.InActiveAll();
        this.arrStateGo[index].SetActive(true);
    }

    private void InActiveAll()
    {
        foreach (var go in this.arrStateGo)
        {
            go.SetActive(false);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System;

public class Test04UIMain : MonoBehaviour
{

    [SerializeField] private Button btnPrev;
    [SerializeField] private Button btnNext;
    [SerializeField] private TextMeshProUGUI textMesh;
    [SerializeField] private Test04UIStageController stageController;//1페이지
    
  //  private List<Test04UIStageController> stageControllers;

    private int currPageNum = 1;//현재페이지 번호
    public int lastPageNum = 2;//마지막 페이지 번호

    private int stageNum;
    private int maxStageNum = 20;

    private Action onPrevStage;
    private Action onNextStage;
    // Start is called before the first frame update
    void Start()
    {

       // Debug.Log(this.stageController.uiStages.Count);
        this.btnPrev.onClick.AddListener(() => {
            if (this.currPageNum>0) {
                this.currPageNum--;
                this.onPrevStage();
            }                   
        });
        this.btnNext.onClick.AddListener(() => {
            if (this.currPageNum < this.lastPageNum)
            {
                this.currPageNum++;
                this.onNextStage();
             //   this.stageController.onClearpage();
            }
        });
       


        this.onPrevStage = () =>
        {
            Debug.Log("이전페이지로 이동");
            this.stageController.UpdatePage();
            //this.stageController.gameObject.SetActive(true);
           // this.stageController2.gameObject.SetActive(false);
        };

        this.onNextStage = () =>
        {
            Debug.Log("다음페이지로 이동");
            this.stageController.UnActivatePrevPage();
            this.stageController.InitUIStage();
            // this.stageController.InitUIStage();
            //update

        };
        
    }

    // Update is called once per frame
    void Update()
    {
        this.textMesh.text = string.Format("{0}/{1}", this.currPageNum, this.lastPageNum);
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using UnityEngine;
using UnityEngine.UI;
public class Test04UIStageController : MonoBehaviour
{
    private List<Test04UIStage> uiStages = new List<Test04UIStage>();
    public List<GameObject> uiPools = new List<GameObject>();
    private List<Button> buttonList = new List<Button>();
    [SerializeField] Test04UIMain main;
    public System.Action onClearpage;
    [SerializeField] GameObject UIStageGo;
    [SerializeField] GameObject gridGo;
    
    public int stageNum;
    private int totalStageNum = 28;//총 스테이지 수
    private int maxStageNum = 18;//한페이지 최대 수용량
    private int maxPageNum;//페이지 수
    private Test04UIStage.eState firstPageState;
    private int firstPageIndex;
    // Start is called before the first frame update
    void Start()
    {
        this.UIStagePool();//오브젝트 풀 생성
        //한 페이지 최대 수용량만큼 스테이지 생성
        //총 스테이지 수 == 페이지 수 * 한 페이지 최대 수용량 + 총스테이지 수%한페이지 수용량 
        // 페이지 수 == 총 스테이지 수/ 한 페이지 최대 수용량 
        //maxPageNum == totalStageNum/ maxStageNum
        //즉 총 스테이지 개수/페이지수 == 한 페이지의 스테이지 수이므로
        //Debug.Log((totalStageNum / maxStageNum)+1);
        this.maxPageNum = totalStageNum / maxStageNum + 1;
        Debug.Log(maxPageNum);
        Debug.Log(totalStageNum %maxStageNum);
        
       this.InitUIStage();

        if (this.stageNum == 0)
        {
            for (int i = 0; i < this.uiStages.Count; i++)
            {
                this.uiStages[i].Init(i);//시작 시 전부 lock
            }
        }    
        for(int i = 0; i < buttonList.Count; i++)
        {
            int index = i;
            this.buttonList[i].onClick.AddListener(() =>
            {
               // Debug.Log("Click!");
                this.firstPageState = this.checkState(index);
                this.firstPageIndex = index;
            });
        }
    }
    public void InitUIStage()
    {
        for (int i = 0; i < this.maxStageNum; i++)
        {
            GameObject go = this.GetUIStageInPool();
            go.SetActive(true);
            this.uiStages.Add(go.GetComponent<Test04UIStage>());
            this.uiStages[i].ChangeState(Test04UIStage.eState.Lock);//락 상태로 초기화
           // Debug.Log(this.uiStages[i]);
            this.buttonList.Add(go.GetComponent<Button>());
        }
    }

    public void UnActivatePrevPage()
    {
        for (int i = 0; i < this.maxStageNum; i++)
        {
            GameObject go = this.uiPools[i];
            go.SetActive(false);
            
        }
    }
    public void UpdatePage()
    {
        //state = this.state;
        //index = this.index;
        for (int i = 0; i < this.maxStageNum; i++)
        {
            GameObject go = this.uiPools[i];
            go.SetActive(true);
            if (this.firstPageIndex == i)//멤버 변수에 저장된 index일때. 즉 클릭한 인덱스
            {
                if (i != 0 && this.firstPageState != Test04UIStage.eState.Lock)
                {
                    for (int j = i - 1; j >=0; j--)
                    {//Doing인 인덱스 앞의 인덱스들의 경우 쭉 Complete로 만들어준다.
                        this.uiStages[j].ChangeState(Test04UIStage.eState.Complete);
                    }
                    }
                 else if (i != 0 && this.firstPageState == Test04UIStage.eState.Lock)
                {
                    this.uiStages[i - 1].ChangeState(Test04UIStage.eState.Doing);
                }
                this.uiStages[i].ChangeState(this.firstPageState);//해당 index 상태 변경
                Debug.Log(this.uiStages[i].state);
            }
        }

    }
    private void UIStagePool()
    {
        for (int i = 0; i < this.maxStageNum; i++)
        {//스테이지 생성- 리스트에 담기
            GameObject go = Instantiate<GameObject>(this.UIStageGo,this.gridGo.transform);
            go.SetActive(false); //생성 후 비활성화 해둔다.
            this.uiPools.Add(go);
           // this.uiStages.Add(go.GetComponent<Test04UIStage>());
        
        }
    }
    private GameObject GetUIStageInPool()
    {
        foreach(GameObject go in this.uiPools)
        {
            if (go.active == false)//비활성화 상태이면
            {
                return go;
            }
        }
        return null;
    }
    private Test04UIStage.eState checkState(int index)
    {
        
        //Debug.Log("CheckState");
        for (int i = 0; i < this.uiStages.Count; i++)
        {
            if(i== index)
            {
                if (this.uiStages[index].state == Test04UIStage.eState.Lock)
                {//lock 상태면 doing으로 변환                 
                    if (index == 0)
                    {
                        this.uiStages[index].ChangeState(Test04UIStage.eState.Doing);
                        return Test04UIStage.eState.Doing;
                    }
                    else
                    {
                        if (this.uiStages[i - 1].state != Test04UIStage.eState.Doing)
                        {//lock이고 이전 스테이지를 완료했다면
                            this.uiStages[index].ChangeState(Test04UIStage.eState.Doing);
                            return Test04UIStage.eState.Doing;
                        }
                        else
                        {
                            Debug.Log("이전 스테이지 미완료");
                            return Test04UIStage.eState.Lock;
                        }
                    }
                }
                else if (this.uiStages[index].state == Test04UIStage.eState.Doing)
                {//doing 상태면 complete로 변환
                    this.uiStages[index].ChangeState(Test04UIStage.eState.Complete);
                    return Test04UIStage.eState.Complete;
                    if (index == this.uiStages.Count-1)
                    {
                        Debug.Log("last stage clear");
                        //if (this.stageNum <2)
                        //{ this.onClearpage(); }
                        
                    }
                }
              
            }
           
        }
        return Test04UIStage.eState.Lock;
    }
  
}
myoskin