Unity. ScriptableObject & Asset

PAVDUP·2023년 2월 25일
0

Unity Manual Link

Asset

정의

에셋은 Unity 프로젝트에서 게임이나 앱을 만드는 데 사용하는 모든 구성요소이다.
에셋은 프로젝트에서 3D 모델, 텍스처, 스프라이트, 음향 효과 또는 음악과 같은 시각적 또는 청각적 요소 등을 포괄하는 개념이다.
또한 에셋은 컬러 그레디언트, 애니메이션 마스크, 임의 텍스트나 숫자 데이터와 같은 더욱 추상적인 요소 또한 의미한다.

에셋은 3D 모델, 오디오 파일, 이미지와 같은 Unity 외부에서 생성된 파일을 가져오기도 하며, ProBuilder 메시, Animator 컨트롤러, 오디오 믹서, 렌더 텍스처와 같이 - Unity Editor 에서 동작하는 요소로 생성할 수도 있다.

내가 알고 싶었던 것

Unity 내부에서 작동하면서도, 파일 탐색기에 존재하는 여러 다양한 요소들이 '.asset' 으로 표현되었기 떄문에, "저 에셋이라는 게 도대체 뭘 의미하는 건가..." 하는 의문이 들었었다.

위의 내용을 바탕으로 파악해보면, 명료하다.

에셋은 Unity 프로젝트에서 게임이나 앱을 만드는 데 사용하는 모든 구성요소이다.

또한, Unity Editor 내부에서 Animator Controller, Audio Mixer 와 같은, 게임 내에서 사용되는 구성요소들을 직접 만들기도 하는데(이는 파일 탐색기의 Asset 폴더 내부에 저장된다.), 이런 Unity 내부적으로 만들어낸 - 게임에서 사용되는 구성 요소들이 '.asset' 파일로서 표현되는 것이지 않나 한다.

ScriptableObject

Unity 에서의 서술

ScriptableObject는 대량의 데이터를 저장하는 데 사용할 수 있는 데이터 컨테이너.
클래스에 의해 만들어진 인스턴스 (객체들) 과는 다르게 작동한다.

변경되지 않는 정보를 저장하는 Script 를 가진 Prefab 이 있는 경우, Scriptable Object 를 유용하게 사용할 수 있다. (해당 Prefab 을 씬 상에 배치할 때 마다 데이터의 사본들이 생겨나는 것을, Scriptable Object 한 군데에 묶을 수 있으므로. - 이 경우, Prefab 들은 Reference 로서 ScriptableObject 에 접근 한다.)

Scriptable Object 는 프로젝트의 에셋으로 저장된다. (사용되는 자원)

정의

Type of asset in Unity that allows you to create and store custom data without needing to attach it to a game object or component.
게임 오브젝트에 첨부할 필요 없이, 에셋의 형태로서 커스텀 데이터를 생성하고 저장할 수 있도록 해주는 Class.

ScriptableObject 의 사용과 주요 이점은 다음과 같다.

  • ScriptableObject로 생성된 인스턴스는 프로젝트 폴더에 저장되고, 다양한 씬과 게임 오브젝트에서 재사용할 수 있는 assets 의 형태를 띕니다.
    (여러 오브젝트나 씬에 걸쳐 사용할 수 있는 데이터를 저장하고 관리하는데 사용.)
  • ScriptableObject로 생성된 인스턴스는 특정 게임 / 오브젝트 / 씬에 종속되지 않는 독립적인 (standalone) asset 이기 때문에 다른 개발자들과 쉽게 공유하고 분산할 수 있습니다.
  • ScriptableObject로 생성된 인스턴스는 텍스쳐나 모델과 같은 다른 에셋들과 마찬가지로 Unity Editor의 인스펙터 창을 이용하여 생성하고 편집할 수 있다.

활용 및 사례

ScriptableObject의 주요 사용 사례는 다음과 같다.

  • 에디터 세션 동안 데이터 저장 및 보관
  • 데이터를 프로젝트의 에셋으로 저장하여 런타임 시 사용

실전에서 ScriptableObject 를 활용하는 방법을 살펴보자.

사례 1

베르의 프로그래밍 노트 - ScriptableObject

using UnityEngine; 

[CreateAssetMenu(fileName = "Zombie Data", menuName = "Scriptable Object/Zombie Data", order = int.MaxValue)] 
public class ZombieData : ScriptableObject 
{ 
	[SerializeField] private string zombieName; 
	public string ZombieName { get { return zombieName; } } 
	[SerializeField] private int hp; 
	public int Hp { get { return hp; } } 
	[SerializeField] private int damage; 
	public int Damage { get { return damage; } } 
	[SerializeField] private float sightRange; 
	public float SightRange { get { return sightRange; } } 
	[SerializeField] private float moveSpeed; 
	public float MoveSpeed { get { return moveSpeed; } } }

다음과 같이 ScriptableObject의 상속을 받는 ZombieData Script를 만들었다.
위의 'CreateAssetMenu' Attribute 를 사용하여, Unity Editor 를 Customize 하였기 때문에 => Project Window 에서 마우스 우클릭 후, Asset 을 Create 하는 항목에서 해당 ScriptableObject 를 확인할 수 있다.

이때 해당 ScriptableObject 를 선택하면, ScriptableObject 의 Instance 가 에셋으로서 생성된다.

![[Pasted image 20230225210541.png|400]]

이렇게 생성한 ScriptableObject 의 Instance 들은 서로 다른 이름을 가질 수 있다.
또한 서로 다른 값을 설정함으로써, 같은 종류의 값 종류를 가지지만, 다른 실질적 값이 들어있는 Data 저장소를 만들 수 있다.

Asset 으로서 생성된 ScriptableObject는 Script에서 ScriptableObject 의 Type 에 접근함으로써 쉽게 접근할 수 있다.

예시 코드를 살펴보자.

public class Zombie : MonoBehaviour 
{ 
	[SerializeField] private ZombieData zombieData; 
	public ZombieData ZombieData { set { zombieData = value; } } 
	
	public void WatchZombieInfo() 
	{ 
		Debug.Log("좀비 이름 :: " + zombieData.ZombieName); 
		Debug.Log("좀비 체력 :: " + zombieData.Hp); 
		Debug.Log("좀비 공격력 :: " + zombieData.Damage); 
		Debug.Log("좀비 시야 :: " + zombieData.SightRange); 
		Debug.Log("좀비 이동속도 :: " + zombieData.MoveSpeed); 
	} 
}

ZombieData라는 type 을 통해 에셋으로서 마련되어 있는 ScriptableObject 의 인스턴스에 쉽게 접근할 수 있으며, 멤버 연산자를 통해 ScriptableObject 의 인스턴스 내부의 정보에 쉽게 접근할 수 있다.

이후 더 응용에 대해 생각해보자.
링크에 나와있는 내용이기는 하나, ZombieSpawner 라는 모든 ScriptableObject의 인스턴스와 연결되어 있는 것을 만들어, ZombieScript 가 붙어있는 오브젝트를 만들어 줄 때마다, 사용해 줄 수 도 있다.

사례 2

Unity 공식 Documentation 에 나와있는 사례이다.

// ScriptableObject
using UnityEngine; 

[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/SpawnManagerScriptableObject", order = 1)] 
public class SpawnManagerScriptableObject : ScriptableObject 
{ 
	public string prefabName; 
	public int numberOfPrefabsToCreate; 
	public Vector3[] spawnPoints; 
}
// Usecase
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++; 
		} 
	} 
}

'SpawnManagerScriptableObject' Class를 만들고, 이를 통해 ScriptableObject 의 Instance 를 만든다.
이후, Spawner 에서 SpawnManagerScriptableObject 를 사용하여, Spawn 동작에 활용한다.

해당 Spawner 의 SpawnEntities Method 는 해당 Class 의 Field 로서 들어있는 entityToSpawn GameObject 를 SpawnManagerScriptableObject의 포인트에, 원하는 이름으로, 원하는 숫자만큼 생성해주는 method 이다.

응용 1

에디터에서는 스크립터블 오브젝트에 데이터를 저장하는 작업이 언제나 가능하지만, 배포된 빌드에서는 데이터를 저장할 수 없고 개발시 설정한 스크립터블 오브젝트 에셋에 저장된 데이터만을 사용할 수 있다.

에디터 툴에서 에셋 형태로 ScriptableObject에 저장한 데이터는 디스크에 작성되므로 세션 간에도 그대로 유지된다.

응용 2

출처 링크

ScriptableObject 도 Monobehavior 와 마찬가지로 유니티 Callback method (Event Functions) 를 지닌다.

  • OnEable : ScriptableObject가 instantiated/loaded 될 때. 해당 스크립트로 Instance (에셋) 가 생성될 때, Unity 가 컴파일 된 후 호출된다.
  • OnDisable : ScriptableObject를 파괴할 때 (에셋을 삭제할 때), 에디터에서 스크립트가 컴파일 되기 전에 호출된다.
  • OnDestroy : ScriptableObject를 파괴할 때 호출된다.

의견

응용 2의 출처 링크 에서 제안된 내용이다.

  • ScriptableObject는 기존에 없던 시스템을 Unity가 새로 만든 것은 아니다. Json, xml, csv 등으로 관리하던 데이터를 Unity에서 쉽게 사용할 수 있도록 편의적인 기능으로 제공하는 것으로 이해할 수 있다.

  • 소규모의 데이터를 편하게 관리할 수 있는 장점이 있지만, 대용량의 데이터를 ScriptableObject로 관리하기엔 어려움이 있을 것으로 생각된다. 대규모의 데이터는 기본적으로 엑셀로 관리하는 것이 편하기 때문이다. 만약 ScriptableObject로 데이터를 관리한다고 할 경우 프로젝트에 맞는 툴 개발이 필요할 것으로 사료된다.

  • 외부 데이터를 파싱해서 사용하는 번거로움을 피하고, 데이터의 관리 부하가 크지 않다면 ScriptableObject를 사용하는 것이 편하고 최적화에도 도움이 될 것으로 생각한다. 또는 에디터에서 편하게 관리가 필요한 데이터만 ScriptableObject를 사용하는 것도 좋은 개발 방향이 될 수 있을 것으로 생각된다.

profile
오와우아오왕

0개의 댓글