지우너

[Unity 3D Run] 게임 오버 UI(1) 본문

Project

[Unity 3D Run] 게임 오버 UI(1)

지옹 2023. 3. 16. 22:26

3.14는 게임 오버, 게임 클리어 등을 이미지 에셋으로 넣으려고 했다. 그런데 찾는 데에도 시간이 좀 걸리는 것 같았고, 시간은 계속 쓰는데 진도는 안 나가니까 조금 지쳤던 거 같다.

3.15와 3.16은 UI를 만들었는데, 점점 게임다워지는 모습이 뿌듯하면서도 난이도가 점점 올라가는 것 같아서 재미있음과 재미없음을 동시에 느꼈다... UI가 오브젝트 뒤에 보이는 현상만 해결하더라도 좀 나을 것 같은데 어떻게 해결해야할지 감이 안 잡힌다...

03.14

유니티 2D 게임제작, STUDIO SHIN 지음, 제이펍(2022)

p125. 이미지 UI 추가하기

계층 뷰의 + → UI → Image를 선택

계층 뷰에서 canvas 컴포넌트의 Render Mode 값을 ‘Screen Space-Camera’로 변경

Render Camera에 설정된 카메라의 범위 안에 Canvas를 담는다는 의미

‘Screen Space-Camera’로 설정하면 Order in Layer를 설정할 수 있게 된다.

UI가 반드시 맨 위에 올 수 있도록 가능한 큰 숫자를 설정한다.

계층 뷰의 Canvas를 선택한 상태에서 인스펙터 뷰에서 Render Camera의 입력 필드에 Main Camera를 드래그 앤 드롭 한다.

Canvas의 크기가 카메라의 영역 안에 들어온다.

03.15-03.16

전에 썼던 GameOver 스프라이트를 찾기 귀찮아서 그냥 텍스트로 넣었다.

나쁘지 않은 것 같기도 하고, UI가 들어가니까 이제야 뭔가 좀 게임같아진 느낌이다.

스테이지를 클리어 못했으면 재시작(RESTART)/단계 설정 씬(QUIT)으로 이동하는 버튼이 필요하다

계층 뷰의 + → UI → Legacy → Button 선택

패널로 UI를 묶어준다.

Canvas를 선택한 상태에서 +→UI→ Panel

Panel의 크기를 조정한 후 두 개의 버튼을 Panel의 자식으로 만든다.

Panel의 Color에 들어가 불투명도 a를 0으로 설정해준다(투명하게 만들기)

Canvas의 Order In Layer를 20으로 설정했는데 왜 다른 오브젝트 뒤에 표시 되는지 모르겠다.

 

Unity) 유니티에서 배경 뒤로 빼기, 오브젝트가 배경에 묻혀서 안 보일 때!

Canvas의 Layer는 UI이고, 다른 Player, Plane, Cube 오브젝트의 Layer는 Default이다. 아마 그래서 UI가 뒤에 배치되는 것 같다.Sorting Layer에 UI를 만들어 Default위에 표시되도록 만들고, 설정해줬는데도 문제가 해결되지 않았다.

GameManager 스크립트 만들기

GameManager를 Canvas에 어태치하기

Text를 안 보이게 만들었다가, GameOver 혹은 Game Clear했을 때 해당 문자로 표시되게 만들고 싶었다.

맨 처음 Text로 GameOver를 만들었다. 컴포넌트를 보니까 뭔가 .text로 접근할 수 있을 것 같다는 생각이 들었다. 그래서 그것을 이용하여 GameOver라는 텍스트를 Game Clear로 바꿀 수 있을 것 같다고 생각했다. 그런데 Text로 변수를 선언하니까 SetActive()를 사용할 수 없었다.

Text를 SetActive하는 방법을 생각해보다가 유니티 공식 문서에서 정답을 찾았다.

Scripting API: UI.Text.text - Unity - Manual

GameObject로 GameState를 선언해서 Hierarchy에 텍스트 오브젝트를 넣어준다.

그리고 private Text text를 선언해서 GetComponent<Text>()로 GameState의 Text에 접근한다.

그러면 GameState.SetActive(false);도 사용할 수 있고, 내가 원하던 text.text = "Game Clear!";를 이용하여 text 내용을 상황에 따라 바꾸는 것도 가능해진다.

// GameManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; // UI를 사용할 때 필p

public class GameManager : MonoBehaviour
{
    public GameObject GameState;// 게임 상태를 표시하는 오브젝트
    private Text text; // GameOver!/GameClear!를 표시
    public GameObject panel; // 패널
    public GameObject RestartButton;
    public GameObject QuitButton;

    // Start is called before the first frame update
    void Start()
    {
        text = GameState.GetComponent<Text>();
        panel.SetActive(false); // 패널숨기기
        GameState.SetActive(false); // 텍스트 숨기ㅑ
        
    }

    // Update is called once per frame
    void Update()
    {
        // 게임 클리어시 텍스트 바꾸고 패널, 텍스트 보이기
        // text.text = "Game Clear!";
        // panel.SetActive(true);
        // GameState.SetActive(true);

        // 게임 오버시 패널, 텍스트 보이기
        // panel.SetActive(true);
        // GameState.SetActive(true);
    }
}

근데 게임 클리어, 게임 오버를 어떻게 GameManager에게 알릴 수 있을지 고민이다.

일단 게임 중, 게임 클리어, 게임 오버 상태를 저장하기 위해 Player 스크립트의 코드를 살짝 수정했다.

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

// GetComponent<PlayerController>()는 PlayerController와 Player 스크립트가 같은 오브젝트에 붙어 있는걸 전제로 한다.
// [RequireComponent(typeof(PlayerController))] 코드를 적어줘서 이 부분이 에러를 내지 않게 됨.
[RequireComponent(typeof(PlayerController))]
public class Player : MonoBehaviour
{
    public enum State { playing, gameclear, gameover };
    State currentState;
    public float moveSpeed = 3.0f;
    protected bool dead;

    // moveVelocity를 다른 스크립트인 PlayerController로 전달해서 물리적인 부분들을 처리할 수 있도록 할 것
    // 그래서 PlayerController에 대한 레퍼런스를 가져와야합니다.
    PlayerController controller;

    void Start()
    {
        currentState = State.playing;
    }

    void Awake()
    {
        controller = GetComponent<PlayerController>();
    }

    void Update()
    {
        if (currentState==State.playing)
        {
            // Movement input 플레이어의 움직임을 입력 받는 것
            // 수평(Horizontal) 과 수직(Vertical) 방향에 대한 입력을 받고 싶으니
            // Input. 을 적고 GetAxis()를 호출해서 "Horizontal"을 넣습니다.
            // y값은 내버려 둬도 되며(0), 일정한 속도로 앞으로 가도록 moveSpeed를 넣어줬다.
            Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal") * moveSpeed, 0, moveSpeed);
            // 입력 받은 값을 방향으로 변환하고 움직임 속도를 곱할 겁니다.
            // 입력의 방향을 얻기 위해 moveInput를 정규화(nomalized)하여 가져옵니다 (nomarlized는 방향을 가리키는 단위벡터로 만드는 연산)
            // 거기에 moveSpeed를 곱해줍니다
            Vector3 moveVelocity = moveInput.normalized * moveSpeed;
            // controller에게 velocity값을 넘겨줌
            controller.Move(moveVelocity);
        }
    }

    public void Die()
    {
        dead = true;
        currentState = State.gameover;
        GameObject.Destroy(gameObject);
    }

}

게임 클리어는 도착지점 게임 오브젝트를 만들어 거기에 닿으면 게임 클리어가 되도록 만들면 될 것 같기는 한데, 뭔가 스크립트들을 연결하는 작업이 어려울 것 같다...ㅠㅠ