유니티 프로그램

[유니티] UNITY 플레이시간(타이머)을 다음 씬(SCENE)까지 끊김없이 흐르게 하려면 어떻게 해야 할까요?

비도르 2022. 8. 9. 21:21

[유니티] UNITY 플레이시간(타이머)을 다음 씬(SCENE)까지 끊김없이 흐르게 하려면 어떻게 해야 할까요?

 

안녕하세요. 오늘도 평화롭게 눅진한 구름이 흘러가는 8월의 어느 여름날입니다.

게임을 진행할 때 시간을 계속 흐르게 하면서 씬을 변경해야 할 때가 있습니다. 또는 씬을 바꿔도 배경음악은 계속 플레이해야 합니다. 

 

이때 사용하는 것이 스크립터 API 중에 DontDestroyOnLoad() 입니다.


How??? 어떻게 사용하는지 알아보겠습니다.

 

1. 시작할 때 타이머를 포함하는 Canvas를 GameObject로해서 DontDestroyOnLoad(gameobject) 를 적용하면 됩니다.

public GameObject tstObject;

DontDestroyOnLoad(tstObject);

 

; 위와같이 하면  타이머가 포함된 Canvas를 드래그앤드랍으로 게임오브젝트로 넣으면, 다음 씬까지 파괴되지 않고 그대로 연결되는것을 볼 수 있습니다. 아래의 예를 통해서 알아보겠습니다.


[예제1]  타이머를 다음 씬까지 끊김없이 가져가기

-. 먼저 타이머를 생성해야겠습니다. 아래와 같이 Timer라는 이름으로 텍스트를 하나 가운데에 생성해서 배치하고 버턴 두개를 그림과 같이 배치합니다. 그리고 , 씬의 구분을 위해서 큐브를 하나 생성해서 두도록 하겠습니다.

Timer 설명_첫번째 씬 화면배치

두번째 씬은 아래와 같이 미리 만들어 두겠습니다.

Timer 설명_두번째 씬 화면배치

그리고 아래와 같이 Build Settings에서 씬을 추가해 두었습니다. 당연한 얘기겠지만, 추가하지 않으면 동작하지 않습니다.

 

그리고 아래와 같이 TestTimer라는 이름으로 스크립터를 생성해서 Timer 오브젝트에 넣고 실행하면 타이머가 잘 동작하는 것을 확인 할 수 있습니다.

using System.Collections;
using UnityEngine;
using UnityEngine.UI; //네임스페이스 추가

public class TestTimer : MonoBehaviour
{
    
    float tstTime; //증가시킬 시간을 넣을 변수
    int tstMsec; //msec를 넣을 변수
    int tstSec; //sec를 넣을 변수
    int tstMin; //Min을 넣을 변수

    private void Start()
    {
        StartCoroutine("TimerGo"); //코루틴 시작
    }

    IEnumerator TimerGo()
    {
        while (true)
        {
            tstTime += Time.deltaTime; //시간을 증가시킴
            tstMsec = (int)((tstTime - (int)tstTime) * 100); //시간에서 소숫점만 남겨서 밀리초를 계산 
            tstSec = (int)(tstTime % 60); //시간에서 60으로 나눈 나머지를 구해서 초를 계산
            tstMin = (int)(tstTime / 60 % 60); // 시간에서 60으로 나누고 다시 60으로 나눈 나머지를 구해서 분을 계산 

            GetComponent<Text>().text = string.Format("{0:00}:{1:00}:{2:00}", tstMin, tstSec, tstMsec); // 텍스트에 포맷을 정해서 출력

            yield return null;
        }
    }
}

 

-. 이제 버턴(Scene Change Button1)을 클릭하면 다음 씬으로 넘어가는 것을 만들어 보겠습니다.

먼저 'GameManager'라는 이름으로 빈오브젝트를 만들고, 'SceneChage1'라는 이름으로 아래와 같이 스크립터를 생성해서 넣습니다. 

using UnityEngine;
using UnityEngine.SceneManagement; //네임스페이스 추가

public class SceneChage1 : MonoBehaviour
{
    public void ChangeScene()
    {
        SceneManager.LoadScene("2nd"); // 다음 씬으로 넘어감
    }    
}

 

그리고, 버턴(Scene Change Button1)에 있는 Inspector 창의 Onclick 이벤트에 드래그앤드랍으로 아래와 같이 넣어줍니다.

Onclick 이벤트 추가

 

그리고 , TextTimer 스크립터에 다음과 같이 DontDestroyOnLoad(tstObject)를 추가하고, 변수 tstObject에는 Canvas를 드래그앤드랍으로 넣어주면 Canvas 자식 레벨에 있는 타이머까지 그대로 파괴되지 않고 다음 씬으로 넘어갑니다.

using System.Collections;
using UnityEngine;
using UnityEngine.UI; //네임스페이스 추가

public class TestTimer : MonoBehaviour
{
	
    public GameObject tstObject; //Canvas안에 있는 오브젝트를 그대로 다음 씬으로 넘기기 위한 변수
    
    float tstTime; //증가시킬 시간을 넣을 변수
    int tstMsec; //msec를 넣을 변수
    int tstSec; //sec를 넣을 변수
    int tstMin; //Min을 넣을 변수

    private void Start()
    {
    	DontDestroyOnLoad(tstObject); //다음 씬으로 오브젝트 Canvas를 파괴없이 넘김
        
        StartCoroutine("TimerGo"); //코루틴 시작
    }

    IEnumerator TimerGo()
    {
        while (true)
        {
            tstTime += Time.deltaTime; //시간을 증가시킴
            tstMsec = (int)((tstTime - (int)tstTime) * 100); //시간에서 소숫점만 남겨서 밀리초를 계산 
            tstSec = (int)(tstTime % 60); //시간에서 60으로 나눈 나머지를 구해서 초를 계산
            tstMin = (int)(tstTime / 60 % 60); // 시간에서 60으로 나누고 다시 60으로 나눈 나머지를 구해서 분을 계산 

            GetComponent<Text>().text = string.Format("{0:00}:{1:00}:{2:00}", tstMin, tstSec, tstMsec); // 텍스트에 포맷을 정해서 출력

            yield return null;
        }
    }
}

 

 

이제 실행하고 나서 버턴(Scene Change Button1)을 클릭하면 다음 씬으로 타이머가 끊김없이 흘러가는 것을 확인 할 수 있습니다.

 


2. 주의 할 점은 다시 처음 씬으로 돌아오게 되면 처음 씬에 있던 기존의 타이머가 그대로 로드가 되기 때문에 타이머가 두개가 되어버린다는 점입니다. 그래서 다시 처음 씬으로 돌아올 때는 Find 함수를 사용해서 기존 타이머를 파괴하는 작업을 하셔야 합니다. ^^

 

; 버턴(Scene Change Button2)  클릭해서 타이머가 두개가 되는 것을 아래의 예를 통해서 확인해 보겠습니다.

 

[예제2]  DontDestroyOnLoad()함수를 통해서 두개의 타이머가 생성됨

 -. ' SceneChage1 ' 스크립터에 원래 씬으로 돌아가기 위한 함수를 아래와 같이 추가합니다.

using UnityEngine;
using UnityEngine.SceneManagement; //네임스페이스 추가

public class SceneChage1 : MonoBehaviour
{
    public void ChangeScene()
    {
        SceneManager.LoadScene("2nd"); // 다음 씬으로 넘어감.Scene[1]
    }    
    
    public void ChangeScene2()
    {
        SceneManager.LoadScene("SampleScene"); // 원래 씬으로 돌아감.Scene[0]
    }
}

 

그리고, 버턴(Scene Change Button2)에 있는 Inspector 창의 Onclick 이벤트에 드래그앤드랍으로 아래와 같이 넣어줍니다.

 

Onclick 이벤트2

 

그런 다음에 실행해서 다음 씬에서 버턴(Scene Change Button2)을 클릭해서 원래 씬으로 오면 아래와 같이 타이머두개가 중첩이 된 것을 확인 할 수 있습니다.

Timer 충첩


※ 참고

; ' GameManager ' 게임오브젝트는 ' Canvas '안의 자식레벨로 이동해 있어야 합니다. 그렇지 않으면 다음 씬에서는 파괴되어서 버턴이 동작하지 않게 됩니다.


 

[예제3]  두개의 타이머가 생성되지 않도록 하기

 -. ' TestTimer ' 스크립터에서 처음 시작할 때 똑같은 TestTimer오브젝트 타입이 있는지 확인하고, 있으면 기존 Canvas를 파괴하고 아니면 DontDestroyObject() 하라는 식으로 아래와 같이 변경합니다.

 

using System.Collections;
using UnityEngine;
using UnityEngine.UI; //네임스페이스 추가

public class TestTimer : MonoBehaviour
{
	
    public GameObject tstObject; //Canvas안에 있는 오브젝트를 그대로 다음 씬으로 넘기기 위한 변수
    
    float tstTime; //증가시킬 시간을 넣을 변수
    int tstMsec; //msec를 넣을 변수
    int tstSec; //sec를 넣을 변수
    int tstMin; //Min을 넣을 변수

	private void Start()
    {
        var obj = FindObjectsOfType<TestTimer>(); // TestTimer 타입을 찾아 봄
        if (obj.Length == 1) // TestTimer 타입이 하나만 있다면
        {
            DontDestroyOnLoad(tstObject); //다음 씬으로 오브젝트 Canvas를 파괴없이 넘김
        }
        else // TestTimer 타입이 하나가 아니라면
        {
            Destroy(tstObject); // 기존 Canvas를 파괴함
        }
        
        StartCoroutine("TimerGo"); //코루틴 시작
    }
    
    IEnumerator TimerGo()
    {
        while (true)
        {
            tstTime += Time.deltaTime; //시간을 증가시킴
            tstMsec = (int)((tstTime - (int)tstTime) * 100); //시간에서 소숫점만 남겨서 밀리초를 계산 
            tstSec = (int)(tstTime % 60); //시간에서 60으로 나눈 나머지를 구해서 초를 계산
            tstMin = (int)(tstTime / 60 % 60); // 시간에서 60으로 나누고 다시 60으로 나눈 나머지를 구해서 분을 계산 

            GetComponent<Text>().text = string.Format("{0:00}:{1:00}:{2:00}", tstMin, tstSec, tstMsec); // 텍스트에 포맷을 정해서 출력

            yield return null;
        }
    }
}

 

이렇게 스크립터를 변경하면  정상적으로 타이머가 두개의 씬을 계속해서 끊김이 없이 동작하는 것을 확인 할 수 있습니다.

 


다들 폭우 조심하시고...

그럼 오늘도 즐유(거운 니티)! ^^