***UIPageStage는 UIStageController, 이전,다음 페이지 버튼, 페이지 쪽 수를 관리
***UIStageController에서는 UIStage들을 관리
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class Test04UIStageController : MonoBehaviour
{
[SerializeField]
private Test04UIStage[] uiStages;
private Dictionary<int, Test04UIStage.eState> dic = new Dictionary<int, Test04UIStage.eState>();
private int totalStages;
public event UnityAction onMoveNextEvent;
private UIPageStage.Page page;
public void Init(int totalStages, UIPageStage.Page page)
{
this.page = page;
Debug.LogFormat("Init : {0} ~ {1}, total : {2}", this.page.start, this.page.end, this.page.Total);
this.totalStages = totalStages;
for (int i = 0; i < this.totalStages; i++)
{
var stageNum = i + 1;
if (stageNum == 1)
{
dic.Add(stageNum, Test04UIStage.eState.Open);
}
else
{
dic.Add(stageNum, Test04UIStage.eState.Lock);
}
}
this.Clear(); //총 Stage를 넘어간 Stage는 비활성화
//이벤트 등록
for (int i = 0; i < this.page.Total; i++)
{
var uiStage = this.uiStages[i];
int idx = i;
uiStage.onClick = (stageNum, state) =>
{
Debug.LogFormat("stageNum: {0}, state: {1}", stageNum, state);
if (state != Test04UIStage.eState.Open) return;//오픈 상태에서만 동작
this.CompleteStage(uiStage);
int nextStageNum = stageNum + 1;
if (nextStageNum <= this.totalStages)
{
Debug.LogFormat("{0} ~ {1}, total : {2}", this.page.start, this.page.end, this.page.Total);
Debug.LogFormat("다음 스테이지 오픈 : {0}, page.end: {1}", nextStageNum, this.page.end);
//다음 UIStage가 현재 페이지에 있는지 확인
if (nextStageNum > this.page.end)
{
Debug.Log("다음 스테이지가 현재 페이지에 없음");
//데이터만 변경
this.dic[nextStageNum] = Test04UIStage.eState.Open;
//다음 페이지로 이동 버튼 눌렀을때 로직 실행
this.onMoveNextEvent();
}
else
{
Debug.Log("다음 스테이지가 현재 페이지에 있음");
Test04UIStage nextUIStage = this.uiStages[idx + 1];
Debug.LogFormat("nextUIStage: {0}", nextUIStage);
//데이터를 변경
this.dic[nextStageNum] = Test04UIStage.eState.Open;
//UI를 업데이트
nextUIStage.ChangeState(Test04UIStage.eState.Open);
//모든 스테이지들의 상태를 출력
for (int i = 0; i < this.totalStages; i++)
{
var num = i + 1;
Debug.LogFormat("{0} : {1}", num, this.dic[num]);
}
}
}
else
{
Debug.Log("마지막 스테이지");
}
};
int stageNum = page.start + i;
uiStage.Init(stageNum, this.dic[stageNum]);
}
}
private void CompleteStage(Test04UIStage uiStage)
{
if (uiStage.State == Test04UIStage.eState.Open)
{
this.dic[uiStage.StageNum] = Test04UIStage.eState.Complete;
//해당 스테이지 찾아 업데이트
uiStage.ChangeState(Test04UIStage.eState.Complete);
}
}
public void UpdateUI(UIPageStage.Page page)
{
this.page = page;
Debug.LogFormat("UpdateUI: {0} ~ {1}, total : {2}", this.page.start, this.page.end, this.page.Total);
for (int i = 0; i < this.totalStages; i++)
{
var stageNum = i + 1;
Debug.LogFormat("{0} : {1}", stageNum, this.dic[stageNum]);
}
this.Clear();
for (int i = 0; i < page.Total; i++)
{
var uiStage = this.uiStages[i];
int stageNum = page.start + i;
uiStage.UpdateUI(stageNum, this.dic[stageNum]);
}
}
private void Clear()
{
foreach (Test04UIStage uiStage in this.uiStages)
{
uiStage.Hide();
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIPageStage : MonoBehaviour
{
public struct Page
{
public int start;
public int end;
public int Total
{
get
{
return this.end - this.start + 1;
}
}
public Page(int start, int end)
{
this.start = start;
this.end = end;
}
}
private const int MAX_DISPLAY_STAGES = 18; //한페이지에 보여줄수있는 최대 UIStage 개수
[SerializeField] private Button btnPrev; //이전 페이지 버튼
[SerializeField] private Button btnNext; //다음 페이지 버튼
[SerializeField] private int totalStages = 28; //최대 UIStage 개수
[SerializeField] private Test04UIStageController stageController; //UIStage들을 관리 하는 컴포넌트
private int currentPage = 1; //현재 페이지 숫자
private int totalPage = -1;
public void Init()
{
//계산하기
this.totalPage = Mathf.CeilToInt((float)this.totalStages / MAX_DISPLAY_STAGES);
Page page = this.CalcStartEnd();
this.stageController.onMoveNextEvent += OnMoveNextEventHandler;
this.stageController.Init(totalStages, page); //초기화
this.btnNext.onClick.AddListener(() => {
this.MoveNext();
});
this.btnPrev.onClick.AddListener(() => {
this.MovePrev();
});
}
private void OnMoveNextEventHandler()
{
this.MoveNext();
}
private void OnDisable()
{
this.stageController.onMoveNextEvent -= OnMoveNextEventHandler;
}
private void MovePrev()
{
if (this.currentPage == 1)
{
Debug.Log("첫 페이지");
return;
}
this.currentPage -= 1;
Debug.LogFormat("currentPage: {0}", this.currentPage);
Page page = this.CalcStartEnd();
this.stageController.UpdateUI(page); //초기화
}
private void MoveNext()
{
if (this.currentPage == this.totalPage)
{
Debug.Log("마지막 페이지");
return;
}
this.currentPage += 1;
Debug.LogFormat("currentPage: {0}", this.currentPage);
Page page = this.CalcStartEnd();
Debug.LogFormat("<color=red>{0} ~ {1}, Total: {2}</color>", page.start, page.end, page.Total);
this.stageController.UpdateUI(page); //초기화
}
private Page CalcStartEnd()
{
Debug.LogFormat("총 스테이지 : {0}", this.totalStages);
Debug.LogFormat("마지막 페이지 : {0}", this.totalPage);
Debug.LogFormat("현재 페이지 : {0}", this.currentPage);
int end = this.currentPage * MAX_DISPLAY_STAGES;
//currentPage : 1
//end : 18
//18 - (18-1)
//start : 1
int start = end - (MAX_DISPLAY_STAGES - 1);
if (end >= this.totalStages)
{
end = this.totalStages;
}
return new Page(start, end);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Test04UIMain : MonoBehaviour
{
[SerializeField]
private UIPageStage uiPageStage;
void Start()
{
this.uiPageStage.Init();
}
}
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class Test04UIStage : MonoBehaviour
{
public enum eState
{
Lock, Open, Complete
}
public TMP_Text[] arrTxtStageNum;
public GameObject[] arrStateGo; //0: lock, 1: Open, 2: complete
public eState state;
public eState State
{
get
{
return this.state;
}
}
private Button btn;
public System.Action<int, eState> onClick;
private int stageNum;
public int StageNum
{
get
{
return this.stageNum;
}
}
public void Init(int stageNum, eState state)
{
this.stageNum = stageNum;
Debug.Log(stageNum);
this.btn = this.GetComponent<Button>();
foreach (var tmpText in this.arrTxtStageNum)
{
tmpText.text = stageNum.ToString();
}
this.btn.onClick.AddListener(() =>
{
this.onClick(this.stageNum, this.state);
});
this.state = state;
this.ChangeState(this.state);
this.gameObject.SetActive(true);
}
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 Show()
{
this.gameObject.SetActive(true);
}
public void Hide()
{
this.gameObject.SetActive(false);
}
public void UpdateUI(int stageNum, eState state)
{
this.stageNum = stageNum;
this.state = state;
foreach (var tmpText in this.arrTxtStageNum)
{
tmpText.text = stageNum.ToString();
}
this.ChangeState(this.state);
this.gameObject.SetActive(true);
}
}
21. 스크립트 작성 및 수정
***유의할 점
1. UIStage 오브젝트에 버튼 컴포넌트가 있는지 꼭 확인하기 -> 없으면 null 오류 발생
2. 보통 Canvas 생성시, EventSystem이 자동 생성되는데, 만약 Canvas만 복사해서 가져올 경우 EventSystem이 없을수도 있다. => 버튼 및 이벤트 트리거 동작 안함
'KDT > 유니티 심화' 카테고리의 다른 글
LearnUGUI 연습 (7. ShopChest 정적 스크롤뷰 관리 하는 스크립트 만들기) (0) | 2023.09.10 |
---|---|
LearnUGUI 연습 (6. ShopChest 정적 스크롤뷰 만들기) (0) | 2023.09.09 |
LearnUGUI 연습 (4. 데이터 연동을 통한 Stage 만들기) (0) | 2023.09.07 |
LearnUGUI 연습 (3. Stage 만들기) (0) | 2023.09.06 |
LearnUGUI 연습 (2. 버튼 만들기) (0) | 2023.09.05 |