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
깃허브
kimYouChae - Overview
클라이언트 개발자 지망생입니다! . kimYouChae has 9 repositories available. Follow their code on GitHub.
github.com
'Unity' 카테고리의 다른 글
[Unity][멀티플레이] 게임에서 충돌 시 동기화 문제 (0) | 2025.02.20 |
---|---|
[Unity][멀티플레이] #1. Photon을 유니티에 연동해보자 (0) | 2025.02.19 |
[Unity] 맵 범위를 넘어가지 않는 카메라 구현 / Mathf.Clamp (0) | 2025.02.17 |
[Unity] 씬 전환 (DontDestroyOnLoad) 오브젝트 Missing 문제 (0) | 2025.01.31 |
[Unity] 스크립트 실행 순서 (0) | 2025.01.21 |