ScriptableObject란
- ScriptableObject는 클래스 인스턴스와는 별도로 대량의 데이터를 저장하는 데 사용할 수 있는 데이터 컨테이너입니다.
ScriptableObject를 쓰는 이유는 다음과 같습니다.
기존 클래스는 내부 변수 하나 당 4Byte가 듭니다(변수에 따라 다름) .
총 4개의 변수가 사용된다 가정할 때, 4X4 = 16Byte가 메모리에 사용되게 됩니다. 만약 좀비라는 몬스터 프리팹이 1000마리를 일반클래스의 변수로 구현했다면 16 X 1000 = 16000Byte(16KB)가 메모리에 사용되게 됩니다.
16KB는 큰 값은 아니지만, 추후 변수가 추가됨에 따라 점점 메모리 소모량이 많아질 것입니다.
하지만, 스크립터블 오브젝트를 사용하면 좀비를 몇 백마리 사용하든 메모리의 스크립터블 오브젝트의 데이터 원본만을 저장하고 이것을 참조하는 방식으로 작동해서 16Byte만 메모리 소모가 됩니다. 즉, 메모리의 소모를 줄일 수 있게 됩니다.
스크립터블 오브젝트 생성 스크립트
- MonsterData.cs
[CreateAssetMenu(fileName = "MonsterData", menuName = "MonsterScriptable/CreateMonsterData", order = int.MaxValue)]
public class MonsterData: ScriptableObject
{
[SerializeField]
private int hp; //4Byte
public int HP { get { return hp; } }
[SerializeField]
private string monsterName; //참조형이라 그때그때 크기 달라짐
public string Name { get { return monsterName; } }
[SerializeField]
private float speed; //4Byte
public float Speed { get { return speed; } }
}
💡 CreateAssetMenu 속성에 대해서는 아래 포스팅을 참고해주세요.
에디터에서 ScriptableObject 생성하기
MonsterData.cs 를 저장한 후, 에디터로 돌아가서 프로젝트 빈 공간을 우클릭 후, 에셋의 이름이 FileName으로 설정한 Monster Data로 잘 생성되는 것을 볼 수 있습니다.
테스트를 위해 생성된 에셋의 이름을 Normal로 바꿔준 후 Ctrl+D를 눌러 2개 더 생성해준 다음 이름을 변경해줍니다.
마지막으로, 인스펙터창에서 Hp, Monster Name, Speed 값을 설정해줍니다.
MonsterData에셋을 참조할 Monster 생성하기
- Monster.cs
public class Monster : MonoBehaviour
{
[SerializeField]
MonsterData monsterData;
public MonsterData MonsterData { set { monsterData = value; } }
public void WatchMonsterInfo()
{
Debug.Log(monsterData.Name);
Debug.Log(monsterData.HP);
Debug.Log(monsterData.Speed);
}
}
테스트를 위해 빈오브젝트를 하나 생성하고 Monster라고 이름을 바꿔준 후, Monster스크립트를 부착시켜줍니다.
그 다음, 해당 오브젝트를 프리팹으로 만들고 하이러키창에서 삭제해줍니다.
Monster 소환 스크립트
- SpawnMonster
using UnityEngine;
public class SpawnMonster : MonoBehaviour
{
public enum MonsterType { Normal, Tanker, Speeder};
public List<MonsterData> MonsterDatas = new List<MonsterData>();
public GameObject monsterPrefab;
private void Start()
{
SpawnMonsterObject();
}
public void SpawnMonsterObject()
{
for (int i = 0; i < MonsterDatas.Count; i++)
{
var monster = SpawnMonsterFunc((MonsterType)i);
monster.WatchMonsterInfo();
}
}
public Monster SpawnMonsterFunc(MonsterType type)
{
var newMonster = Instantiate(monsterPrefab).GetComponent<Monster>();
newMonster.MonsterData = MonsterDatas[(int)(type)];
return newMonster;
}
}
MonsterDatas List에는 아까 생성한 Monster(ScriptableObject)을 집어 넣어주면 됩니다.
주의) 리스트 순서는 Enum순서에 맞게 설정해줘야 합니다.
MonsterPrefab에도 아까 만들어둔 프리팹을 넣어줍니다.
마지막 테스트 단계
Monster Data(ScriptableObject) 에셋에서 설정한 값들이 잘나오는 것을 확인할 수 있습니다.
Monster 오브젝트는 MonsterData(ScriptableObject) 에셋으로 부터 데이터를 받는 관계이며,
Monster 오브젝트는 SpawnManager를 통해 소환되는 구조를 갖고 있습니다.