저는 저장될 내용에 따라 JSON, 바이너리, PlayerPrefs 등 혼용해서 많이 쓰는데요.
그중 이번에는
아마도 유니티 내에서 가장 간단한 PlayerPrefs를 활용해볼까 합니다.
PlayerPrefs
일단 알아 두셔야 할 점은,
-간편하게 관리할 수 있다는 점.
-간편하고 쉬운만큼 보안성은 개나 줘 버려서 없음. (저장 위치의 파일을 열어보면 날 것 그대로의 값이..)
위 같은 이유로 중요한 데이터는 웬만해서는 이 방법을 추천하지 않습니다.
보통, 게임 옵션의 세팅 정보 (BGM, Sound의 볼륨 크기, 진동 유무) 정도로 사용하시는 게 적당하지 않을까 싶네요.
(만약 정말 만약 PlayerPrefs를 활용해서 중요한 게임 데이터를 저장코자 한다면,
꼭 저장 전에 암호화한 값을 저장해주세요. 암호화는 나중에 한 번 다뤄 보도록 하겠습니다.)
PlayerPrefs은 기본적으로 Int / Float / String의 변수 타입을 지원합니다.
(배열을 간혹 저장해야 할 때가 있는데 배열을 String으로 변환 후 Spilt을 이용해 사용합니다.)
저장하기(Save)
정말 간단히 저장된다.
//기본적으로 PlayerPrefs는 ("키", 값) 형태로 사용
//Int - 정수형 변수의 저장
PlayerPrefs.SetInt("키", int);
//String - 문자열 형태의 변수 저장
PlayerPrefs.SetString("키", string);
//Float - 실수형의 변수 저장
PlayerPrefs.SetFloat("키", float);
예를 들어
//유저 데이터 세이브
//캐릭터 이름
PlayerPrefs.SetString("CharName", "무예꼬마");
//캐릭터 레벨
PlayerPrefs.SetInt("Level", 10);
//치명타 확률
PlayerPrefs.SetFloat("Critical", 0.5f);
불러오기(Load)
로드 역시 간단하다.
//기본적으로 PlayerPrefs는 ("키", 값) 형태로 사용
//Int - 정수형 변수의 저장
PlayerPrefs.GetInt("키");
//String - 문자열 형태의 변수 저장
PlayerPrefs.GetString("키");
//Float - 실수형의 변수 저장
PlayerPrefs.GetFloat("키");
//유저 데이터 로드
//캐릭터 이름
string charName = PlayerPrefs.SetString("CharName"); //"무예꼬마"
//캐릭터 레벨
int level = PlayerPrefs.SetInt("Level"); //10
//치명타 확률
float criticalPoint =PlayerPrefs.SetFloat("Critical"); //0.5f
끝이다.
다만 만약에 로드를 했는데 해당 키가 없을 경우 기본 초기값을 설정해주는 방법이 있는데
//불러올때 초기값을 설정해주면, 혹시나 값이 없을때 초기값으로 값을 돌려준다.
PlayerPrefs.GetInt("키", 초기값);
//예를들어
//레벨 데이터를 가져오고, 만약 레벨 데이터가 없다면 1을 불러온다.
PlayerPrefs.GetInt("level", 1);
//String Float 모두 동일하게 사용가능하다.
아래는 추가적으로 필요한 기능들!
삭제(Delete)
더 이상 필요가 없는 저장된 키값을 지우고 싶을 때가 있다.
//지우고싶은 데이터 삭제
PlayerPrefs.DeleteKey("키");
//저장되어있는 모든 데이터 삭제
PlayerPrefs.DeleteAll();
해당 데이터가 있는지 확인
//해당 이름을 가진 데이터가 있다면 true
if(PlayerPrefs.HasKey("키"))
Debug.Log("해당 키가 존재합니다.");
일단 제 기준으로 유니티에서 사용하기 편하고 관리하기 쉬운 방법의 싱글톤 예제를 가지고 왔습니다.
싱글톤의 역할
싱글톤은 프로그래밍 디자인 패턴 중 추상 객체 인스턴스 생성 패턴 중의 하나로
유니티에서 싱글톤의 역할은
1. 게임 시스템에서 전체를 관장하는 스크립트(단일 시스템 자원 관리 차원)
2. 게임 시스템상 전역 변수의 역할을 하는 스크립트
3. 씬 로드시 데이터가 파괴되지 않고 유지
4. 여러 오브젝트가 접근을 해야 하는 스크립트의 역할
5. 단 한개의 객체만 존재(게임 전체를 관장하는 스크립트가 둘 이상 있으면 꼬이겠죠?)
등등 많겠지만 결론은 다 같은 말이죠? 네 이 모든 역할을 할 수 있는게 Singleton Pattern입니다.
아마 새로운 씬을 로드를 하게 되면 앞에 있던 변수들은 전부 파괴되고 새로운 씬이 로드가 될 거예요.
하지만 싱글톤은 씬 이동시 자신을 파괴하지 않으면서 자신이 가진 데이터들 또한 함께 유지한답니다.
실습 예제 및 스크립트
위 그림과 같은 경우로
유니티 내에서 씬과 씬 사이를 넘어갈 때 앞의 씬에서 데이터를 받아와서 다음 씬에서 받고 싶을 때 사용할 수 있어요.
그럼 MyGold 가 씬이 이동이 되어도 계속해서 유지할 수 있는 방법을 알아볼게요
저는 우선 "GameManager"라는 이름의 스크립트를 만들었습니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
/* // 싱글톤 //
* instance라는 변수를 static으로 선언을 하여 다른 오브젝트 안의 스크립트에서도 instance를 불러올 수 있게 합니다
*/
public static GameManager instance = null;
private void Awake()
{
if (instance == null) //instance가 null. 즉, 시스템상에 존재하고 있지 않을때
{
instance = this; //내자신을 instance로 넣어줍니다.
DontDestroyOnLoad(gameObject); //OnLoad(씬이 로드 되었을때) 자신을 파괴하지 않고 유지
}
else
{
if (instance != this) //instance가 내가 아니라면 이미 instance가 하나 존재하고 있다는 의미
Destroy(this.gameObject); //둘 이상 존재하면 안되는 객체이니 방금 AWake된 자신을 삭제
}
}
//게임 내에서 씬이동시 유지하고 픈 골드 값(변수)
public int myGold = 0;
}
위와 같이 스크립트를 짜주시고, 각 씬의 하이라키창에 빈 오브젝트(Empty Object)를 생성해줍니다.
이제 어디서든
GameManager.instance.(변수 혹은 함수명)
으로 불러 줄 수 가 있게 되었습니다!
지금 의 예제로는
GameManager.instance.myGold 라고 불러 줄 수 가 있겠네요.
그럼 Main 씬에서 '돈 벌기' 버튼을 눌렀을때 아래가 작동이 되는 스크립트를 만들어주고,
GameManager.instance.myGold += 2;
씬을 이동(상점) 후, 아이템 구매마다 해당하는 가격만큼 myGold가 줄어들게 설정을 하고 테스트를 해보면..