경고 전문 Parent of RectTransform is being set with parent property. Consider using the SetParent method instead, with the worldPositionStays argument set to false. This will retain local orientation and scale rather than world orientation and scale, which can prevent common UI scaling issues.
→ 번역 RectTransform 의 부모는 부모 속성으로 설정됩니다. 대신 setParent 메서드를 사용하고 worldPositionStays 인수를 false로 설정하는 것이 좋습니다. 이렇게 하면 월드 방향과 스케일이 아닌 로컬 방향과 스케일이 유지되어 일반적인 UI 스케일 문제를 방지할 수 있습니다.
위의 경고문은 transform.parent 대신 transform.SetParent() 메서드를 사용을 권고하는 경고이다.
RectTransform에서 parent 사용 시 UI에 스케일링 관련 이슈가 있어 SetParent를 사용하는것을 권하고있다.
transform.parent = parent_panel; //경고의 원인
transform.SetParent(parent_panel); //이와 같이 SetParent()메서드로 변경해서 사용
저는 저장될 내용에 따라 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가 줄어들게 설정을 하고 테스트를 해보면..