Prefab이란?

자주 쓰이는 GameObject를 재사용하기 위해 Asset화 한 것이다. 


사용처

정말 많다. 총알/화살과 같은 Projectile, Hit/Death 효과를 책임지는 Particle, 심지어 Enemy나 Player도 Prefab화의 대상이다. Scene Template에도 사용된다.


Prefab Override

Instance(원본 Prefab으로부터 Scene에 Instance된 GameObject)를 수정한 경우:

  • 이 행위 자체는 원본 Prefab에 영향을 미칠 수 없다.
  • 원본 Prefab과의 변경점이 Override되어 저장된다. (Override된 Instance!)
  • Apply와 Revert 옵션이 활성화된다;
    (Apply : Instance로 원본 Prefab을 덮어씌움 / Revert : 원본 Prefab으로 Instance를 덮어씌움)
  • 이런 식으로 Apply나 Revert를 한 경우, "원본 Prefab"과 "Instance"의 차이는 고려되지 않는다. 그냥 그대로 덮어씌워버린다.

원본 Prefab을 수정한 경우:

  • Instance가 Override되지 않은 경우, 원본 Prefab으로 Instance를 덮어씌운다.
  • Instance가 Override된 경우, 수정된 부분을 확인한다;
    >> 만일 수정된 부분이 같다면, 원본 Prefab에서 수정한 부분이 Instance에 적용되지 않는다. (예시 : Instance Override를 scale.x를 1 -> 2로 바꿈으로써 했다. 원본 Prefab에선 scale.x를 1 -> 6으로 바꿨다. GIT CONFLICT!)
    >> 만일 수정된 부분이 다르다면, 원본 Prefab에서 수정한 부분이 Instance에 적용된다.
  • 참고로 원본 Prefab을 수정할 땐 Auto Save를 끄고 작업하는 것이 좋다. Instance와는 다르게 Apply나 Revert 옵션을 선택하는 과정이 존재하지 않으므로...

Scene Template과의 연계

Scene Template의 옵션에서, 지정한 Assets를 Clone 할 것인지 Reference 할 것인지 선택할 수 있다. 이때, Prefab의 경우 무조건 Reference로 하는 것이 좋다. 어짜피 Instance에는 Override 기능이 있어서 Tilemap과 같이 각 Scene(Stage)마다 배치가 달라지는 경우에도 Prefab을 충분히 사용할 수 있다. 


읽어주셔서 감사합니다!

궁금한 점이 있다면 댓글로 문의주세요!

Singleton Pattern이란?

하나의 Scene에 "반드시" 하나의 Object만 존재하도록 강제하는 디자인 패턴이다. 


사용처

주로 Manager 계열의 Object에 사용된다.

 

이유 : 대부분의 경우 이러한 Object는 모든 Scene에 사용된다. 그러나 매번 넣어주기도 귀찮고, 실수할 가능성도 있다. 또한 Scene Template을 사용하더라도, 무조건 사용되는 Object들이 매번 Hierarchy 창을 차지한다면, 각각의 Scene을 편집하는 데 있어 상당한 방해가 된다.


사용법

대체로 Main Menu와 같은, "무조건 맞닥뜨리게 되는(=index가 0인 Scene)"에 Game, Data, Audio Manager Object를 배치한다. 그 후, 그것들을 DontDestroyOnLoad 목록에 등록하여 재사용한다.


Skeleton Code - Game Manager

using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameObject game_manager;

    private void Awake()
    {
    	SingletonCheck();
    }
    
    private void SingletonCheck()
    {
    	if (game_manager == null)
        {
            game_manager = gameObject;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
    
    private void Start()
    {
    	// 처음 로드됐을 시에만 "단 한 번" 실행하고 싶은 것들을 여기에.
    }
}

문제점

DontDestroyOnLoad를 사용하기 때문에, Start()가 단 한 번밖에 실행되지 않는다. (그러니까, Main Menu Scene을 10번 Load하더라도 Game Manager의 Start()는 단 한 번만 호출된다!) 따라서 "Scene이 Load되는 타이밍"에 "매번" 실행하고 싶은 메서드가 있다면, Delegate를 사용해야 한다.


해결책

using UnityEngine;
using UnityEngine.SceneManagement;

public class GameManager : MonoBehaviour
{
    public static GameObject game_manager;

    private void Awake()
    {
    	SingletonCheck();
    }
    
    private void SingletonCheck()
    {
    	if (game_manager == null)
        {
            game_manager = gameObject;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
    
    private void Start()
    {
        SceneManager.sceneLoaded += OnSceneLoaded;
    }
    
    private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
        if (scene.name == "Main Menu")
        {
            // Main Menu Scene이 Load됐을 때만 하고 싶은 것을 적으면 됨.
            return;
        }
        if (scene.name == "Shop")
        {
            // Shop Scene이 Load됐을 때만 하고 싶은 것을 적으면 됨. 등등...
            return;
        }
    }
}

읽어주셔서 감사합니다!

궁금한 점이 있다면 댓글로 문의주세요!

+ Recent posts