-
[Unity 2D] Fly Bird 게임오버 UI 구현하기 (Best Score 저장, Button 구현)Unity 2D 2023. 3. 26. 15:22
Bird가 Death처리 됐을 때 GameOver 판넬이 나오면서
베스트 스코어와 현재 스코어가 같이 판넬 안에서 나타나고
버튼을 만들어서 다시 게임을 플레이 할 수 있도록 한다.
빈 오브젝트를 생성해서 GameOverUI 폴더를 만든다.
하이라키창 우클릭 → UI → Panel
이런 판넬이 하나 생긴다.
이게 바로 GameOver UI의 바탕(Background)이 된다.
파란 점을 마우스 클릭한 상태로 alt 키 혹은 opt 키를 클릭한다.
누른 상태로 원하는 크기를 조정하면
비율에 맞게 크기가 자동으로 맞춰져 편하게 설정할 수 있다.
파란 점 클릭한 상태로 → alt키 혹은 opt키 누른 상태로 → 크기 조정
실제 게임 씬에서는 이렇게 보인다.
이제 또 UI를 역량껏 꾸며보겠다..
일단 나는 이렇게 꾸밈..
그리고 꿀팁 하나
폰트 같은 걸 쓰다 보면 텍스트마다 효과가 동기화 되는 경우가 있는데
이렇게 폰트를 복사해서 이름을 지정하고 텍스트마다 다른 폰트를 사용하면
텍스트 각각 효과를 다르게 줄 수 있다.
이제 버튼을 만들어보자.
하이라키창 우클릭 → UI → Button 클릭 (TextMeshPro가 자동 생성됨)
버튼을 두 개 만들고 텍스트도 넣었다.
폴더 정리는 보기 편하게 정리했다.
UI 폴더
- 배경과 게임오버 텍스트
- 스코어 텍스트
- 버튼
사실 근데 그냥 자기 스타일대로 정리하면 된다.
새로운 스크립트를 만든다.
using UnityEngine; using TMPro; public class GameOverUI : MonoBehaviour { public TextMeshProUGUI bestScoreText; public TextMeshProUGUI scoreText; // UI가 SetActive 할 때 호출되는 함수 private void OnEnable() { int bestScore = PlayerPrefs.GetInt("BestScore", 0); if(GameManager.score > bestScore) { PlayerPrefs.SetInt("BestScore", GameManager.score); bestScore = GameManager.score; } bestScoreText.text = bestScore.ToString(); scoreText.text = GameManager.score.ToString(); } }
스코어를 경신했을 때 새로 저장할 변수, 현재 스코어 를 저장할 변수를 선언하고
인스펙터 창으로 숫자 텍스트 오브젝트를 드래그한다.
GameOver UI는 게임이 멈췄을 때 비활성화 상태였다가 활성화 되면서 딱 한 번만 나타나기 때문에
OnEnable 함수를 사용했다. 딱 한 번만 호출된다는 특징이 있다.
PlayerPrefs.GetInt("BestScore", 0);
→ key 값인 Best Score 을 0 값으로 불러온다. 이 값은 int형 변수 bestScore에 저장이 된다.
이때 만약 스코어가 Best Score (초기값인 0) 보다 크다면
PlayerPrefs.SetInt("BestScore", GameManager.score);
→ key값인 Best Score는 GameManager.score 로 저장이 된다.
그리고 int형 변수인 bestScore에 경신된 score 값을 새로 저장한다.
경신한 경우가 아니라면 best Score 값은 그대로 int형 변수인 bestScore에 저장된 값이 되고
현재 스코어 값도 GameManager.score 의 값이다.
플레이어 스크립트로 돌아가서 게임오버일 때 UI가 나타나도록 구현해보자.
public class Player : MonoBehaviour { // Jump 구현 Rigidbody2D rb; [SerializeField] float Speed = 5f; private bool keyJump = false; // Rotate 구현 [SerializeField] private float upRotate = 5f; [SerializeField] private float downRotate = -5f; private Vector3 birdRotation; // Move 구현 [SerializeField] private float moveSpeed = 5f; // Ready 구현 [SerializeField] private float readyPower = 0.3f; // 게임오버UI public GameObject GameOverUI; }
필드 선언부에 GameOverUI 를 선언하고 인스펙터 창에 오브젝트를 드래그한다.
{ void ShowDeathUI() { GameManager.isDeath = true; GameOverUI.SetActive(true); } void OnCollisionEnter2D(Collision2D coll) { if(coll.gameObject.tag == "Pipe" || coll.gameObject.tag == "Ground") { ShowDeathUI(); } } }
ShowDeathUI 메서드로 따로 빼서 죽음 처리하는 곳에 넣었다.
스코어와 UI가 제대로 적용이 된 걸 확인할 수 있다.
버튼 구현도 해보자.
Retry 버튼을 눌렀을 때 게임이 다시 시작되고
Menu 버튼을 눌렀을 때 메인화면으로 돌아가게 할 건데
메뉴화면은 맨 마지막에 할 거라서 그냥 Debug로 체크만 하도록 한다.
게임매니저에 메서드를 만든다.
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class GameManager : MonoBehaviour { // 플레이어 죽음 체크하기 public static bool isDeath = false; // 플레이어 시작 체크하기 public static bool isStart = false; // 스코어 public static int score = 0; void Start() { isDeath = false; isStart = false; score = 0; } public void Retry() { SceneManager.LoadScene(SceneManager.GetActiveScene().name); } public void Menu() { Debug.Log("메인메뉴"); } }
씬을 관리하는 것이기 때문에 네임스페이스에
uning UnityEngine.SceneManagement; 도 잊지 않고 입력해야 한다.
public void 를 사용해서 인스펙터 창에서 button의 함수로써 연결해줄 것이다.
GetActiveScene().name 은 현재 씬의 이름을 뜻한다.
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
→ 씬매니저를 통해 현재 씬을 다시 로드한다.
먼저 GameOverUI 오브젝트를 비활성화 시킨다.
Retry버튼을 누르면 인스펙터 창에 Button기능이 있다.
On Click()에서 클릭했을 때 호출할 함수를 선택한다.
On Click() 에서 + 버튼 클릭
아까 Retry메서드와 Menu메서드를 구현해놨던 GameManager 스크립트가 들어있는
게임매니저 오브젝트를 드래그해서 놓는다.
No Function → GameManager 클릭
Retry버튼에서는 Retry메서드를 선택한다. (현재 씬 다시 로드)
Menu버튼에서는 Menu메서드를 선택하면 된다. ( Debug.Log("메인메뉴"); )
게임씬에서 Menu버튼을 클릭할 때 나오는 값이다. 게임 씬에서 제대로 작동하는 걸 확인할 수 있다.
전체 코드
↓
더보기GameOverUI.cs
using UnityEngine; using TMPro; public class GameOverUI : MonoBehaviour { public TextMeshProUGUI bestScoreText; public TextMeshProUGUI scoreText; private void OnEnable() { int bestScore = PlayerPrefs.GetInt("BestScore", 0); if(GameManager.score > bestScore) { PlayerPrefs.SetInt("BestScore", GameManager.score); bestScore = GameManager.score; } bestScoreText.text = bestScore.ToString(); scoreText.text = GameManager.score.ToString(); } }
Player.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Player : MonoBehaviour { // Jump 구현 Rigidbody2D rb; [SerializeField] float Speed = 5f; private bool keyJump = false; // Rotate 구현 [SerializeField] private float upRotate = 5f; [SerializeField] private float downRotate = -5f; private Vector3 birdRotation; // Move 구현 [SerializeField] private float moveSpeed = 5f; // Ready 구현 [SerializeField] private float readyPower = 0.3f; // 게임오버UI public GameObject GameOverUI; void Start() { // RigidBody2D 컴포넌트를 rb라는 변수를 통해 가져온다 rb = this.GetComponent<Rigidbody2D>(); } void Update() { InputBird(); if(GameManager.isStart == false) { ReadyBird(); return; } RotateBird(); MoveBird(); } private void FixedUpdate() { // 게임 물리 연산은 FixedUpdate 메서드 안에서 진행한다 // 입력받은 Jump값이 true라면 if (keyJump == true) { // JumpBird메서드 받기 JumpBird(); // 그리고 다시 keyJump값은 false로 만들어준다 keyJump = false; } } void ReadyBird() { if (rb.velocity.y < 0) { rb.velocity = Vector2.up * readyPower; } } void JumpBird() { // Rigidbody의 velocity 는 Speed 만큼 올라간다 rb.velocity = Vector3.up * Speed; } void InputBird() { if(GameManager.isDeath == true) { return; } // 스페이스바 혹은 마우스 좌버튼을 눌렀을 때 keyJump |= Input.GetKeyDown(KeyCode.Space); keyJump |= Input.GetMouseButtonDown(0); // Bird가 시작했을 때 내려오지 않는 버그 수정 if(GameManager.isStart == false && keyJump == true) { GameManager.isStart = true; } } void RotateBird() { // upRotate와 downRotate를 누적해서 저장할 변수 degree 초기화 float degree = 0; if(rb.velocity.y > 0) { // upRotate 누적 degree = upRotate; } else if(rb.velocity.y < 0) { // downRotate 누적 degree = downRotate; } // birdRotation을 오일러각으로 변환하여 최댓값 30, 최솟값 -90을 받는다 birdRotation = new Vector3(0, 0, Mathf.Clamp((birdRotation.z + degree), -90, 30)); transform.eulerAngles = birdRotation; } void MoveBird() { if(GameManager.isDeath == true) { return; } // Bird가 앞으로 이동하는 것 구현하기 transform.Translate(Vector3.right * moveSpeed * Time.deltaTime, Space.World); } void GetScore() { GameManager.score++; } void ShowDeathUI() { GameManager.isDeath = true; GameOverUI.SetActive(true); } void OnTriggerEnter2D(Collider2D coll) { if(coll.gameObject.tag == "Score") { GameManager.isDeath = false; GetScore(); } } void OnCollisionEnter2D(Collision2D coll) { if(coll.gameObject.tag == "Pipe" || coll.gameObject.tag == "Ground") { ShowDeathUI(); } } }
GameManager.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class GameManager : MonoBehaviour { // 플레이어 죽음 체크하기 public static bool isDeath = false; // 플레이어 시작 체크하기 public static bool isStart = false; // 스코어 public static int score = 0; void Start() { isDeath = false; isStart = false; score = 0; } public void Retry() { SceneManager.LoadScene(SceneManager.GetActiveScene().name); } public void Menu() { Debug.Log("메인메뉴"); } }
'Unity 2D' 카테고리의 다른 글
[Unity 2D] Fly Bird 메뉴 타이틀 씬 만들기 (+ 스코어 초기화) (0) 2023.03.26 [Unity 2D] Fly Bird 대기화면 UI 구현하기 (Animation조금 활용) (0) 2023.03.26 [Unity 2D] Fly Bird 스코어 누적 count 하기 (+ 간단 버그 수정) (0) 2023.03.25 [Unity 2D] Fly Bird 충돌체와 충돌했을 때 Death 처리하기 (0) 2023.03.25 [Unity 2D] Fly Bird 파이프 프리팹 Spawn하기 (2) 2023.03.23