ScriptableObject란?

ScriptableObject는 Unity에서 제공하는 클래스 타입으로, 데이터를 저장하고 관리하기 위한 *컨테이너이다. 즉, 씬에 독립적으로 존재하며, 여러 오브젝트가 동일한 데이터를 참조해야 할 때 가장 유용하다.
 
*컨테이너: 데이터를 담아두는 그릇 역할을 하는 구조를 말한다.
 
공식 문서 정의에 따르면:

ScriptableObject는 프로젝트의 메모리 사용을 줄이고, 데이터의 사본을 생성하는 대신 공용 데이터 자원을 저장하고 여러 객체에서 공유할 수 있도록 설계된 클래스입니다.

 
1. ScriptableObject 기본 예제

using UnityEngine;

// ScriptableObject 정의
[CreateAssetMenu(fileName = "NewWeapon", menuName = "RPG/Weapon")]
public class WeaponData : ScriptableObject
{
    public string weaponName;
    public Sprite icon;
    public int attackPower;
    public int defensePower;
}

CreateAssetMenu 어트리뷰트를 붙이면, Project 창에서 Create -> RPG -> Weapon메뉴가 생긴다. 이것을 선택하면 NewWeapon.asset 파일이 생성되고, Inspector에서 값 입력이 가능해진다.

Project 창 → Create → RPG → Weapon
위의 과정을 통해 생성한 Sample.asset

사용 예시:

public class WeaponUser : MonoBehaviour
{
    public WeaponData weaponData;

    void Start()
    {
        Debug.Log($"무기 이름: {weaponData.weaponName}, 공격력: {weaponData.attackPower}");
    }
}

 

앞서 만든 Sample.asset 파일을 할당

 

코드 실행 결과

이러한 방식으로 Project에 저장된 SO 데이터를 참조할 수 있게 된다.
 
2. ScriptableObject 사용 이유

  1. 데이터 공유와 메모리 절약
    Prefab에 데이터를 저장하면, Instantiate 할 때마다 값의 복사본이 생기게 된다. 반면 SO는 하나의 데이터 자원만 존재하고, 여러 오브젝트가 같은 것을 참조하게 된다. 
    ex) 인벤토리에 검이 100개가 있어도, 공격력 = 10 데이터는 SO 1개만 있다.
  2. 씬 독립성
    SO는 씬에 묶이지 않으므로, 씬이 바뀌어도 유지가 된다. 때문에 여러 씬에서 공통으로 사용하는 설정값에 적합하다.
  3. 에디터 친화성
    SO는 에셋이므로 Project 창에 보관되고, Inspector에서 값 수정이 간단하다. 때문에 비개발자도 프로그래머 도움 없이 데이터를 수정할 수 있어 협업에 도움이 된다.

SO는 단순히 데이터를 담는 클래스 이상으로, Unity에서 데이터 중심 설계(Data-Driven Design)를 가능하게 해주는 핵심 도구이다. 장비나 포션 등의 아이템, 스킬 시스템, 몬스터나 직업 포지션 별 기본 스텟 등 다양한 조건에서 활용이 가능할 것 같다. 

using UnityEngine;

[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/SpawnManagerScriptableObject", order = 1)]
public class SpawnManagerScriptableObject : ScriptableObject
{
    public string prefabName;

    public int numberOfPrefabsToCreate;
    public Vector3[] spawnPoints;
}
using UnityEngine;

public class Spawner : MonoBehaviour
{
    // The GameObject to instantiate.
    public GameObject entityToSpawn;

    // An instance of the ScriptableObject defined above.
    public SpawnManagerScriptableObject spawnManagerValues;

    // This will be appended to the name of the created entities and increment when each is created.
    int instanceNumber = 1;

    void Start()
    {
        SpawnEntities();
    }

    void SpawnEntities()
    {
        int currentSpawnPointIndex = 0;

        for (int i = 0; i < spawnManagerValues.numberOfPrefabsToCreate; i++)
        {
            // Creates an instance of the prefab at the current spawn point.
            GameObject currentEntity = Instantiate(entityToSpawn, spawnManagerValues.spawnPoints[currentSpawnPointIndex], Quaternion.identity);

            // Sets the name of the instantiated entity to be the string defined in the ScriptableObject and then appends it with a unique number. 
            currentEntity.name = spawnManagerValues.prefabName + instanceNumber;

            // Moves to the next spawn point index. If it goes out of range, it wraps back to the start.
            currentSpawnPointIndex = (currentSpawnPointIndex + 1) % spawnManagerValues.spawnPoints.Length;

            instanceNumber++;
        }
    }
}


Unity 공식 문서에서는 위와 같은 샘플 코드를 제공해 주었는데, 제공된 SO에는 어떤 프리팹을 몇 개나 어디에 생성할지에 대한 정보가 담겨있었다. 예를 들어 웨이브 기반 게임의 경우, 각 웨이브에 따라 어떤 몬스터를 어디에, 몇 마리씩 스폰해 줄지 규칙을 정해두고, 이를 레벨에 따라 불러오는 기믹에 있어서 해당 SO가 유용할 것처럼 느껴졌다.

SO를 다뤄본 적은 있었지만, 어디까지나 아이템이나 스킬정도가 전부였기에 이런 구조로도 생각해 볼 수 있다는 게 신선했다. 활용 방안이 무궁무진한 것 같아 더 어렵게 느껴지면서도 다양하게 도전해보고 싶은 느낌. 🧐


 

ScriptableObject - Unity 매뉴얼

ScriptableObject는 클래스 인스턴스와는 별도로 대량의 데이터를 저장하는 데 사용할 수 있는 데이터 컨테이너입니다. ScriptableObject의 주요 사용 사례 중 하나는 값의 사본이 생성되는 것을 방지하

docs.unity3d.com

 

+ Recent posts