안 쓰던 블로그
unity 변수/함수/오브젝트 다른 씬에서 접근, 공유하기(DontDestroyOnLoad) 본문
지금 씬(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으로 하지 않음
'유니티 > 개발' 카테고리의 다른 글
unity csv파일 유니티로 불러오기(StreamReader 사용)-유니티 csv파일 형식으로 스테이지 만들기 (4) | 2020.02.11 |
---|---|
unity 슈팅게임 총알 5개 한 번에 쏘는 방법(GetComponentsInChildren) (0) | 2020.02.04 |
유니티 GameObject와 Prefab 차이 (0) | 2020.02.02 |
유니티 코드에서 return이 if문 안에만 있으면 안 되네 (0) | 2020.02.02 |
유니티 오브젝트 이동(transform.position) 이상한 곳으로 갈 때 해결 방법 (2) | 2020.01.30 |