Unity

[Unity] GameManager 를 통해 Scene 아이디 주고받기 (TextMeshPro)

박도치 2023. 11. 28. 18:53

개요

LoadScene과 GameScene을 분리하여 player의 닉네임을 2글자 ~ 10글자 사이의 글자로 입력받는 것을 만들어보도록 할 예정이다.

 

그림으로 보자면 아래와 같은 느낌이다.

 

 

그러면 LoadScene부터 차근차근 알아보도록 하자!

 

1. LoadScene

LoadScene의 역할은 TextMeshPro를 이용해 input박스와 button을 활성화 시켜 input박스에 들어오는 이름을 GameScene의 아이디에 전달해줄 생각이다.

 

 

 

초기에 아무것도 안하고 생성만했을시 모습

 

먼저 button과 inputFiled를 각각 만들어주자. 한곳에 관리하기 위해 Panel밑에 생성하였다.

 

(1) InputFiled

InputFiled의 안을 들여다 보면 Text Area 안에 Placeholder 과 Text가 있다.

 

placeholder은 안에 default 값으로 들어있는 Enter text... 이부분이고 입력시에 지워지는 공간이다.

 

 

placeholder의 내용을 text input에 입력하여 커스텀 할 수 있고, 폰트사이즈 및 폰트를 설정할 수 있다.

 

그리고 left와 top을 이용해 placeholder의 글자 위치를 조정할 수 있다.

 

 

Font Asser Creator로 폰트를 뽑아내지 않으면 아마 한글의 경우 깨져서 나올것이다. 추후에 폰트를 뽑는 것도 포스트하여 링크를 걸어놓을 예정이다.

 

Text 는 입력시 입력받는 글자들을 Text이다

 

 

마찬가지로 폰트를 설정해두고 유니티 재생버튼을 눌러 input 박스내에 글자를 입력해보면 위 사진과 같이 입력될 것이다.

 

(2) Button

Button의 경우 버튼을 눌렀을 때 어떤 이벤트를 할당할 수 있는 역할을 한다. 현재는 스크립트나 버튼 클릭시에 일어나는 일이 없기에 클릭했을 때 버튼 클릭한 표시만 나고 아무일도 일어나지않는다.

 

 

 

(3) 스크립트 작성

 

그렇다면 버튼을 클릭했을 때 text가 출력되고 GameScene이 나오게 끔 해줘야한다. 이는 스크립트를 작성하여 코드로 이벤트를 주면된다.

 

테스트를 위해 output이라는 TextMesh 오브젝트를 생성한다.

 

output생성

 

- script생성 

 

Assets -> Scripts -> Text -> NameTag라는 스크립트를 하나 생성한다.

 

 

 

생성하면 위와같은 스크립트가 나온다. class명을 한번 확인하고 스크립트를 작성하도록 하자.

 

우리가 지금 받아와야 할 것들을 한번 생각해보도록 하자.

 

1. input창에 입력된 text

2. 클릭할 버튼

3. input창에 입력된 text를 출력할 output Text

 

그렇다면 받아올 세가지를 위에 차례차례 선언해주면 된다.

 

using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class NameTag : MonoBehaviour
{
    [SerializeField] private Button enterBtn; // 버튼
    [SerializeField] private TMP_InputField userNameInput; //inputFiled에서 입력받은 text
    [SerializeField] private TextMeshProUGUI userNameOutput; // 테스팅용으로 입력받은 text를 나타낼 output text
   

}

 

이러면 유니티에서 오브젝트를 받아올 수 있다.

 

세 가지를 선언했다면 이제는 버튼을 클릭했을 때 일어날 이벤트를 코드로 작성해주면된다.

 

 

버튼에 OnClick이벤트에 드래그 앤 드롭하여 이벤트를 주는 방법도 있지만, 여기서는 코드로 작성하여 관리하는 법으로 진행하도록 한다.

 

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

public class NameTag : MonoBehaviour
{
    [SerializeField] private Button enterBtn; // 버튼
    [SerializeField] private TMP_InputField userNameInput; //inputFiled에서 입력받은 text
    [SerializeField] private TextMeshProUGUI userNameOutput; // 테스팅용으로 입력받은 text를 나타낼 output text


    private void Awake()
    {
        // 버튼을 onClick 이벤트가 일어났을 때 호출될 메서드
        enterBtn.onClick.AddListener(OutputText);
    }

    private void OutputText()
    {
        // usernameInput의 text를 받아와 output의 text로 전환해준다.
        userNameOutput.text = userNameInput.text;
    }
}

 

 

다시 유니티로 돌아가 이 스크립트를 버튼에 Add Component해주도록 하자.

 

 

 

스크립트를 등록하면 우리가 이전에 받아야 할 세가지 목록들이 위에 나온다.

 

차례대로 Btn에는 버튼 오브젝트를, input에는 inputFiled를, Output에는 Output을 각각 전달하면 된다.

 

 

이제 실행 해보면 텍스트가 잘 들어오는것을 볼 수 있다.

 

 

여기까지 왔으면 반절은 왔다. 이제 각자 커스텀해주고 현재 output에서 전달받는 내용을 GameScene의 Player머리위에 전달해주도록 해야한다.

 

많은 방법들이 있겠지만, 여기서는 GameManager에서 id를 받아와서 이를 전달해주는 식으로 하도록 하겠다.

 

 

2. GameManager

(1) 스크립트 생성

LoadScene과 GameScene으로 나뉘어 있는데 GameScene에 빈 오브젝트인 GameManager를 생성하고, 스크립트도 GameManager를 생성하도록 하자.

 

 

GameManager라는 스크립트를 생성하면 아래와 같이 톱니바퀴 모양이 나오는데 그냥 유니티쪽에서 GameManager를 쓰려는구나 하고 아이콘을 변경시켜주는 거지 스크립트인거는 마찬가지이다.

 

그리고 빈 오브젝트인 GameManager에 스크립트 GameManager를 담아주면 준비는 완료된것이다.

 

 

(2) GameManager 스크립트 작성

- GameManager 싱글톤 사용 이유 및 장점

 

GameManger 스크립트는 싱글톤으로 작성되었다.

 

이는 GameManager에서 static으로 메모리에 등록하여 전역으로 원하는 스크립트에 접근하기 위해 싱글톤으로 작성하였다.

 

이러면 public으로 매 스크립트마다 연결하는 것을 방지하여 메모리 사용을 크게 줄일 수 있다는 장점이있다. 하지만 static을 너무 남발하면 이또한 과도한 메모리 사용이 문제가 되므로 GameManager 같은 전역으로 관리해야 할 때만 사용하도록 하자.

 

그렇다면 싱글톤으로 작성한 스크립트를 보도록 하자.

 

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

public class GameManager : MonoBehaviour
{

    private static GameManager _instance;

    /// <summary>
    /// 싱글톤
    /// </summary>
    public static GameManager Instance
    {
        get
        {
            if (_instance == null)
            {
                // _instance가 null 이면 GameObject에 "GameManager" 라는 오브젝트를 생성
                GameObject gameManagerObject = new GameObject("GameManager");
                // _instance 에 GameManager 컴포넌트 추가
                _instance = gameManagerObject.AddComponent<GameManager>();
                // DontDestroyOnLoad로 GameManagerobject가 씬 변환시 Destroy되지 않게끔 설정
                DontDestroyOnLoad(gameManagerObject);
            }
            return _instance;
        }
    }

    /// <summary>
    /// Double-Check Locking
    /// </summary>
    private void Awake()
    {
        if(_instance == null)
        {
            _instance = this; 
            DontDestroyOnLoad(this.gameObject);
        }
        else
        {
            // 인스턴스가 중복되어 생성될 경우 파괴해준다.
            Destroy(gameObject);
        }
    }

    // 받아올 playerId
    private string _playerId;
    
    // 프로퍼티
    public string playerId
    {
        get { return _playerId; }
        set { _playerId = value; }
    }

}

 

LoadScene에서 버튼을 클릭했을 때 GameManager에서 id를 받고 이를 GameScene으로 전달해야 하는데, LoadScene에서 이름을 입력하고 버튼을 누르면 Null이 뜨고 GameManager가 null 로 떠있는 현상이 일어나는 경우가 있다. 절대 내가 그것때문에 고생해서 그런거 아님 

 

그래서 처음에 싱글톤으로 생성을 해주고, 이후에 instance에 중복으로 생성되었는지 다시한번 체킹하면서 이를 완화해주는 역할을 위 코드에서 해주고있다.

 

그리고 playerId 변수를 생성해주고 이를 받아올 프로퍼티를 만들어 주면 GameManager의 역할은 끝이난다.

 

(3) LoadScene의 NameTag 수정

 

아까 테스팅을 위해 output텍스트를 생성했었는데 이제는 필요없으니 과감하게 지워주고, 버튼과 inputFiled만 남겨주도록 하자. 

 

그러면 LoadScene에서 받아올 스크립트는 아래와 같다.

 

using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEditor.SearchService;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

// InputNameText라고 이름을 변경함
public class InputNameText : MonoBehaviour
{
    [SerializeField] private Button enterBtn; //버튼 선언
    [SerializeField] private TMP_InputField userName; // 유저의 이름 선언
    // output은 GameScene에서 해야하므로 과감히 삭제

    /// <summary>
    /// 버튼 이벤트
    /// </summary>
    private void Awake()
    {
        enterBtn.onClick.AddListener(InputNameBtnEvent);
    }

    // 
    public void InputNameBtnEvent()
    {
        // 글자의 길이가 2 ~ 10
        if(userName.text.Length >= 2 && userName.text.Length <= 10)
        {
            // GameManager에 playerId 전달
            GameManager.Instance.playerId = userName.text;
            // scene 전환
            SceneManager.LoadScene("GameScene");
        }
        else
        {
            Debug.Log("안돼");
        }
    }
}

 

여기까지왔으면 정리하자면 LoadScene에서 입력한 아이디를 받아오고, 이를 GameManager에게 전달하면서 씬을 전환해주기 까지 했다.

 

그렇다면 이제 머리위에 입력받은 아이디를 나타나게만 하면된다. 위에서 output테스트를 하듯이 GameManager에서 받은 id를 전달해주도록 하자.

 

 

3. GameScene 이름 전달

전달받은 스크립트와 전달 받을 오브젝트를 먼저 생성해주자.

 

 

위의 Panel부분이 펭귄이라고 들어가있는 이름 부분이며 Panel 내에는 TMP가 들어있다. 그리고 OutputNameText라는 스크립트가 add되어있는것을 볼 수 있다.

 

 inputScript에서 OutputNameText라는 스크립트를 생성한 상태이다.

 

그렇다면 코드를 작성하고 output해주기만 하면 된다.

 

(1) OutputNameText 스크립트

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

public class OutputNameText : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI playerNameText; // output 선언 

    private void Start()
    {
        // GameManager에 담아둔 playerid 전달
        string playerName = GameManager.Instance.playerId;
        // 이를 output 해줌
        playerNameText.text = playerName;
    }

}

 

잘 보면 아까 테스팅할때 지웠던 부분을 마치 잘라온듯한 느낌과 같다.

 

output을 받을 곳을 TextMeshProUGUI로 선언하고, GameManager에 담은 아이디를 여기에 그대로 전달하여 나타내주면 끝이다.

 

 

그러면 다음과 같이 씬이 전환되면서 문제없이 이름이 전달되는 것을 볼 수 있다.

 

 

 

 

4. 마무리

마무리는 실수했거나 몰랐던 내용을 다시한번 돌아보는 시간을 갖도록 하겠다.

 

(1) TextMeshPro 버그 

 

TextMeshPro에서 버튼과 inputField를 사용하는데 처음에 버튼과 inputField 둘 다 작동이 안돼서 한시간정도 날린 것 같다. 지웠다가 다시 하니까 결국 해결됐는데 아마 모종의 버그로 EventSystem이 안들어간 모양이다.

 

(2) GameManager 싱글톤 및 중복생성

 

처음에 LoadScene에서 GameMager.Instance.playerId가 null값이 들어가서 무엇이 문제인지 해결하기 위해 이것 저것 찾다보니 싱글톤으로 처음에 생성해주지 않아서 일어났던 문제이다. 

 

뭣도모르고 아래 Awake() 부분만 사용해서 생성했더니 다른 Scene에서는 가져올 수 없는 상황이 되어 이러한 조치를 취했고, 이로 인해 고생은 했지만 GameManager에 대해 어느정도 알아가는 시간이 되었다.

'Unity' 카테고리의 다른 글

[프로그래머스] 삼총사 C#  (0) 2023.12.01
[Unity] 벡터 및 계산  (0) 2023.11.29
Unity 2D 캐릭터 움직임 주기  (2) 2023.11.27
New Input System  (3) 2023.11.24
[C#] 알고리즘 약수의 개수와 덧셈  (2) 2023.11.24