Prefab (프리팹)
프리팹 정의와 생성
👉 오브젝트를 에셋 파일로 만들어 두는 것을 Prefab 이라고 한다. 만들어 둔 프리팹을 CLone 화 하여 씬에 실존하는 오브젝트로 찍어낼 수 있다.
프리팹을 이용하여 게임 도중에도 실시간으로 오브젝트를 씬 상에서 실존하도록 찍어내어 생성할 수 있고, 프리팹 하나로 수 많은 동일한 오브젝트들을 동시에 생성할 수도 있다. Class(프리팹)를 만들어 두고 이것을 객체 인스턴스(오브젝트)로 찍어내는 것과 같다. 프리팹은 오브젝트와 다르게 게임 상에 실존하는게 아니라 오브젝트를 찍어내는 틀이라고 생각하면 된다.
프리팹 만드는 방법
- 그냥 프리팹화 하려는 오브젝트를 📂Assets 에 드래그 앤 드롭 하면 된다.
프리팹을 Scene에 오브젝트로서 찍어내기 (Clone 만들기)
- 마찬가지로 Hierarchy 혹은 Scene 창에 프리팹을 드래그 앤 드롭하면 된다.
- 코드 상으로는 Instantiate 함수를 사용하여 프리팹을 오브젝트로 실존하게 찍어낼 수 있다.
프리팹 수정하는 방법
- 수정하려는 프리팹 더블 클릭. 혹은 Open Prefab 누르면 해당 프리팹을 수정할 수 있는 모드가 나온다. (오브젝트로서가 아닌 프리팹으로서 수정한다.)
- 아래와 같이 프리팹으로 만든 오브젝트를 통해 프리팹을 수정하려면 Hierarchy 에서 해당 오브젝트 옆에 조그만 화살표를 누르면 프리팹 모드로 갈 수 있다!
프리팹 오버라이딩
프리팹으로 Cube, Cube(1), Cube(2) 이렇게 3개의 오브젝트를 찍어낸 상태이다. 그러니 셋 다 프리팹에 설정되어 있는 기본값을 따른다. 그러나 Cube(1)의 Box Collider 컴포넌트를 Cube(1)만 좀 수정해보니! 이렇게 Cube(1)의 인스펙터의 Overrides 버튼을 눌러 보면 프리팹과 다르게 어떤 부분이 달라졌는지, 즉 어떤 부분이 오버라이딩 되었는지가 표시난다.
오버라이딩 된(기존 프리팹과 다르게 재정의 된) 부분을 클릭하면 이렇게 어떻게 달라졌는지 친절하게 나온다! 프리팹에선 박스 콜라이더의 사이즈가 1, 1, 1 이었는데 Cube(1)의 박스 콜라이더는 사이즈가 3, 3, 3 으로 오버라이딩 됐다는 것을 볼 수 있다.
Revert All 👉 다시 프리팹에서 설정된 기본값들로 되돌림
Apply All 👉 프리팹에도, 모든 오브젝트(같은 프리팹으로 찍어낸)들에게도 이렇게 재정의한 내용을 다 적용 시킴.
프리팹은 프리팹과 동일한 속성과 값을 가진 여러개의 오브젝트로 찍어낼 수도 있지만 또 이렇게 찍어낸 각각의 오브젝트들도 다르게 개성있게 재정의할 수 있다는 장점이 있다!
Nested Prefab
👉 프리팹 속 프리팹. 즉 프리팹을 구성하고 있는 요소에 또 다른 프리팹이 있는 경우다.
Prefab Variant
상속 개념이다. 👉 다 물려 받되, 자신만의 새로운 기능 추가.
이미 프리팹으로 만들어진 오브젝트를 가지고 다시 프리팹으로 만드려고 한다면 위와 같은 다이얼로그가 뜬다.
Original Prefab
지금 자기 자신의 모습 그대로를 바탕으로 별개의 새로운 프리팹을 만든다.
Prefab Variant
자기 자신을 찍어냈던 그 프리팹을 상속받는 새로운 프리팹으로서 만든다. 추후 오버라이드도 할 수 있고 새로운 기능도 덧붙일 수 있되, 기존의 프리팹 성질은 다 물려 받는 새로운 자식 프리팹을 생성하는 것과 마찬가지다.
프리팹을 인스턴스로 찍어내는 방법
유니티 에디터에서 직접 할당하기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PrefabTest : MonoBehaviour
{
public GameObject prefab;
void Start()
{
Instantiate(prefab);
}
}
1️⃣ public GameObject prefab;
프리팹을 할당할 수 있는 GameObject 타입의 변수를 선언하고 유니티 에디터에서 변수에 직접 프리팹을 할당해준 후 Instantiate 함수의 인수로 넘겨주는 방법.
Instantiate
- 인수로 넘겨 받은 프리팹을 인스턴스(실존하는 게임 오브젝트)화하고, 생성한 게임 오브젝트를 리턴한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PrefabTest : MonoBehaviour
{
public GameObject prefab;
GameObject tank;
void Start()
{
tank = Instantiate(prefab);
Destroy(tank, 3.0f);
}
}
tank에 프리팹으로 찍어낸 오브젝틀르 받아 놓고 이를 사용해 Destroy를 이용하여 3초 후에 삭제한다.
코드 상으로 Resources 사용하여 프리팹 지정
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PrefabTest : MonoBehaviour
{
private GameObject prefab;
GameObject tank;
void Start()
{
prefab = Resources.Load<GameObject>("Prefabs/Tank");
tank = Instantiate(prefab);
Destroy(tank, 3.0f);
}
}
2️⃣ Resources.Load<GameObject>(“Prefabs/Tank”);
**Resources.Load<에셋타입>(string 에셋경로)**
- 불러오려는 에셋의 타입과 에셋의 경로를 지정해주면 해당 에셋을 로컬 환경(📂Resources)에서 찾아 GameObject로서 불러오고 이를 리턴하는 함수다.
- 📂Assets/Resources 로컬 폴더에서 에셋을 가져온다. 그러므로 위의 예에선 📂Assets/Resources/Prefabs 폴더에 있는 “Tank” 프리팹을 가져오게 되는 것이다.
- 만약 📂Resources 폴더가 없을 경우 직접 만들어주자.
프리팹을 직접 유니티 에디터에서 일일이 변수에 할당해줄 필요 없이 게임 중에 코드상으로 불러올 에셋이 있다면 📂Resources 폴더 안에 넣어두고 Resources.Load 함수를 사용하자.
ResourceManager.cs
여러 스크립트 내에서 Resources.Load 함수를 사용하여 에셋을 불러오거나 아니면 직접 변수에 에셋을 할당하는 식으로 하면, 여러 곳에서 불러오는 작업을 하게 되므로 잘못되도 추적이 어렵고 수정도 어려워 진다.
👉 오로지 에셋을 불러오는 작업만 하는 스크립트로 따로 만들었다. Input Manager 처럼!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ResourceManager
{
public T Load<T>(string path) where T : Object
{
return Resources.Load<T>(path);
}
public GameObject Instantiate(string path, Transform parent = null)
{
GameObject prefab = Load<GameObject>($"Prefabs/{path}");
if (prefab == null)
{
Debug.Log($"Filed to load prefab : {path}");
return null;
}
return Object.Instantiate(prefab, parent);
}
public void Destroy(GameObject go)
{
if (go == null)
return;
Object.Destroy(go);
}
}
Load 제네릭 사용자 지정 함수 정의
- where T : Object 👉 부모 클래스가 Object 인 타입만 받을 수 있도록 제약을 걸음 (C# 문법)
- Resources.Load(path)
- 👉 📂Resource 폴더를 시작 위치로 한 “path”에 해당하는 T 타입의 에셋 파일을 불러오고 이를 리턴한다.
Instantiate 사용자 지정 함수 정의
- Load 를 사용해 prefab에 path 에 해당하는 GameObject 타입의 에셋을 할당한다.
- 📂Resource의 📂Prefab 에서 찾아 온다. ($”Prefabs/{path}”)
- 성공적으로 찾았다면 Object.Instantiate(prefab, parent) 리턴한다.
✨그냥 Instantiate이 아닌 Object.Instantiate 이라고 명시해준 이유 ✨
👉그냥 Instantiate 라고 명시하면 지금 정의하고 있는 이 사용자 지정 함수 Instantiate 라고 인식되서 재귀호출 되기 때문이다. 따라서 못 찾았다면 null을 리턴한다.
Destroy 사용자 지정 함수 정의
마찬가지로 재귀를 막기 위해 Object. 까지 붙여서 Object.Destroy 호출
📜Manager.cs
이전 포스트에 다루었던 게임 전반적인 부분을 총관리하는 싱글톤이다. 마찬가지로 📜Resource Manager도 📜Manager.cs 의 멤버로 두어(구성 요소로 두어) 싱글톤으로 관리하자.
추가된 부분은 아래와 같다.
ResourceManager _resource = new ResourceManager();
public static ResourceManager Resource { get { return Instance._resource; } }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Managers : MonoBehaviour
{
static Managers s_instace;
static Managers Instance { get { Init(); return s_instace; } }
InputManager _input = new InputManager();
ResourceManager _resource = new ResourceManager();
public static InputManager Input { get { return Instance._input; } }
public static ResourceManager Resource { get { return Instance._resource; } }
void Start()
{
Init();
}
void Update()
{
_input.OnUpdate();
}
static void Init()
{
if (s_instace == null)
{
GameObject obj = GameObject.Find("@Managers");
if (obj == null)
{
obj = new GameObject { name = "@Managers" };
obj.AddComponent<Managers>();
}
DontDestroyOnLoad(obj);
s_instace = obj.GetComponent<Managers>();
}
}
}
ResourceManager.cs 사용
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PrefabTest : MonoBehaviour
{
private GameObject prefab;
GameObject tank;
void Start()
{
Managers.Resource.Instantiate("Tank");
Managers.Resource.Destroy(tank);
}
}
'공부 > 인프런 - Rookiss' 카테고리의 다른 글
Part 3-4-2. Raycast, LayerMask, Tag, 투영의 개념 (0) | 2023.08.21 |
---|---|
Part 3-4-1. Collider, Collision, Trigger (0) | 2023.08.17 |
Part 3-2-1. Transform (트랜스폼), InputManager (0) | 2023.08.11 |
Part 3-1-1. 싱글톤 (0) | 2023.08.11 |
Part 3. 유니티 엔진 (0) | 2023.08.10 |