Quick Reference
ScriptableObject는 GameObject에 붙지 않는 project asset data container입니다. 여러 prefab이 같은 asset을 참조하면 하나의 shared definition을 보며, runtime field 변경도 그 shared in-memory instance에 반영됩니다. deployed build에서는 ScriptableObject asset을 player save처럼 디스크에 기록할 수 없습니다.
| 데이터 성격 | 둘 위치 | runtime 변경 | 앱 재실행 뒤 |
|---|---|---|---|
| 무기 기본 피해·아이템 이름·spawn table | ScriptableObject asset | 모든 참조자가 같은 값을 봄 | build에 포함된 원본으로 다시 시작 |
| player current HP·cooldown·장착 상태 | runtime class/MonoBehaviour | 해당 run·instance에 한정 | save를 따로 하지 않으면 사라짐 |
| Editor 제작 도구의 설정 결과 | ScriptableObject asset + Editor save workflow | Editor에서 asset write 가능 | project asset으로 보존 |
| player progress | versioned save data | load한 state에 적용 | file/cloud/서버 정책에 따름 |
[CreateAssetMenu(menuName = "Game/Weapon Definition")]
public sealed class WeaponDefinition : ScriptableObject
{
[SerializeField] private string displayName;
[SerializeField] private int baseDamage;
public int BaseDamage => baseDamage;
}Asset Inspector와 공유성
CreateAssetMenu는 Project 창에서 asset instance를 만드는 menu entry를 추가합니다. Inspector field는 Unity serialization 규칙을 따르며, prefab은 그 asset reference만 들고 있을 수 있습니다. 이것이 동일한 balance data를 prefab마다 복사하지 않는 장점입니다.
public sealed class WeaponView : MonoBehaviour
{
[SerializeField] private WeaponDefinition definition;
public int DamageForThisHit(int bonus)
{
return definition.BaseDamage + bonus;
}
}같은 WeaponDefinition을 여러 WeaponView가 참조한다면 field 하나를 바꾸는 순간 모든 참조자가 바뀐 값을 봅니다. 읽기 중심 definition에는 적합하지만, player A의 durability만 줄어야 하는 경우에는 shared asset을 쓰지 않습니다.
runtime state와 저장 경계
asset 원본에서 시작하는 runtime state는 복사하거나 별도 class에 둡니다. Instantiate(definition)로 ScriptableObject runtime clone을 만들 수는 있지만, clone의 ownership·파괴·재생성 시점이 필요합니다. 단순한 player state에는 plain C# state class가 더 직접적인 경우가 많습니다.
public sealed class WeaponRuntimeState
{
public WeaponDefinition Definition { get; }
public int RemainingAmmo { get; private set; }
public WeaponRuntimeState(WeaponDefinition definition, int startingAmmo)
{
Definition = definition;
RemainingAmmo = startingAmmo;
}
}Editor tool이 ScriptableObject asset을 변경해 disk에 남기는 작업은 Undo, dirty mark, asset save 같은 Editor API workflow를 갖습니다. 일반 gameplay code가 Play Mode에서 asset field를 바꿨다고 deployed build의 asset이 persistent save로 갱신되는 것은 아닙니다. Editor와 build의 저장 능력을 섞어 설계하지 않습니다.
참조와 version 경계
ScriptableObject에 scene object reference를 넣으면 asset은 scene과 결합됩니다. scene이 바뀌거나 asset을 다른 project/scene에서 재사용할 때 reference가 의미를 잃기 쉬우므로, shared definition에는 item ID, prefab asset reference, scalar config처럼 project-stable data를 우선 둡니다.
asset field 구조를 바꾸면 기존 asset migration을 확인합니다. serialized field rename에는 FormerlySerializedAs를 적용하고, content pipeline에서 새 asset과 기존 asset의 default·validation을 검사합니다.
자주 틀리는 부분
| 증상 | 원인 | 수정 |
|---|---|---|
| 한 player의 HP가 다른 player에도 바뀜 | shared SO asset을 per-instance state로 사용 | definition과 runtime state를 분리 |
| build에서 SO를 save file처럼 갱신하려 함 | asset과 player persistent storage를 혼동 | JSON/file/cloud 등 save owner 사용 |
| Play Mode 값이 Editor asset과 섞여 보임 | runtime mutation과 Editor asset authoring을 분리하지 않음 | production data를 읽기 중심으로 두고 Editor write workflow 별도화 |
| 다른 scene에서 asset reference가 Missing | shared asset에 scene object reference 보관 | stable ID/prefab asset/reference resolver로 분리 |
| field 구조 변경 뒤 data가 사라짐 | asset migration 없음 | rename attribute·migration 검증 추가 |
참고 링크
3 sources