Unity

[Unity] ScriptableObject (스크립터블 오브젝트) 이해하기

youcheachae 2025. 2. 18. 20:58
1. ScipratbleObject
2. 생성 방법
3. 사용 방법
4. 유용한 이유, 하나의 메모리에 참조

 

📝 1. ScriptableObject 

: 스크립터블 오브젝트(ScriptableObject )는 대량의 데이터를 저장하는 데 사용할 수 있는 데이터 컨테이너다.

: 값의 사본이 생성되는 것을 방지하여 프로젝트의 메모리 사용을 줄이는데 유용하다.

: MonoBehaviour 스크립트를 프리팹에 넣으면, 해당 프리팹을 인스턴스 화 할 때마다 사본이 생성된다.

: ScriptableObject를 사용하면, 메모리에 데이터 사본을 하나만 저장하여 모든 프리팹이 하나의 메모리에 참조한다.

 

📝 2. 생성 방법

[CreateAssetMenu(fileName = "MonsterData", menuName = "ScriptableObjects/MonsterData")]
public class Scriptable_Monster : ScriptableObject
{
    [SerializeField] private int health;
    [SerializeField] private int damage;
    [SerializeField] private string monsterName;

    // 프로퍼티
    public int Health { get => health; set => health = value; }
    public int Damage { get => damage; set => damage = value; }
    public string MonsterName { get => monsterName; set => monsterName = value; }

}

ScriptableObject를 상속받아서 구현한다.

CreateAssetMenu

             에디터의 메뉴를 통해서 쉽게 에셋을 생성할 수 있게 한다.

           ■  fileName : 저장할 파일의 이름

             menuName : create시 눈에 보이는 목록 이름

 

- 생성방법

상단의 Asset 버튼을 클릭하거나 Asset 폴더 내에서 우클릭 → Create   ScriptableObject MonsterData 선택

 

: Asset폴더에 잘 생성되었다.

 

: 인스펙터창에서 스크립트의 프로퍼티들을 확인할 수 있다.

 

 

📝 3. 사용방법

: 각각 다른 필드를 가진 Monster 에셋을 여러 개 만들었다: 예를 들어서, Health는 10, Damage는 10, Name은 Duck으로 입력해 준다.

 

MonsterTest라는 Monobehavior을 상속받는 클래스를 하나 만들어주고,
Slime 프리팹에 추가한다.

public class MonsterTest : MonoBehaviour
{
    [SerializeField]
    private Scriptable_Monster _monsterScriptable;

    private void Start()
    {
        Debug.Log("몬스터 체력 :: " + _monsterScriptable.Health);
        Debug.Log("몬스터 이름 :: " + _monsterScriptable.Damage);
        Debug.Log("몬스터 공격력 :: " + _monsterScriptable.MonsterName);
    }

}

 

그리고 Slime이라는 이름의 ScriptableObject 타입의 데이터를 드래그해서 넣어준다.

 

실행하면,해당 Slime에 작성한 필드들이 출력되는 것을 확인할 수 있다.

 

 

📝 4. 유용한 이유, 하나의 메모리에 참조

위쪽에서 ScriptableObject를 설명할 때
" ScriptableObject를 사용하면, 메모리에 데이터 사본을 하나만 저장하여 모든 프리팹이 하나의 메모리에 참조한다."라는 말을 사용했다. GetHashCode()를 사용하여 테스트해 보았다.

 

Slime프리팹에 추가된 클래스에 HasCode()를 출력하는 코드를 추가하였다.

private void Start()
{
    Debug.Log("몬스터 체력 :: " + _monsterScriptable.Health);
    Debug.Log("몬스터 이름 :: " + _monsterScriptable.Damage);
    Debug.Log("몬스터 공격력 :: " + _monsterScriptable.MonsterName);

    Debug.Log("Scriptable Object를 사용한 인스턴스화 : " + _monsterScriptable.GetHashCode());

}

 

 

이와 비교하기 위해서, 클래스를 인스턴스화하는 클래스도 작성해 보았다.

public class MonsterClass
{
    private int health;
    private int damage;
    private string monsterName;
}


public class MonsterClassInstanceTest : MonoBehaviour
{
    [SerializeField]
    MonsterClass monster;

    void Start()
    {
        monster = new MonsterClass();

        Debug.Log("클래스 인스턴스화 : " + monster.GetHashCode());
    }
}

 

각각 10번씩 반복해서 Instantiate (인스턴스화) 해보았다.

public class ScriptableSpawn : MonoBehaviour
{
    [SerializeField]
    private GameObject _objectableSlime;    // ScriptableObject를 사용하는 프리팹
    [SerializeField]
    private GameObject _classSlime;         // 클래스를 사용하는 프리팹

    private void Start()
    {
        for (int i = 0; i < 10; i++) 
        {
            Instantiate(_objectableSlime);

            Instantiate(_classSlime);
        }
    }
}

 

- 출력 

  ScriptableObject를 사용하는 오브젝트들은 다 같은 Hashcode를 가진다.

             모든 오브젝트가 Asset으로 생성된 동일한 ScriptableObject를 참조하기 때문이다.

  클래스를 인스턴스화하는 오브젝트들은 다 다른 Hashcode를 가진다. 

              new 키워드를 사용했기 때문에 각각 독립적인 메모리에 할당되어 있다.

             각 인스턴스는 자신만의 데이터 복사본을 가진다.

 

(+)

🔖문제점

상황에 따라 동일한 ScriptableObject를 참조하는 것이 문제가 될 수 있다.

예를 들어, 던전에 슬라임 10마리가 생성되어서 슬라임 한 마리를 처치했는데, 즉 Health가 0 이하로 떨어졌는데

다 같은 메모리를 참조하기 때문에 던전에 생성된 모든 슬라임의 Health가 0 이하가 되는 대참사가 발생할 수도 있다.

 

1. 해결방법

: 변경될 수 있는 데이터는 각 인스턴스에서 별도로 관리해야 한다.

public class Monster : MonoBehaviour 
{
    public MonsterData monster; 	// ScriptableObject 
    private int currentHealth; 	// 변하는 데이터
    
    void Start()
    {
        // 초기 체력은 ScriptableObject에서 복사
        currentHealth = monster.Health;
    }
}

 

2. 불변의 데이터를 저장하는 데 사용한다.

□ 스프라이트, 사운드 등 에셋참조

□ 몬스터 이름, 설명 등 고정 텍스트 


유니티 - ScriptableObject

https://docs.unity3d.com/kr/2022.3/Manual/class-ScriptableObject.html

 

ScriptableObject - Unity 매뉴얼

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

docs.unity3d.com

 


깃허브

https://github.com/kimYouChae

 

kimYouChae - Overview

클라이언트 개발자 지망생입니다! . kimYouChae has 9 repositories available. Follow their code on GitHub.

github.com