ScriptableObject

ScriptableObject의 개념과 용도
게임 오브젝트에 컴포넌트로 붙지 않고 프로젝트의 에셋으로 존재하는 데이터 그릇입니다. -> 데이터 에셋
데이터 에셋의 용도
값을 프로젝트 안에 에셋으로 넣어 두고, 게임이 실행되는 동안 그 값을 읽어 쓰는데 씁니다.
- 데이터 에셋을 쓰기 위해 필요한 요소 3가지
- 클래스 스크립트
- 데이터 에셋
- 컴포넌트
1. ScriptableObject 스크립트
- 상속 대상 ==MonoBehaviour== 를 ==ScriptableObject== 로 바꿉니다.
- Start와 Update 이벤트함수는 지웁니다.
using UnityEngine;
public class EnemyStats : ScriptableObject
{
}
2. CreateAssetMenu
Create 메뉴에 항목을 표시해주는 기능입니다.
| 속성 | 하는 일 | 이 예의 값 |
|---|---|---|
fileName | 새로 만든 에셋의 기본 파일 이름 | NewEnemyStats |
menuName | Create 메뉴에 보이는 이름. /로 나누면 하위 메뉴가 됩니다 | AIProgramming/Enemy Stats |
using UnityEngine;
[CreateAssetMenu(fileName = "NewEnemyStats", menuName = "AIProgramming/Enemy Stats")]
public class EnemyStats : ScriptableObject
{
[SerializeField] private int _maxHp;
[SerializeField] private float _detectRange;
[SerializeField] private float _attackRange;
[SerializeField] private float _meterPerSecond;
[SerializeField] private float _attackInterval;
[SerializeField] private string _name;
public int MaxHp => _maxHp;
public float DetectRange => _detectRange;
public float AttackRange => _attackRange;
public float MeterPerSecond => _meterPerSecond;
public float AttackInterval => _attackInterval;
public string Name => _name;
}
2-1 ) 에셋 인스펙터
인스펙터 맨 위에 에셋이 어느 클래스로 만들어졌는지 보여주는 ==Script== 칸, 그 아래에 ==field== 칸이 있습니다.
인스펙터에서 넣은 값은 에셋 파일에 저장되어 에디터를 다시 켜도 남습니다.

3.MonoBehaviour와의 차이
- MonoBehaviour와 ScriptableObject 상속 계층

==ScriptableObject==는 ==Component== 아래가 아니라 ==Object== 바로 아래에 있기 때문에 ==Component== 과 관련된 ==transform== 등을 적으면 컴파일 오류가 납니다.
MonoBehaviour | ScriptableObject | |
|---|---|---|
붙는 곳 | 게임 오브젝트에 컴포넌트로 붙음 | 붙지 않음. 프로젝트의 에셋 |
에디터에서 만드는 방법 | 인스펙터의 | Project 창의 |
코드로 만드는 방법 |
|
|
보이는 곳 | Hierarchy에서 고른 오브젝트의 인스펙터 | Project 창에서 고른 에셋의 인스펙터 |
| 불림 | 불리지 않음 |
Transform | 있음 | 없음 |
4. 에셋 참조와 공유
4-1) 에셋을 받는 칸
==SciptableObject==는 Create로 만든 에셋을 컴포넌트의 칸으로 받아 사용합니다.

using UnityEngine;
public class AssetEnemy : MonoBehaviour
{
[SerializeField] private EnemyStats _stats;
private void Start()
{
PrintStats();
}
private void PrintStats()
{
Debug.Log($"AssetEnemy: {_stats.Name} 체력 {_stats.MaxHp} 감지 {_stats.DetectRange} 속도 {_stats.MeterPerSecond}");
}
}
4-2) 한 에셋의 공유
값을 바꾸게 된다면 데이터 에셋은 같은 ==SciptableObject== 를 가지고 있다면 모두 바뀐 값을 씁니다.
데이터 에셋은 실행중에도 바꾼 값이 모두에게 적용됩니다.
[Serializable] 일반 클래스 칸 | ScriptableObject 칸 | |
|---|---|---|
칸의 모양 | 펼치면 필드마다 칸이 나옴 | 펼쳐지지 않고 에셋 하나를 가리킴 |
값이 있는 곳 | 그 컴포넌트 안 | 가리키는 에셋 안 |
오브젝트가 셋이면 | 값이 세 벌 | 에셋 하나를 셋이 가리킴 |
4-3) 함께 쓰는 값과 개체마다의 값
값의 성격 | 예 | 두는 곳 |
|---|---|---|
같은 종류면 모두 같은 값 | 최대 체력, 감지 거리, 공격 거리, 초당 이동 거리, 공격 간격, 이름 | 데이터 에셋 |
개체마다 달라지는 값 | 현재 체력, 위치, 쫓아갈 대상 | 컴포넌트 필드 |

![[Unity] PC 세이브 데이터 Android로 옮기기](https://data.develog.develrocket.com/upload/develog/muchan/1792206352286-hd4xz4/_____2026-10-17_114953.png)
![[Unity] 제네릭 박싱 예방](https://data.develog.develrocket.com/upload/develog/gmumdev/1792123312021-bhxx2i/_____.png)
