■ ScriptableObject
스크립터블 오브젝트(Scriptable Object)는 유니티에서 제공하는 Mono와 다른 경량 데이터 컨테이너 클래스이다.
- 말 그대로 스크립팅 가능한 Object, 즉 코드로 정의된 데이터 저장용 객체를 의미한다.
스크립터블 오브젝트는 씬에 존재하지 않으며, 데이터를 독립적으로 저장하고 재사용 할 수 있는 “에셋 파일(.asset)”로 저장된 직렬화 가능한 데이터 객체이다.
스크립터블 오브젝트는 다음과 같은 상황에서 사용된다.
- 게임 내 설정값 관리.
- 무기, 아이템, 능력치 등 고정된 데이터를 관리할 때.
- 동일한 데이터를 여러 오브젝트가 공유해야 할 때.
- 씬이 변경되어도 데이터가 유지되어야 할 때.
▼ 몬스터에 관련된 데이터 클래스를 만들 때, Monobehaviour와 Scriptable Object는 다음과 같은 차이점이 있다.
Monobehaviour | Scriptable Object | |
참조 객체 | 각 GameObject 마다 개별 인스턴스. | 여러 객체가 하나의 데이터 인스턴스 공유. |
값 변경 시 | 각자만의 값이 바뀜. (개별 상태 유지) | 모든 객체에 반영. |
저장 위치 | 씬 혹은 프리팹 내부. | 프로젝트 창의 .asset 파일 |
1. 직렬화(Serialization) 란?
일반적으로 직렬화는 복잡하고 다양한 구조를 가진 데이터를, 순차적인 바이트 흐름(데이터 스트림)으로 변환하는 작업을 의미한다.
- 객체의 변수들이 연속된 주소에 없을 수 있음.
- 포인터, 참조 등은 메모리 내부 전용 정보라 외부 저장 불가.
그렇기에 파일에 저장하거나 네트워크로 전송하려면 이 메모리 구조를 일렬로 정리해야 하는데, 이 과정을 바로 직렬화(Serialization)라고 한다.
[System.Serializable]
public class MonsterData
{
public string name; // 문자열은 길이 + 문자들
public int hp; // 4바이트
public float speed; // 4바이트
}
유니티에서의 직렬화도 위와 같은 데이터를 저장하기 위해선
→ name, hp, speed를 정해진 순서로, 포맷에 맞게 바이트로 변환.
→ 이 과정은 유니티의 직렬화 시스템이 자동으로 처리한다.
스크립터블 오브젝트는 내부 변수 데이터를 자동으로 직렬화하여 저장하고, 사용할 때는 역직렬화(Deserialization)하여 메모리에서 사용할 수 있도록 한다.
■ 스크립터블 오브젝트 생성
using UnityEngine;
[CreateAssetMenu(fileName = "MonsterData", menuName = "Scriptable Objects/MonsterData",
order = 1))]
public class MonsterData : ScriptableObject
{
[SerializeField] private string monsterName;
[SerializeField] private float hp;
[SerializeField] private float damage;
[SerializeField] private int lv;
public string MonsterName => monsterName;
public float Hp => hp;
public float Damage => damage;
public int Lv => lv;
}
스크립터블 오브젝트는 ScriptableObject 클래스를 상속받아 정의한다.
프로젝트 창에서 에셋 파일(.asset)을 생성하기 위해 [CreateAssetMenu] 어트리뷰트를 사용한다.
▶ [CreateAssetMenu] 어트리뷰트
- fileName = 생성되는 .asset 파일의 기본 이름
- menuName = 프로젝트 창에서 우클릭 → Create 시 표시될 메뉴 경로
- order = 메뉴 항목의 정렬 순서. (숫자가 낮을수록 위에 표시)
using UnityEngine;
public class Monster : MonoBehaviour
{
[SerializeField] private MonsterData data;
private void Start()
{
Debug.Log(data.MonsterName);
Debug.Log(data.Hp);
Debug.Log(data.Damage);
Debug.Log(data.Lv);
}
}
스크립터블 오브젝트를 사용하려면, 해당 컴포넌트에서 스크립터블 오브젝트 클래스 타입의 변수를 선언한 후, 인스펙터에서 .asset 파일을 드래그하여 연결하면 된다.
MonsterData.asset 처럼 하나의 스크립터블 인스턴스를 여러 오브젝트가 공유하면, 해당 .asset의 값을 변경했을 때 모든 참조 대상에게도 즉시 반영된다.
즉, 하나의 데이터를 여러 프리팹이나 게임 오브젝트가 공통으로 사용할 수 있는 구조가 된다.
- 런타임 중 스크립터블 오브젝트의 값을 수정하면, 에디트 모드로 돌아와도 변경 내용이 유지된다. (.asset 파일 자체가 수정되기 때문)
스크립터블 오브젝트는 변하지 않는 “설정 데이터”를 저장.
private float currentHp;
private void Start()
{
currentHp = data.Hp; // ScriptableObject로부터 초기값만 받아옴
}
hp, lv처럼 게임 플레이 중 변경되는 상태 값을 스크립터블 오브젝트에 그대로 저장하면 참조하는 모든 오브젝트의 값이 바뀌는 부작용이 발생한다.
따라서, 이런 상태 값이 필요한 경우에는
- 초기값만 스크립터블 오브젝트에서 불러오고, 런타임에서는 MonoBehaviour나 별도의 상태 클래스에 복사하여 사용한다.
MonsterData clone = Instantiate(originalMonsterData);
clone.hp = 50; // 이제 이건 독립된 값
혹은 위와 같이 스크립터블 오브젝트 자체를 복사하여 개별로 사용할 수 있다.
'Unity,C# > Unity 정보' 카테고리의 다른 글
[Unity, C#] EditorWindow - 커스텀 에디터 윈도우 (1) | 2025.08.02 |
---|---|
[Unity, C#] Editor - 커스텀 인스펙터 (0) | 2025.08.02 |
[C#] LINQ(Language Integrated Query) (1) | 2025.06.27 |
[Unity] Coroutine(코루틴) 파헤치기 (4) | 2025.05.30 |