안 쓰던 블로그

unity 변수/함수/오브젝트 다른 씬에서 접근, 공유하기(DontDestroyOnLoad) 본문

유니티/개발

unity 변수/함수/오브젝트 다른 씬에서 접근, 공유하기(DontDestroyOnLoad)

proqk 2020. 2. 2. 17:38
반응형

지금 씬(Stage)는 스테이지 선택 창임

여기서 스테이지를 클릭하면 Scene1에다가 현재 클릭된 스테이지 번호를 넘겨주고, 그 번호의 스테이지를 실행하게 해주고 싶다

그러면 '스테이지 번호' 변수가 다른 씬으로 공유되어야 함

 

유니티에서 씬에서 씬으로 변수나 함수를 못 넘기는 이유가, 씬이 넘어갈 때 그 씬에 있는 모든 오브젝트를 파괴하기 때문인데, 파괴되지 않거나 static이면 씬이 넘어가도 접근할 수 있으니까 공유가 될 것이다

 

만약 플레이어가 맵을 이동해야 한다면? 플레이어 객체는 삭제되지 않아야 되니까 이 경우는 DontDestroyOnLoad라는 유니티 동작 매커니즘을 추가해서 객체가 파괴되지 않도록 해준다

 

DontDestroyOnLoad를 적용한 객체는 씬이 넘어가도 삭제되지 않으므로 새로운 씬이 실행되어도 계속 접근할 수 있다

그리고 그 객체의 컴포넌트든, 붙어있는 스크립트든 정보를 가져와서 쓰면 씬끼리 데이터 공유가 되는 것

 

 

참고)

DontDestroyOnLoad가 나와서 싱글톤 패턴을 짚고 가자면,

'싱글톤 패턴'이라고 간단히 말해 한 개의 클래스 인스턴스만 갖도록 하고, 그 인스턴스에 전역적으로 접근할 수 있게 해주는 코딩 패턴이 있음

유니티에서 말하는 싱글톤 패턴은 객체 하나를 만들고, 씬이 바뀔 때에도 그 객체는 삭제되지 않게 DontDestroyOnLoad를 해주는 형태임

그래서 새로운 씬이 실행되어도 그 객체는 삭제되지 않으므로 계속 접근할 수 있다

 

아래 나올 코드에서도 위에서 말했듯 DontDestroyOnLoad를 쓰는데, 근데 이건 싱글톤 패턴은 아니라고 생각함

싱글톤 패턴은 한 개의 클래스 인스턴스를 갖게 하고(static사용), 그 인스턴스에 전역적으로 접근(DontDestroyOnLoad 사용)할 수 있게 해주는 것인데 내 코드는 static을 사용하지 않았기 때문임

 

DontDestroyOnLoad만 쓰는 건 그냥 유니티의 동작 매커니즘(씬이 넘어가도 객체가 삭제되지 않음)을 이용했을 뿐임(이 내용이 틀리면 정정좀)

 

 

어쨌든 DontDestroyOnLoad를 쓴 객체는 씬이 넘어갔을 때

이런 식으로 넘어옴

DontDestroyOnLoad아래 stagenum이 넘어온 모습이다

 

구현하기 전에 싱글톤에서 주의해야 할 점이,

씬이 넘어갈 때 오브젝트가 다 삭제되는데 싱글톤은 삭제되지 않으니까, 어딘가의 자식이면 안 됨

무조건 최상위 객체여야 함

 

근데 내 프로젝트에서 StageManager는 각 스테이지 버튼 s1, s2..에 붙어있는 구조라 Canvas아래 있을 수밖에 없어서

씬을 넘기는 SceneManager가 붙은 stagenum이라는 객체에서 스테이지 번호 변수도 같이 넘겨주려고 한다

 

StageManager 스크립트

public class StageManager : MonoBehaviour
{
    public SceneChange sc;

    public void OnClickBox()
    {
        string nowbutton = EventSystem.current.currentSelectedGameObject.name;
        if (nowbutton == "s1")  sc.stageNum = 1;
        else if (nowbutton == "s2") sc.stageNum = 2;
        else if (nowbutton == "s3") sc.stageNum = 3;
        else if (nowbutton == "s4") sc.stageNum = 4;
        
        if (sc.stageNum != 0) sc.call();
    }
}

SceneChange 스크립트

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

public class SceneChange : MonoBehaviour
{
    public int stageNum;
    public GameObject stageNumObject;

    // Start is called before the first frame update
    public void call()
    {
        SceneManager.LoadScene("Scene1");
        DontDestroyOnLoad(stageNumObject);
    }
}

1. StageManager에서 SceneChange스크립트를 불러온다

2. StageManager에서 SceneChange에 있는 stageNum변수를 업데이트 한다

3. SceneChange의 stageNumObject는 씬이 넘어갈 때 삭제되지 않고 넘어갈 오브젝트임

SceneChange 스크립트가 붙어 있어서 SceneChange의 stageNum도 같이 감

즉, 씬이 바뀌어도 stagenum객체의 SceneChange에 있는 변수 접근이 가능함

 

씬이 넘어가면 이렇게 됨

이제 넘어온 변수를 사용하면 된다

 

넘어온 씬(Scene1)의 GameManager 스크립트

public class GameManager : MonoBehaviour
{
    int click, nowStage;
    GameObject StageManager;

    void Start()
    {

        StageManager = GameObject.Find("stagenum");
        nowStage = StageManager.GetComponent<SceneChange>().stageNum;

        //...
    }
}

1. 삭제되지 않고 넘어온 GameObject를 찾는다(find)

2. 그 GameObject에 붙어있는 SceneChange 스크립트를 불러온다(GetComponent)

3. 스크립트 안에 있는 stageNum변수를 가져온다

 

 

--------------

참고로 넘어올 변수를 static으로 선언했다면 그냥 갖다 쓰면 됨

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

public class SceneChange : MonoBehaviour
{
    public static int stageNum;
    public GameObject stageNumObject;

    // Start is called before the first frame update
    public void call()
    {
        SceneManager.LoadScene("Scene1");
        DontDestroyOnLoad(stageNumObject);
    }
}

 근데 이 코드의 경우는 stageNum을 업데이트 해줘야 했기 때문에 static으로 하지 않음

 

반응형
Comments