UI Manager - 모든 UI들을 관리 / 로직 포함
캔버스에 직접 스크립트 추가하여 나머지 UI들은 자동으로 연동 딱히 다른 클래스 만들어서 이를 상속 받아 팝업 형태 할 정도로 개수가 많지 않아서 단순하게 구현
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
public class UI_Manager : SingletonLocal<UI_Manager>
{
[SerializeField]
GameObject GameUI_Prefab;
public GameUI gameUI;
public ResultUI ResultUI_Obj;
int mLayer;
bool isCreatedResUI = false;
// 파이프 UI 용도
public Canvas pipeUI_CanvasPrefab = null;
Canvas pipeUI_Canvas;
// 서브 UI 용도 (결과창)
public Canvas subUI_CanvasPrefab = null;
Canvas subUI_Canvas;
// Start is called before the first frame update
void Awake()
{
Init();
}
private void Update()
{
}
public void Init()
{
mLayer = LayerMask.NameToLayer("UI");
// 서브캔버스 결과 (UI 전용) 세팅 및 카메라 세팅
pipeUI_Canvas = Instantiate(pipeUI_CanvasPrefab);
pipeUI_Canvas.worldCamera = Global.GetUI_Camera();
subUI_Canvas = Instantiate(subUI_CanvasPrefab);
subUI_Canvas.worldCamera = Global.GetUI_Camera();
gameUI = Instantiate(GameUI_Prefab, transform).GetComponent<GameUI>();
gameUI.Init();
}
public void ResetLevel()
{
// Init();
// GetComponent<Canvas>().worldCamera = Global.GetUI_Camera();
}
public Slot CheckForHoveredItem()
{
return CheckForHoveredItem(GetEventSystemRaycastResults());
}
public Slot CheckForHoveredItem(List<RaycastResult> listRaycastResult)
{
Slot tmpSlot = null;
for (int index = 0; index < listRaycastResult.Count; index++)
{
RaycastResult res = listRaycastResult[index];
if (res.gameObject.layer == mLayer)
tmpSlot = res.gameObject.GetComponentInChildren<Slot>();
}
return tmpSlot;
}
List<RaycastResult> GetEventSystemRaycastResults()
{
PointerEventData eventData = new PointerEventData(EventSystem.current);
eventData.position = Input.mousePosition;
List<RaycastResult> listRes = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventData, listRes);
return listRes;
}
public void ClearedGame()
{
if (isCreatedResUI ||
subUI_Canvas == null)
return;
Instantiate(ResultUI_Obj, subUI_Canvas.transform);
isCreatedResUI = true;
}
}
Score Manager - 모든 스코어 관리
이중 구조체로 선언, 프로퍼티로 해서 모든 값 변경은 해당 매니저가 관리 외부로부터 임의로 값을 수정해선 안됨
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 오직 스코어 관련
public class ScoreManager : SingletonGlobal<ScoreManager>
{
#region 스코어 관련
public struct GameScore
{
public int curPipes, totalPipes, move, best, percent;
}
GameScore _gameScore;
//
public GameScore gameScore
{
get => _gameScore;
}
#endregion
public bool IsGameEnded() => gameScore.curPipes == gameScore.totalPipes;
public string UpdateCurPipe(int val)
{
_gameScore.curPipes = val;
return _gameScore.curPipes.ToString();
}
public string UpdateTotalPipe(int val)
{
_gameScore.totalPipes = val;
return _gameScore.totalPipes.ToString();
}
public string UpdateMoveCnt() => (++_gameScore.move).ToString();
}
인게임
게임 진행상황을 관리해줄 GameUI.cs
아래는 각 버튼들을 가지고와서 자동으로 연동
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using static ScoreManager;
public class GameUI : MonoBehaviour
{
// 메인 UI
[SerializeField] Text mTxtLvl, mTxtSize;
// 서브 UI
[SerializeField] TextMeshProUGUI mTxtCur, mTxtMax, mTxtMove, mTxtBest, mTxtPercent;
ScoreManager scoreManager;
private void Awake()
{
scoreManager = ScoreManager.instance;
}
public void Init()
{
InitButtons();
InitTexts();
}
// ------- 버튼 관련 -------
void InitButtons()
{
// 버튼 초기화 O(n2)
BtnEvent btnEvent = UI_Manager.instance.GetComponent<BtnEvent>();
foreach (var button in GetComponentsInChildren<Button>())
{
UnityAction fn = null;
var name = button.name;
// 메뉴 버튼
if (name.Contains("Before"))
fn = btnEvent.GoToScreen;
// 옵션 버튼
else if (name.Contains("Option"))
fn = btnEvent.GoToOption;
// 되돌리기 버튼
else if (name.Contains("Undo"))
fn = btnEvent.Undo;
// 초기화 버튼
else if (name.Contains("Reset"))
fn = btnEvent.Reset;
button.onClick.AddListener(fn);
}
}
void InitTexts()
{
// 검색해서 할당
foreach (var txt in GetComponentsInChildren<TextMeshProUGUI>())
{
var arrName = txt.name.Split(' ', 5);
for (int i = 1; i < arrName.Length; i++)
{
if (arrName[i] == "Title")
break;
switch (arrName[i])
{
//case "Level": mTxtLvl = txt; break;
//case "Size": mTxtSize = txt; break;
case "Cur": mTxtCur = txt; break;
case "Max": mTxtMax = txt; break;
case "Movement": mTxtMove = txt; break;
case "Best": mTxtBest = txt; break;
case "Percent": mTxtPercent = txt; break;
}
}
}
UpdateTexts();
}
void UpdateTexts()
{
var gameScore = scoreManager.gameScore;
mTxtCur.SetText(gameScore.curPipes.ToString());
mTxtMax.SetText(gameScore.totalPipes.ToString());
mTxtMove.SetText(gameScore.move.ToString());
mTxtBest.SetText(gameScore.best.ToString());
mTxtPercent.SetText(gameScore.percent.ToString());
}
public void UpdateMoveTxt() => mTxtMove.SetText(scoreManager.UpdateMoveCnt());
public void UpdateCurPipeTxt(int val) => mTxtCur.SetText(scoreManager.UpdateCurPipe(val));
public void UpdateTotalPipeTxt(int val) => mTxtMax.SetText(scoreManager.UpdateTotalPipe(val));
}
결과창
Result UI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
public class ResultUI : MonoBehaviour
{
public Text gradeTxt, movementsTxt;
private void Awake()
{
InitButtons();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
var gameScore = ScoreManager.instance.gameScore;
int movements = gameScore.move;
int max = gameScore.totalPipes;
float res = (float)movements / max;
string resMsg = "";
if (res <= 1.5f)
resMsg = "퍼펙트";
else if (res > 1.5f &&
res <= 3.0f)
resMsg = "잘했어요";
else
resMsg = "괜찮아요";
gradeTxt.text = resMsg;
movementsTxt.text = $"{movements}번의 무브로 레벨을 완료했습니다.";
}
// ------- 버튼 관련 -------
void InitButtons()
{
// 버튼 초기화 O(n2)
BtnEvent btnEvent = UI_Manager.instance.GetComponent<BtnEvent>();
foreach (var button in GetComponentsInChildren<Button>())
{
UnityAction fn = null;
var name = button.name;
// 종료 버튼
if (name.Contains("Close"))
fn = btnEvent.Close;
// 메인 화면 버튼
else if (name.Contains("Next"))
fn = btnEvent.NextLevel;
// 힌트 버튼
else if (name.Contains("Hint"))
fn = btnEvent.FreeHint;
// 공유 버튼
else if (name.Contains("Share"))
fn = btnEvent.Share;
button.onClick.AddListener(fn);
}
}
}
'게임엔진 > 개인 플젝' 카테고리의 다른 글
[Outdated] 농장 시뮬레이터 개인작 (0) | 2024.04.30 |
---|---|
플레이어 방향에 따른 발사 위치 변경 (0) | 2024.04.23 |
Flow Free 2 - 슬롯(그리드)과 파이프(연결선) (0) | 2024.03.27 |
Flow Free 1 - 그리드 (맵) 생성 (0) | 2024.03.27 |
[Unity] Flow Free 게임 카피캣 만들기 (0) | 2023.12.05 |