Quick Comparison
"데이터가 남는다"는 세 가지 다른 요구입니다. 같은 실행 중 여러 씬에서 공유, 프로젝트 asset에 저장된 원본, 앱을 껐다 켜도 남는 player save를 먼저 나눕니다.
| 필요한 수명 | 기본 선택 | 저장되는 것 | 피해야 할 오해 |
|---|---|---|---|
| 현재 실행 중 scene 전환을 넘어 유지 | DontDestroyOnLoad service 또는 runtime state | 살아 있는 object/메모리 | 앱 종료 뒤에도 남는 save라고 생각 |
| 여러 prefab이 공유하는 설계·밸런스 값 | ScriptableObject asset | 개발 시 만든 asset data | 플레이 결과를 asset에 저장한다고 생각 |
| 작은 사용자 설정 | PlayerPrefs | int, float, string key-value | 비밀·치트 방지·복잡한 save로 사용 |
| 구조화된 진행·인벤토리·save slot | versioned data + JSON/file | 직접 정의한 save schema | ToJson만으로 migration·atomic write가 끝난다고 생각 |
선택과 소유권
DontDestroyOnLoad는 BGM player, loading overlay처럼 행동하는 service가 여러 scene에서도 살아야 할 때 사용합니다. 그 service 안의 runtime state는 해당 실행 동안만 유효합니다. 값 하나를 넘기기 위해 scene object 전체를 살려 두면 cleanup·테스트·중복 생성 책임까지 따라옵니다.
ScriptableObject는 무기 정의, difficulty preset, spawn table처럼 asset으로 관리할 공유 원본에 맞습니다. 여러 prefab이 한 asset을 참조하면 메모리에는 공유된 한 인스턴스를 사용하므로, 플레이 중 그 field를 바꾸면 그 asset을 보는 모든 시스템에 즉시 반영됩니다. 이 공유성은 설정에는 이점이지만 player별 current HP 같은 session state에는 위험합니다.
PlayerPrefs는 volume, language, last selected resolution처럼 작은 preference에만 둡니다. 진행 save는 plain data class를 정의해 version을 포함하고, load validation·migration·파일 교체 실패 대책까지 save owner가 관리합니다.
using System.Collections.Generic;
[System.Serializable]
public sealed class SaveData
{
public int version = 1;
public int currentChapter;
public List<string> unlockedItemIds = new();
}JSON save의 최소 경계
JsonUtility는 Unity field serialization 규칙을 따릅니다. dictionary, property, arbitrary JSON tree는 그대로 처리하지 못하므로 schema가 그 기능을 요구하면 wrapper나 다른 serializer를 선택합니다. UnityEngine.Object reference를 player save에 넣으면 object identity가 다음 실행에도 복원된다고 가정할 수 없습니다. save에는 asset·scene reference 대신 안정적인 ID를 저장하고, load 뒤 ID로 runtime data를 다시 찾습니다.
using System.IO;
string json = JsonUtility.ToJson(saveData);
File.WriteAllText(Path.Combine(Application.persistentDataPath, "save.json"), json);이 코드는 직렬화와 파일 쓰기만 보여 줍니다. 실제 save에는 쓰기 실패, 손상 JSON, 이전 version, 임시 파일 후 replace, cloud/플랫폼 동기화 같은 정책이 추가됩니다. 저장 중 앱이 종료되어도 되는 데이터인지, 마지막 정상 save를 복구해야 하는지에 따라 atomic write와 backup 필요성이 달라집니다.
자주 틀리는 부분
| 증상 | 원인 | 수정 |
|---|---|---|
| 앱 재시작 뒤 점수가 사라짐 | DontDestroyOnLoad/ScriptableObject를 persistent save로 사용 | save schema와 file/서비스 저장 경로를 분리 |
| prefab 여러 개의 값이 같이 바뀜 | 같은 ScriptableObject asset을 runtime state로 수정 | immutable definition과 per-instance state를 분리 |
| PlayerPrefs 값이 변조됨 | local, unencrypted store에 민감 값을 둠 | 서버 권한·검증 또는 별도 보안 정책 사용 |
| save update 뒤 예전 JSON을 못 읽음 | version·migration 없음 | save data에 version을 넣고 migration path 작성 |
| JSON에 scene object reference를 저장 | Unity object reference의 session identity를 영속 ID로 오해 | stable asset/item ID를 저장하고 load 시 resolve |
참고 링크
4 sources