본문 바로가기
Unity/스크립터블오브젝트

Scriptable Object - 개요 (1)

by PlaneK 2020. 5. 28.

좋은 아키텍쳐는 모듈화 여부에 있다

기존 방식은 MonoBehaviour 개체를 정의할 기능을 잘게 세분화하지 않고 스크립트 하나에 모두 정의한다. 따라서 MonoBehaviour 동작 시점과 조건이 같은 일부 기능을 다른 개체에 재사용 할 없다. 왜냐하면 공통적인 기능 외에 다른 기능도 정의됐기 때문이다. 다른 개체로써는 불필요한 프로퍼티를 요구하고 있고 프로퍼티의 참조를 구하지 못해도 기능이 동작되리라 신뢰하기 힘들다(재사용 가능 여부를 검증하기 위해 코드 분석이 발생한다).

때문에 기능을 잘게 세분화(granularly) 필요가 있다. 그런 MonoBehaviour 기능이 동작하는데 필요한 최소한의 프로퍼티를 명시만 해주고 참조하는 시점과 조건 틀만 정의해주면 된다. 구체적인 기능 정의는 프로퍼티가 한다.  MonoBehaviour 준비된 틀에 프로퍼티라는 내용물을 채워 넣는 역할만 한다. 이는 크게 보면 '모듈화' 있다. , 좋은 아키텍쳐의 핵심 키워드는 '모듈화'.

프로퍼티가 기능을 정의하려면 프로퍼티는 MonoBehaviour로 작성된 특정 시스템이거나 컴포넌트 또는 ScriptableObject여야 한다. 아키텍쳐가 지향하는 프로퍼티는 모두 ScriptableObject로 만들어진다. 

Coin.cs, Bird.cs, SomeNPC.cs → Interactable.cs, Destructible.cs, Tradible.cs 
기능을 세분화하면 좌측의 스크립트들은 모두 우측의 스크립트로 세분화될 수 있다. 개체인 Coin과 Bird, SomeNPC는 이제 이 3가지의 MonoBehaviour 컴포넌트를 사용한다. 세 개체가 갖는 유일한 다른 점은 프로퍼티 에셋이다.

 

좋은 아키텍쳐의 이점

실제 개발 과정에서 다른 점은 뭘까? 기존에는 MonoBehaviour 신규 작성해주면 된다. 하지만 모듈화를 위해서는 MonoBehaviour 더불어 해당 프로퍼티의 ScriptableObject 작성하고 에셋을 추가해 줘야한다. 개발 공수가 쓸데없이 불어난 기분이다.

그렇다면 ScriptableObject 프로퍼티와 기능을 정의하고 MonoBehaviour 이들의 Asset 참조하는 방식은 무슨 이점이 있을까?

"초기화 작업과 수정 작업은 코드가 아닌 인스펙터 상에서, 확장 작업은 신규 작성이 아닌 기존 소스 재사용과 에셋 생성으로" → [스크립터블 오브젝트].asset 파일은 모두에게 언제든지 참조 가능한 인스턴스이다.

모듈화 / 확장성

1. 씬을 비울 있어서 전환이 수월해 진다. 씬이 채워지는 이유는 디펜던시를 참조하기 위해 디펜던시의 인스턴스 배치 또는 디펜던시를 매개하는 싱글톤 매니저의 배치 때문이다. ScriptableObject 만들어진 프로퍼티는 Asset으로써 디스크에 존재하기 때문에 언제 어디서든 참조 가능하다. 그래서 싱글톤 매니저 등을 씬에 띄울 필요도 없고 매니저의 초기화 작업도 필요 없어진다.

디펜던시(의존성)는 프로퍼티의 일종이며 '외부 클래스'라고 바꿔 써도 무방하다. 자신의 기능을 동작하는데 필요한, 외부 개체인 것이다. 디펜던시라 불리는 외부 개체들은 자신과 통합할 수 없는 분리된 영역에 있고 독립적이다. 

2. 모든 오브젝트를 프리팹화 있다. 그래서 유연하게 변경을 반영할 있다.  기존에는 씬에 미리 배치해서 디펜던시를 Drag&Drop해서 참조했다. 왜냐하면 프로퍼티가 .Asset 형태가 아닌 인스턴스이므로 disk로부터 참조할 없기 때문이다(해당 디펜던시가 프리팹이더라도 인스턴스가 아니므로 생성된 인스턴스를 할당하는 초기화 작업이 필요). 그래서 기존 개체가 새로운 프로퍼티를 요구하거나 새로운 개체가 씬에 등장하면 씬에서 Drag&Drop하는 작업이 필요했다.

그러나 ScriptableObject 프로퍼티를 .Asset으로 정의하면 모든 개체의 프로퍼티를 프리팹 단에서 구성 가능하다. 그래서 어떤 개체에 특수한 어빌리티나 기능을 추가하거나 제거할 프리팹 단에서 해당 컴포넌트만 반영해 주면 된다. 기존처럼 씬에 존재하는 모든 오브젝트를 찾아 하나하나 반영해줄 필요가 없다.

쉬운 디버깅 / 테스트 / 밸런싱

3. 코드를 들여다보는 시간이 최소화되며 디버깅이 쉬워진다. Asset Inspecor뷰를 통해 값이 무엇인지 점검 가능해진다. 그리고 옵저버 패턴을 사용해 설계된 이벤트-리스너 관계와 DataSet(기존 싱글톤 매니저; 디펜던시를 모아놓고 개체들에게 매개해주는 역할) 통해서 개체의 리스너와 DataSet 값을 inspecor뷰에서 바로 확인할 있다.

4. ScriptableObject 만든 Asset Enum 대체할 있다. 따라서 Enum 단점을 극복할 있다. Enum 단점은 index 사용되는 요소는 int 매핑되기 때문에 중간요소의 제거나 순서 변경이 발생하면 반드시 index 재정렬(reorder) 필요하다. 하지만 Asset으로 대체하면 이런 단점이 없어지고 Enum 같이 Index 역할도 하며 동시에 기능도 정의한다. "확장성"

5. 아키텍쳐의 프로퍼티는 .Asset 파일이므로 플레이모드가 종료되도 값이 유지된다. 그래서 테스트와 밸런싱 작업이 수월하다. 런타임에서 값을 조정할 있고 값들은 Asset 바로 저장되기 때문이다.

간결한 코드

6. 기능 파악이 쉬워진다. 기능을 파악하기 위해 MonoBehvaiour 통해 언제 어떻게 동작되는지는 필요 없이 inspector뷰를 통해 프로퍼티의 값을 보거나 ScriptableObject 코드만 분석하면 된다. MonoBehaviour 신규 기능을 추가하기 위해 MonoBehaviour 기존 로직을 크게 변경하거나 비대해질 필요가 없다. 기능 정의는 프로퍼티가 하기 때문에 해당 프로퍼티의 ScriptableObject Asset 추가하면 된다. MonoBehvaiour 그대로 프로퍼티를 참조하는 시점과 조건만 정의한다. (feat. 스트레티지 패턴)

 

(Unite Austin 2017 - Game Architecture with Scriptable Objects)
https://youtu.be/raQ3iHhE_Kk

(Unite Europe 2016 - Overthrowing the MonoBehaviour tyranny in a glorious ScriptableObject revolution)
https://youtu.be/VBA1QCoEAX4

(Three ways to architect your game with ScriptableObjects)
https://unity.com/how-to/architect-game-code-scriptable-objects

 

댓글