참고링크를 내 방식대로 해석했다.
게임이라면 꺼서 지금까지의 기록이 사라지면 안된다.
만약 예전에도... 자동저장이 있었다면 누나와 싸우지 않지 않았을까??
게임을 중간에 끄더라도... 아무 기분이 상하지 않도록 데이터를 저장해야 한다.
그래서 알아보기로 했다.
ㅋㅋㅋㅋㅋ
Holy Grail 이거보고 할리갈리라 읽음 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
진짜 시작해보자
-Data Persistence, 데이터의 지속성이 필요하다.
데이터를 다루려면 현재 가지고 있는 데이터가 사라지지 않아야 한다.
다만 여기서는 Save하거나 Load와 같이 메모리에 저장한다는 의미는 아니다.
그저 게임이 실행하는 동안만 데이터를 가지고 있었으면 좋겠다는 이야기다.
1945, 메탈슬러그가 껐다 킨다고 해서 중간 부분부터 시작하진 않는 것처럼.. 최소한 게임이 진행되고 있을 때 데이터가 사라지지 않고 우리가 제어할 수 있어야 한다는 이야기다.
++ 1탄 깼는데 1탄 clear가 저장이 안되어서 2탄을 못가면 그게 말이 되는 소리일까
-PlayerPrefs an easy way but not the best
플레이어프렙스를 쓸 수 있다. 하지만.. 최선의 방법은 아니다. 한계가 명확하다.
//PlayerPrefs 에 데이터 저장
PlayerPrefs.SetFloat("health", 100);
PlayerPrefs.SetFloat("experience", 1000);
//PlayerPrefs 에서 데이터 추출
float health = PlayerPrefs.GetFloat("health");
float experience = PlayerPrefs.GetFloat("experience");
엄청 간단하다. 저렇게 하면 데이터가 저장되고..불러올 수 있다.
장점
- 쓰기 겁나 쉽다.
- 유니티가 알아서 다해준다.
단점
- 문자열, 정수, 불리안 타입만 저장 가능하다.
- 파일 상에 저장되어서 조작하기 쉽다.
- 중요한 데이터에 쓰기에 알맞지 않다.
그래서 사람들은 포기하지 않고 다른 방법을 생각해낸다.
-GameControl , a special GameObject
새로운 오브젝트를 만든다.
씬 간의 이동에도 데이터를 저장할 수 있게 어떻게 하냐..?
우선 우리가 2개가 필요하다고 가정해보자.
1.health
2.experience
public class GameControl : MonoBehaviour
{
//Data to persist
public float health;
public float experience;
}
이렇게 우리가 필요하다면 "따로" 오브젝트를 만들어서 데이터를 잘라서 넣으면 된다.
그렇게 되면 PlayerPrefs에선 3개의 타입만 저장이 되지만
이 오브젝트에는 우리가 원하는 다른 타입도 넣을 수 있다.
그 오브젝트는 어차피 씬 넘어가면 없어지지 않느냐??
DontDestroyOnLoad method
이 메서드가 우리가 "따로" 만든 오브젝트의 기능을 향상시켜준다.
이 메서드는 새로운 씬을 로딩 중일 때도, target Object는 파괴하지 않는다고 한다.
-> 새로운 씬으로 넘어가도 이 오브젝트가 유지된다는 뜻이다.
public class GameControl : MonoBehaviour
{
//Data to persist
public float health;
public float experience;
void Awake()
{
//이 메서드 덕분에 다른 씬이 로딩되어도 파괴되지 않는다.
DontDestroyOnLoad(gameObject);
}
}
해석 쫌 하나. 잘 해석했네 그 뜻이 맞다.
이렇게 씬을 옮겨도 유지가 되는 것이다.
씬을 옮겨지더라도 오브젝트가 없어지는 것은 해결했지만 아직 2개가 남았다.
1. Data access, 데이터 접근
2. Object Reference management, 데이터 접근할 때 참조
우리는 값을 접근할 수 있게끔 첫 번째 씬에서 참조자를 만든다 치자.
그럼 다른 씬에서는 어떻게 그 오브젝트에 접근을 해야할까??
Static Reference
역시나 Static을 이용한다.
Data access 문제를 해결해보자.
그니까 오브젝트에 굳이 참조자를 공유하지 않고도 접근하는 방법이 필요하다.
그래서 우리는 싱글톤 패턴이라는 것을 이용하기로 했다.
**싱글톤과 Static은 조금 다른데 나중에 정리해보자.
그래서 참조자를 static으로 선언해서 언제든 참조할 수 있게 하는 것이다.
public class GameControl : MonoBehaviour
{
//Static reference -> 정적으로 선언
public static GameControl control;
//Data to persist -> 저장 할 데이터
public float health;
public float experience;
void Awake()
{
//Let the gameobject persist over the scenes
DontDestroyOnLoad(gameObject);
//Check if the control instance is null
if (control == null)
{
//This instance becomes the single instance available
control = this;
}
}
}
만약 GameControl 를 이용하고 싶다? 이렇게 사용한다.
//Read data directly
Debug.Log(GameControl.control.health);
Debug.Log(GameControl.control.experience);
//Read data through a local variable
float currentHealth = GameControl.control.health;
float currentExperience = GameControl.control.health;
//Edit data
GameControl.control.health += 10;
GameControl.control.experience += 100;
이렇게 아무데서나 이용할 수 있다.
Prefab is the way
일단 우리가 오브젝트에 저장하고 나면 그 오브젝트를 프리팹에 저장할 수 있다.
하지만 그 전에 할 것이 몇가지 있다.
우리가 하고 싶은 것은 씬 사이의 데이터들을 제어하고 싶은데 그렇게 하려고 모든 씬에다 GameControl을 넣고 싶진 않다.
그렇게 하려면 Awake()에 조금 변화가 필요하다.
매순간 객체화를 할 때 마다 다른 객체가 있는지 체크하고 있으면 그 객체를 삭제하게 한다.
이게 바로 싱글톤 방식이다. 싱글톤의 가장 강력한 규칙이 있다.
“one and only one will live forever and ever!”
가장 중요한 규칙이다.
public class GameControl : MonoBehaviour
{
//Static reference
public static GameControl control;
//Data to persist
public float health;
public float experience;
void Awake()
{
//Let the gameobject persist over the scenes
DontDestroyOnLoad(gameObject);
//Check if the control instance is null
if (control == null)
{
//This instance becomes the single instance available
control = this;
}
//Otherwise check if the control instance is not this one
else if (control != this)
{
//In case there is a different instance destroy this one.
Destroy(gameObject);
}
}
}
그래서 우리는 어떤 씬을 불러오더라도 일단 GameControl을 일단 선언하면 끝까지 살아있고 게임의 오브젝트들과 데이터를 바꾸고 공유할 수 있다.
ControlManager
굳이 객체화시킬 때마다 기존의 객체가 있을 때마다 삭제하는 것을 하기 싫다면..?
ControlManager 를 생각해볼 수 있다.
GameManager는 GameControl의 객체화를 책임지고 있다.
public class ControlManager : MonoBehaviour
{
//Reference to the prefab of the game control
private Object gameControlRef;
void Awake()
{
//Initialise the reference
gameControlRef = Resources.Load("Prefabs/GameControl");
//Check if the game control instance is null
if (GameControl.control == null)
{
//This instance becomes the single instance available
Instantiate(gameControlRef);
}
//The job is done this object is not used anymore so destroy it
Destroy(gameObject);
}
}
ControlManager ControlObject가 객체화가 될지 말지 정한다.
여기까지 모든 데이터 관리는 끝났다.
한국인은 항상 요약이 필요하다.
그래서 요약한다.
- 데이터를 저장할 오브젝트를 생성한다.
- DontDestroyOnLoad 메서드로 씬 간의 오브젝트를 유지한다.
- static으로 선언하여 다른 오브젝트에서도 데이터에 접근할 수 있도록 한다.
- 오브젝트를 프리팹으로 선언하고 게임 전체에서 유일하게 존재할 수 있도록 한다.
끝
참고링크
gamedevelopertips.com/how-to-handle-data-between-scenes-in-unity/
'Game Development, 게임개발 > 개발' 카테고리의 다른 글
Namespace, 네임스페이스 [Unity] (0) | 2021.03.29 |
---|---|
Extension Method, 확장 메서드 [Unity] (0) | 2021.03.29 |
Interface, 인터페이스 [Unity] (0) | 2021.03.28 |
Overriding, 덮어쓰기, 오버라이딩 [Unity] (0) | 2021.03.27 |
Member hiding, 하이딩, 은닉 [Unity] (0) | 2021.03.27 |