하참이의 아이디어노트

Unity 강의 8일차 (3) - 게임 오버와 재시작 본문

Unity/Unity 기초

Unity 강의 8일차 (3) - 게임 오버와 재시작

하참이 2025. 1. 31. 10:30

본 강의는 다음 문서를 참고하여 제작하였습니다. 자세한 내용은 하단 링크를 참조하시거나 댓글로 질문 남겨주시면 성심성의껏 답변 드리겠습니다.

 

https://learn.unity.com/tutorial/5-3gang-geim-obeo?uv=2020.3&pathwayId=63ca4663edbc2a7be103183f&missionId=63c7676bedbc2a66daff99b1&projectId=63ca2415edbc2a5f480737d2#

 

5.3강 - 게임 오버 - Unity Learn

개요: 게임에 멋진 점수 카운터를 추가했지만 그 외에도 여러 획기적인 게임 UI 요소를 추가할 수 있습니다. 이 수업에서는 착한 타겟 오브젝트가 센서 밑으로 떨어질 때 표시되는 'Game Over' 텍스

learn.unity.com

 

 


 

UI로 제작해야 하는 부분은 게임 스타트 뿐 만 아니라 게임 오버와 재시작 등 제작해야 할 분이 많습니다.

 

이번 시간에는 게임 오버와 재시작을 만들어보며 UI를 조금 더 응용해봅시다.

 

 

Canvas 위에 TextMeshPro를 하나 더 생성 하나를 더 만들고, 이름을 Game Over Text로 변경합니다.

 

 

 

 

 

 

 

Game Over Text의 폰트와 크기, 위치를 조절해줍니다. (폰트는 라이브러리에서 제공합니다.)

 

 

 

 

 

하지만 지금 상태로는 게임 오버가 계속 게임 창에 나와있지요.

 

 

게임 오버의 조건을 만들고 게임 오버 상태가 아니면 해당 UI를 비활성화 하도록 하겠습니다. 착한 오브젝트가 땅에 떨어지면 게임 오버로 해보도록 하죠.

 

GameManager 스크립트를 다음과 같이 수정합니다.

 

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

public class GameManager : MonoBehaviour
{
    public List<GameObject> targets;
    private int score;
    public TextMeshProUGUI scoreText;
    public TextMeshProUGUI gameOverText;

    private float spawnRate = 1.0f;
    void Start()
    {
        StartCoroutine(SpawnTarget());
        score = 0;
        UpdateScore(0);
        gameOverText.gameObject.SetActive(false);
    }

    IEnumerator SpawnTarget()
    {
        while (true)
        {
            yield return new WaitForSeconds(spawnRate);
            int index = Random.Range(0, targets.Count);
            Instantiate(targets[index]);
        }
    }

    public void UpdateScore(int scoreToAdd)
    {
        score += scoreToAdd;
        scoreText.text = "Score : " + score;
    }

    public void GameOver()
    {
        gameOverText.gameObject.SetActive(true);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

 

 

Target 스크립트를 다음과 같이 수정합니다.

 

 

 

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

public class Target : MonoBehaviour
{
    private Rigidbody targetRb;

    private float minSpeed = 12;
    private float maxSpeed = 16;
    private float maxTorque = 10;
    private float xRange = 4;
    private float ySpawnPos = -6;

    private GameManager gameManager;
    public int pointValue;

    public ParticleSystem explosionParticle;

    void Start()
    {
        targetRb = GetComponent<Rigidbody>();
        targetRb.AddForce(RandomForce(), ForceMode.Impulse);
        targetRb.AddTorque(RandomTorque(), RandomTorque(), RandomTorque(), ForceMode.Impulse);
        transform.position = RandomSpawnPos();

        gameManager = GameObject.Find("GameManager").GetComponent<GameManager>();
    }

    Vector3 RandomForce()
    {
        return Vector3.up * Random.Range(minSpeed, maxSpeed);
    }

    float RandomTorque()
    {
        return Random.Range(-maxTorque, maxTorque);
    }

    Vector3 RandomSpawnPos()
    {
        return new Vector3(Random.Range(-xRange, xRange), ySpawnPos);
    }
    private void OnMouseDown()
    {
        Destroy(gameObject);
        Instantiate(explosionParticle, transform.position, explosionParticle.transform.rotation);
        gameManager.UpdateScore(pointValue);
    }

    private void OnTriggerEnter(Collider other)
    {
        Destroy(gameObject);
        if (!gameObject.CompareTag("Bad")) { gameManager.GameOver(); }
    }

    void Update()
    {
        
    }
}

 

 

 

 

이제 Bad Target에 Bad 태그를 달아주고, GameManager 스크립트 컴포넌트에 UI를 달아주고 실행해봅시다.

 

 

 

 

 

 

 

게임 오버가 되면 아이템 생성과 점수 집계를 멈춰야 합니다.

 

 

GameManager 스크립트를 다음과 같이 작성합니다.

 

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

public class GameManager : MonoBehaviour
{
    public List<GameObject> targets;
    private int score;
    public TextMeshProUGUI scoreText;
    public TextMeshProUGUI gameOverText;
    private float spawnRate = 1.0f;
    public bool isGameActive;

    void Start()
    {
        StartCoroutine(SpawnTarget());
        score = 0;
        UpdateScore(0);
        gameOverText.gameObject.SetActive(false);
        isGameActive = true;
    }

    IEnumerator SpawnTarget()
    {
        while (isGameActive)
        {
            yield return new WaitForSeconds(spawnRate);
            int index = Random.Range(0, targets.Count);
            Instantiate(targets[index]);
        }
    }

    public void UpdateScore(int scoreToAdd)
    {
        score += scoreToAdd;
        scoreText.text = "Score : " + score;
    }

    public void GameOver()
    {
        gameOverText.gameObject.SetActive(true);
        isGameActive = false;
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

 

isGameActive 부울을 만들어 게임 시작시 true, 게임 오버시 false로 만들어 게임 오버 상태인지 아닌지 체크합니다.

 

어려운 부분은 없습니다.

 

 

Target 스크립트의 OnMouseDown 함수를 다음과 같이 수정합니다.

 

 

    private void OnMouseDown()
    {
        if (gameManager.isGameActive)
        {
            Destroy(gameObject);
            Instantiate(explosionParticle, transform.position, explosionParticle.transform.rotation);
            gameManager.UpdateScore(pointValue);
        }
    }

 

 

 

이 역시 어려운 부분은 없습니다.

 

 

마지막으로 Restart 버튼을 제작해보도록 하겠습니다.

 

 

Canvas에서 우클릭으로 Button TextMeshPro를 제작합니다.

 

 

 

버튼 이름을 Restart Button으로 변경하고, 잠깐 GameOver Text를 활성화 해서 위치, 폰트, 크기를 조절합니다.

 

 

 

 

다시 GameOver와 Restart UI를 비활성화 하고 GameManager 스크립트를 다음과 같이 수정합니다.

 

 

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

public class GameManager : MonoBehaviour
{
    public List<GameObject> targets;
    private int score;
    public TextMeshProUGUI scoreText;
    public TextMeshProUGUI gameOverText;
    private float spawnRate = 1.0f;
    public bool isGameActive;
    public Button restartButton;

    void Start()
    {
        StartCoroutine(SpawnTarget());
        score = 0;
        UpdateScore(0);
        gameOverText.gameObject.SetActive(false);
        restartButton.gameObject.SetActive(false);
        isGameActive = true;
    }

    IEnumerator SpawnTarget()
    {
        while (isGameActive)
        {
            yield return new WaitForSeconds(spawnRate);
            int index = Random.Range(0, targets.Count);
            Instantiate(targets[index]);
        }
    }

    public void UpdateScore(int scoreToAdd)
    {
        score += scoreToAdd;
        scoreText.text = "Score : " + score;
    }

    public void GameOver()
    {
        gameOverText.gameObject.SetActive(true);
        isGameActive = false;
        restartButton.gameObject.SetActive(true);
    }

    public void RestartGame()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 

 

 

게임 오버가 아니면 비활성화, 게임 오버가 되면 활성화를 하도록 합니다.

 

또한 UnityEngine.SceneManagment의 LoadScene을 사용해 현재 씬을 불러와 게임을 다시 시작한 것 처럼 만들 도록 합니다.

 

SceneManager.GetActiveScene().name을 사용한 것을 보아 현재 씬의 이름을 가져오고, 이름을 사용해 씬을 불러오는 방식이 SceneManager.LoadScene()의 사용 방식임을 알 수 있습니다.

 

Restart 버튼에 RestartGame() 메소드를 할당하겠습니다.

 

 

 

 

 

 

 

이제 Restart 버튼을 누르면 게임이 재시작 하는 것을 확인 할 수 있습니다.