원문: Prefab workflow improvements, Prefabs, Nested Prefabs, Prefab Variants, Editing a Prefab in Prefab Mode
참고용 예제 저장소: Unity Prefab Workflow (Sungkuk Park)

본문은 Prefab에 대한 개요부터 시작해 Unity 2018.3.0 버전부터 적용된 신규 Prefab 워크플로우와 그 구성 요소들을 소개하고 각 요소에 대한 입문을 예제를 통해 돕는 포스팅이다. 본문과 관련된 오탈자 신고나 피드백은 sungkukshawnpark@gmail.com으로 부탁드린다.

Prefab이란?

Unity의 Prefab 시스템은 원하는 GameObject를 해당 GameObject에 포함된 모든 컴포넌트와 프로퍼티 값, 그리고 자식 GameObject를 포함해 재사용 가능한 어셋(Asset)의 형태로 생성, 변경, 저장하도록 지원하는 시스템이다. 이 Prefab 어셋은 씬(Scene)에 Prefab 인스턴스를 생성하는데 필요한 템플릿(template)의 역할을 한다.

만약 사용자가 NPC, 프롭(prop), 또는 배경 일부를 GameObject로 만든 뒤 특정 씬이나 프로젝트 전반에서 여러 번 재사용하고자 한다면 해당 GameObject를 Prefab으로 만들어야 한다. 이처럼 Prefab을 활용하는 방법은 Prefab이 각 복제본과의 동기화를 보장한다는 점에서 GameObject를 단순히 복사해서 붙여넣는 것보다 나은 방법이다.

요약하자면,

  1. Prefab은 일부 GameObject들을 재사용할 목적(reusability)으로 존재하는 시스템이며,
  2. 각 Prefab에 대한 인스턴스들의 동기화(synchronization)를 보장하는 시스템이다.

사용자의 편집을 통해 Prefab 어셋에 발생한 변경은 자동적으로 해당 Prefab에 대한 모든 인스턴스들에 반영된다. 이는 사용자가 해당 어셋의 복제본에 대한 반복적인 작업을 수행하지 않고도 프로젝트에 전역적인 변경을 가하도록 도와준다.

또한, 사용자는 Prefab 내부에 다른 Prefab을 중첩(nest)시켜 오브젝트들의 복잡한 계층 구조를 생성해 복층 구조로도 중첩된 해당 Prefab을 쉽게 편집할 수도 있다.

그러나, 위에서 언급한 동기화가 모든 Prefab 인스턴스들이 반드시 동일해야 한다(identical)는 의미는 아니다. 사용자는 특정 Prefab의 인스턴스가 다른 Prefab 인스턴스들과 차별화되도록 각 Prefab 인스턴스의 설정을 오버라이드(override)할 수 있다. 사용자는 각 Prefab에 대한 변종(variants)들을 만들 수 있고 이는 사용자가 특정 오버라이드 집합을 만들어 해당 Prefab에 대한 유의미한 차이(variation)를 갖도록 만들 수 있다.

또한, 사용자는 Prefab을 활용해 런타임(runtime)에 초기에는 씬에 존재하지 않았던 GameObject를 인스턴스화(instantiate)하는 용도로도 활용할 수 있다. 예컨대, 사용자는 파워업(powerup) 아이템, 특수 효과, 투사체, 또는 NPC 등을 게임플레이 도중 원하는 시점에 등장하게 만들 수 있는 것이다.

Prefab의 일반적인 사용 사례들

일반적인 Prefab의 사용 사례들은 다음과 같다:

  1. 배경 어셋 - 하나의 씬에서 여러 차례 사용되는 특정 나무 프롭(prop)을 예로 들 수 있다.
  2. NPC(Non-player characters)들 - 하나의 씬 뿐만 아니라 여러 개의 씬에서 등장하는 특정 로봇 캐릭터를 예로 들 수 있다. 해당 로봇 캐릭터는 오버라이드를 통해 움직이는 속도나 발생시키는 사운드가 각기 다를 수 있다.
  3. 투사체들(Projectiles) - 예컨대, 해적의 대포의 경우 매번 발사할 때마다 대포알 Prefab에 대한 인스턴스화를 활용해 발사 동작을 구현할 수 있다.
  4. 플레이어 캐릭터(The player’s main character) - 플레이어 캐릭터 Prefab의 경우는 분리된 씬에 해당하는 각 레벨의 초기 위치에 배치될 수 있다.

PrefabsIntroScene

신규 Prefab 워크플로우의 등장

2018년 12월 7일에 출시된 Unity 2018.3.0 버전부터는 Prefab에 대한 신규 워크플로우(workflow)가 지원되기 시작했다. 이 신규 워크플로우의 구성 요소들로는 프리팹 모드(Prefab Mode), Prefab의 중첩 기능(Nesting) — 즉, 중첩 프리팹(Nested Prefabs), 그리고 프리팹 변종(Prefab Variants)을 들 수 있다.

프리팹 모드 (Prefab Mode): 편집에서의 실수를 방지

프리팹 모드(Prefab Mode)는 신규 Prefab 워크플로우의 중추로서, 사용자가 Prefab 어셋을 고립시켜 편집하도록 한다.

Prefab 어셋을 편집하기 위해서는, 해당 어셋을 프리팹 모드에서 열도록 한다. 프리팹 모드는 사용자가 프리팹 어셋을 씬 내의 다른 오브젝트들로부터 고립시켜 해당 컨텐츠를 확인하고 편집할 수 있게 해준다. 프리팹 모드에서의 변경은 해당 Prefab의 모든 인스턴스들에 일괄 적용된다.

Prefab 어셋을 씬에 생성하거나 이미 존재하는 인스턴스를 편집하지 않고도 편집할 수 있다는 사실은 결국 사용자가 의도치 않게 특정 씬에 편집 내용을 적용하게 되는 실수를 방지하기 위한 것이다. 특정 Prefab에 대한 인스턴스에 대한 편집과 어셋에 대한 편집의 분리는 사용자가 실수에 대한 두려움 없이 작업을 할 수 있게 도와준다.

프리팹 모드의 등장과 함께, Hierarchy 창 내에서의 일반 GameObject와 Prefab 인스턴스의 표시 방식 역시 아래와 같이 바뀌었다.

2018.2_prefabIcons

그림 1. 2018.2 버전에서의 Hierarchy 내 Prefab 표시 방식

2018.2_prefabIcons

그림 2. 2018.3 버전에서의 Hierarchy 내 Prefab 표시 방식

위의 스크린샷에서 알 수 있듯이, 기존의 일반 GameObject들은 검은색 글씨체로, Prefab 인스턴스들은 파란색 글씨체로 표시되던 것이 각각 회색 상자 아이콘과 파란색 상자 아이콘으로 대체되었다. 특히, 위의 그림 2에서 PrefabInstance라는 오브젝트의 오른쪽에 화살표 버튼이 생겼는데, 해당 버튼을 누르면 즉시 프리팹 모드에 진입해 Prefab 어셋을 직접 편집할 수 있다.

프리팹 모드에 진입하는 3가지 방법

프리팹 모드에서 Prefab을 편집하는 방법으로는 여러 가지가 있다:

  1. Project 창에서 해당 Prefab을 더블-클릭하기
  2. Hierarchy 창에서 해당 Prefab 오른쪽에 위치한 화살표 버튼을 누르기
  3. Project 창에서 해당 Prefab 어셋을 선택한 뒤 Inspector 창의 “Open” 버튼을 누르기

PrefabArrowNextToPrefab

그림 3. Hierarchy 창의 오른쪽에 화살표 버튼이 위치한 것을 볼 수 있다

프리팹 모드에 진입하는 것은 곧 Scene 뷰와 Hierarchy 윈도우가 해당 Prefab의 컨텐츠만을 표시하게 한다는 뜻이다. 그리고 해당 Prefab의 루트(root) 오브젝트는 아래와 같이 일반적인 GameObject로 표현되며 파란색 Prefab 인스턴스 아이콘을 표시하지 않는다.

PrefabsSceneAndHierarchyInPrefabMode

그림 4. 프리팹 모드에서의 Scene 뷰와 Hierarchy 창

프리팹 모드에서 Scene 뷰는 상단에 브레드크럼 바(breadcrumb bar)를 표시하게 된다. 맨 오른쪽의 항목은 현재 열린 Prefab을 의미한다. 사용자는 이 브레드크럼 바를 활용해 메인 씬이나 다른 Prefab 어셋으로 되돌아갈 수 있다.

PrefabsBreadcrumbBar

그림 5. Scene 뷰 상단에 위치한 이 브레드크럼 바는 프리팹 모드에서만 표시된다

추가적으로, 프리팹 모드에서 Hierarchy 윈도우는 상단에 Prefab 헤더 바(header bar)를 표시해 현재 열려있는 Prefab이 무엇인지 알려준다.

사용자는 헤더 바에 위치한 뒤로 돌아가기 화살표 버튼을 사용해 한 단계 뒤로 돌아갈 수 있으며, 이는 Scene 뷰의 브레드크럼 바에서 이전 브레드크럼 바를 클릭하는 것과 정확히 같은 동작을 수행한다.

PrefabsBackArrow

그림 6. Hierarchy 창 상단에 위치한 헤더 바의 뒤로 돌아가기 화살표 버튼은 프리팹 모드에서만 표시된다

자동 저장 (Auto Save) 기능

프리팹 모드는 Scene 뷰 우측 상단 코너에 Auto Save 설정을 가진다. 해당 설정이 활성화된 경우, Prefab에 적용되는 모든 변경은 즉시 Prefab에 적용된다. Auto Save 설정은 기본값으로 활성화되어 있다.

PrefabsAutoSave

그림 7. 프리팹 모드에서 등장하는 Scene 뷰 우측 상단의 Auto Save 토글

만약 프리팹 모드에서의 변경이 자동적으로 Prefab 어셋에 적용되지 않길 원한다면, Auto Save 설정을 비활성화시키면 된다. 이 경우, 현재 편집 중인 Prefab에 대한 프리팹 모드를 종료할 때 변경 내역을 저장할지 아니면 폐기할지에 대한 결정을 요구하는 팝업 창이 뜨게 된다. 이 토글은 프리팹 모드에서의 편집이 느려질 때 비활성화하면 유용하다.

환경 편집 (Editing Environment) 기능

프리팹 모드에서는 씬(Scene)을 편집 환경(editing environment)로 할당할 수가 있는데, 이는 사용자가 빈 씬에서 작업하기보다는 특정 배경을 선택한 상태에서 편집을 진행할 수 있게 해준다. 이는 특정 Prefab이 게임의 환경에 영향을 받아 어떻게 보이는지 확인할 때 특히 유용하다.

이에 대한 구체적인 설명은 다음 Unity 공식 매뉴얼을 참고할 것: Editing a Prefab in Prefab Mode

중첩 기능 (Nesting): 데이터의 유연성과 생산성 증대

기존의 사용자는 건물처럼 거대하고 단일한 Prefab을 생성하거나 가구처럼 작은 Prefab을 생성하는 양자택일의 선택권 밖에는 없었다. 하지만 이제는 중첩 프리팹을 통해 거대한 건물 Prefab은 작은 방 Prefab들로 구성될 수 있고, 다시 해당 방 Prefab들은 여러 개의 가구 Prefab으로 구성될 수 있다.

즉, 사용자는 Prefab 내부에 다른 Prefab을 포함할 수 있다. 이를 프리팹 중첩(nesting Prefabs)이라 한다. 이 프리팹 중첩을 통해 다른 Prefab에 포함된 Prefab을 중첩 프리팹(Nested Prefabs)이라 부르자. 이 중첩 프리팹들은 다른 Prefab의 부분으로서 포함된 상태에서도 각각의 Prefab 어셋에 대한 링크를 유지한다.

이러한 기능은 팀의 사이즈를 막론하고 다음과 같은 생산성 증대 효과를 가져온다:

  1. 작업 효율을 위해 Prefab들을 여러 개의 개체로 분리할 수 있다
  2. 크기와 관계없이 어떤 컨텐츠든 재활용할 수 있다
  3. 컨텐츠의 각기 다른 부분을 동시에 작업할 수 있다

중첩 기능 예제

이번 중첩 기능 예제에서는 SF 우주 전투 시뮬레이션 게임을 만드는 상황을 가정해보자. 이 게임 내에서는 다양한 종류의 초계기(corvettes)와 전투함(fighters)이 등장하며, 모든 함선 상단의 마커(marker)로 선택 여부가 표시된다. 편의 상 미리 중첩 프리팹을 만들어두었고, 마커 Prefab은 각 함선의 원본에 해당하는 Prefab 어셋의 자식으로 포함되어 있다고 가정하자. 모든 전함의 마커는 같은 Prefab 어셋을 참조한다. 이때, 아래의 각 초계기 위에 보이는 모든 빨간색 마커의 크기값을 일괄적으로 변경하려면 어떻게 해야 할까?

nestedPrefabs-01

그림 8. 각 초계기와 전투함 위에 같은 크기의 마커가 표시된 것을 볼 수 있다

중첩된 프리팹의 크기를 일괄적으로 변경하기 위해서는 간단하게 해당 프리팹을 선택 후 프리팹 모드로 진입한 뒤 해당 크기값(scale)을 변경하고 저장해주기만 하면 된다.

nestedPrefabs-02

그림 09. 모든 함선에 중첩된 프리팹으로 포함된 “Marker” 프리팹의 크기값을 변경해보자

nestedPrefabs-03

그림 10. 각 초계기와 전투함 위의 마커의 크기가 일괄적으로 변경된 것을 볼 수 있다

만약, 전투함의 경우만 마커의 색상을 빨강색에서 초록색으로 바꾸고 싶다면 어떻게 할까?

nestedPrefabs-04

그림 11. 모든 전투함의 원본에 해당하는 Prefab 어셋 “Fighter Unit-01” 내부에 중첩된 “Marker”의 머테리얼(material)을 변경해보자

그런 경우에는 “Marker” 자체를 변경하는 것이 아니라 원하는 변경 영역(scope)에 해당하는 부모 프리팹으로 이동해 원하는 변경점을 오버라이딩해주면 된다.

nestedPrefabs-05

그림 12. 초계기를 제외하고 모든 전투함 위의 마커의 색상이 초록색으로 변경된 것을 볼 수 있다

프리팹 변종 (Prefab Variants): 유연한 프로퍼티

프리팹 변종(Prefab Variants)은 특정 프리팹에 대한 미리 지정된 여러 개의 차이(variations)들을 발생시키는 용도로 적합하다.

기본적으로 프리팹 변종은 특정 Prefab의 오브젝트들과 프로퍼티들을 상속한다. 그러나 동시에, 사용자는 해당 프로퍼티를 오버라이드하고 신규 컴포넌트나 GameObject를 이 변종에 추가할 수 있다. 이는 객체 지향 프로그래밍(OOP)의 상속(inheritance) 개념과 비슷하다.

프리팹 변종 기능 예제

이번 프리팹 변종 예제에서도 SF 우주 전투 시뮬레이션 게임을 만드는 상황을 가정해보자. 이 게임 내에서는 다양한 종류의 초계기(corvettes)가 등장해야 한다. 단, 모든 초계기는 기본 초계기 Prefab에 기반해야 하며, 그럼에도 불구하고 일부 초계기는 다른 초계기와 구분되는 특정 무기를 갖고 있거나, 다른 이동 속도를 갖거나, 아니면 다른 컴포넌트를 포함해야 한다.

참고로, 초계기의 비용과 능력을 표현하는 Corvette 스크립트는 다음과 같다:

using UnityEngine;

public class Corvette : MonoBehaviour
{
    public int Cost = 2;

    public float Speed = 6;
}

우선, 위의 스크립트를 추가한 Prefab 어셋과 그에 대한 인스턴스를 아래와 같이 생성한다.

prefabVariants-01

그림 13. PrefabVariants 씬에 Corvette Unit-01라는 Prefab 어셋의 인스턴스 하나를 생성했다

위의 Prefab 인스턴스는 해당 Prefab 어셋의 기본값을 가지고 있다. 이제 해당 초계기의 비행 속도에 해당하는 Speed를 변경함으로써 아래와 같이 해당 Prefab에 대한 변종(Variant)을 만들 수 있다. 이를 프로퍼티 오버라이드(Property Override)라고 부른다. 오버라이드된 프로퍼티는 아래와 같이 Inspector 창에서 파란색으로 강조 표시된(highlighted) 것을 확인할 수 있다.

prefabVariants-02

그림 14. Corvette 컴포넌트의 프로퍼티 중 하나인 Speed 값을 변경해 Prefab 변종 하나를 생성했다

이후, 프리팹 모드에 진입해 해당 Prefab의 원본에 해당하는 Prefab 어셋의 Corvette 컴포넌트 내 Speed 값을 10으로 변경해보았다.

prefabVariants-03

그림 15. 프리팹 모드에 진입해 Prefab 어셋의 Corvette 컴포넌트의 프로퍼티 중 하나인 Speed 값을 변경해보았다

하지만, 복제본에 해당하는 Prefab 인스턴스의 Speed 값은 10이 아니라 여전히 12이다. 왜냐하면 해당 값은 프로퍼티 오버라이드를 통해 생성된 Prefab 변종으로서 보존되기 때문이다.

prefabVariants-04

그림 16. 원본에 해당하는 Prefab 어셋 내 Component의 프로퍼티가 변경되더라도 프리팹 변종의 Speed 값은 여전히 12이다

또한, 프로퍼티 오버라이드와 별개로 Prefab 인스턴스 각각에 신규 Component나 신규 GameObject를 추가하는 식의 오버라이딩을 통해 Prefab 변종을 생성할 수도 있다. 아래의 Prefab 인스턴스는 Shield 컴포넌트를 추가하고 이온 캐논(Ion Cannon) GameObject를 자식으로 추가한 경우이다. 이때, 추가한 컴포넌트와 GameObject 모두에 대해 ‘더하기(+)’ 아이콘으로 오버라이드되었음이 표시되는 것을 볼 수 있다.

prefabVariants-05

그림 17. Prefab 인스턴스에 Shield 컴포넌트를 추가하고 “ion_cannon” GameObject를 자식으로 추가했다

마지막으로, Prefab 인스턴스를 선택한 뒤 Inspector 창의 우측 상단에 위치한 Overrides 드롭다운 메뉴를 통해 해당 변종에 대한 모든 변경점들을 Prefab 어셋 기준으로 되돌리거나(Revert All), 원본에 해당하는 Prefab 어셋에 적용할 수도 있다(Apply All). 사용자는 해당 메뉴를 통해 어떤 부분이 오버라이드되었고 어떤 부분이 오버라이드되지 않았는지 한눈에 파악할 수 있다.

prefabVariants-06

그림 18. Prefab 인스턴스를 선택한 뒤 Inspector 창의 우측 상단의 Overrides 드롭다운 메뉴를 선택하면 해당 변종에 대한 모든 변경점들을 한눈에 파악할 수 있다

결론

위에서 논한 바와 같이, Prefab은 본질적으로 GameObject를 생성, 변경, 저장하는 방식으로 재사용하기 위해 존재하는 시스템이다. 그러나 새로운 Prefab 워크플로우가 등장하기 이전의 Prefab은 Prefab 내부에 Prefab이 존재할 수 없었기 때문에 데이터의 중복(repetition)을 피할 수 없었다. 이에 Unity는 다수의 개발자들의 의견을 수렴해 신규 Prefab 워크플로우를 Unity 2018.3.0 버전에 포함시켰다.

이 신규 Prefab 워크플로우는 다음 3가지 요소로 구성된다:

  1. 프리팹 모드(Prefab Mode)
  2. 프리팹 중첩(Nesting Prefabs)
  3. 프리팹 변종(Prefab Variants)

여기서 프리팹 모드는 사용자가 Prefab 어셋을 고립시켜 편집하게 함으로써 편집 중에 특정 씬으로 변경 결과가 의도치 않게 적용되는 것을 막아준다. 이 기능은 자동 저장(Auto Save) 기능의 비활성화를 통해 더 신중한 어셋 편집을 지원할 수도 있다.

프리팹 중첩 기능은 Prefab이 다른 Prefab을 포함하는 방식으로 Prefab 데이터의 유연성을 높이고 불필요한 중복을 제거해, 결과적으로 Prefab의 재사용성을 높이는 방식으로 개발 생산성을 증대시킨다.

마지막으로, 프리팹 변종은 프로퍼티 오버라이딩과 GameObject 또는 컴포넌트 추가를 통한 오버라이딩을 통해 사용자가 원하는 범위에 Prefab 변경을 국한시킨다. 또한, Inspector 창의 Overrides 드롭다운 메뉴를 통해 사용자가 특정 Prefab에 대한 변경점을 더 간편하게 일괄적으로 관리할 수 있도록 지원한다.

<끝>