본문 바로가기

Unity

Unity - 오브젝트풀(ObjectPool Pattern) 구현하기 (심화) - DontDestroyOnLoad

오브젝트풀 대해 기본적구현을 모른다면 아래를 확인

 

https://malbongcode.tistory.com/38

 

Unity2D - 오브젝트풀(ObjectPool Pattern) 구현하기 (일반)

오브젝트풀(ObjectPool)이란? 위에서 설명하는 것 처럼 생성 디자인 패턴임 생성된 오브젝트의 집합을 사용하는 것임 필요할 때 마다 생성하고 파괴하기보다는 미리 생성해놓고 사용하는 것임 또한 계속 생성(Ins..

malbongcode.tistory.com

 

 

이번엔 오브젝트풀에 대한 조금 다른과정을 살펴보려 함

오브젝트 풀을 DontDestroyOnLoad 하는 것을 보려 함

 

Scene이 몇개 없는 상태에서 Scene의 전환이 빈번할 때 ex. 메뉴씬과 게임씬만 있는 경우

게임 Scene에서 오브젝트풀을 생성하고 메뉴 Scene에서 오브젝트풀을 파괴하면

오브젝트 풀을 이용하는 것에 의미가 없음

 

그래서 게임Scene에 들어가면 오브젝트풀을 한번만 생성하고 그 이후 메뉴씬을 가거나 게임씬을 다시 로드할 경우에

오브젝트 풀을 생성하지 않고 있는것을 다시 쓰는 코드를 보려 함

 

키워드는 DontDestroyOnLoad 함수임

 

 

 

구현방법

1) DontDestroyOnLoad 함수로 ObjectPool의 instance를 넣음

2) ObjectPool의 instance뿐만아니라 개별Pool도 파괴되지 않아야 하므로 static으로 만듬

-> 만들필요 없음 -> DontDestroyOnLoad로 메모리에 클래스변수가 살아있음을 명심

3) 개별 Object도 파괴되지 않아야 하므로 DontDestroyOnLoad에 넣음

4) 다른 씬으로 로드되거나 다시 시작되면 모든 풀의 활성화를 꺼줌 (Reset())

 

 

 

 

 

구현

1) DontDestroyOnLoad 함수로 ObjectPool의 instance를 넣음

 

2) ObjectPool의 instance뿐만아니라 개별Pool도 파괴되지 않아야 하므로 static으로 만듬

-> 만들필요 없음 -> DontDestroyOnLoad로 메모리에 클래스변수가 살아있음을 명심

 

3) 개별 Object도 파괴되지 않아야 하므로 DontDestroyOnLoad에 넣음

 

 

4) 다른 씬으로 로드되거나 다시 시작되면 모든 풀의 활성화를 꺼줌 

-> Scene 체크 + 한번만 Reset() 진행

 

 

 

결과

 

 

 

 

전체코드

씬을 로드하는 거나 오브젝트풀에서 가져와 오브젝트를 사용하는 코드는 여기서 다루지 않음

전적으로 ObjectPooler의 스크립트임

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
 
public class ObjectPooler : MonoBehaviour
{
    public bool more = true;
    public static ObjectPooler instance;
 
    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(instance);
            CreateBullet(); // start instantiate bullet...
        }
        else if(instance != this)
        {
            Destroy(this.gameObject);
        }
    }
 
 
    private bool isMenuSceneReset = false;
    private bool isGameSceneReset = false;
    private void Update()
    {
        string sceneName = SceneManager.GetActiveScene().name;
        if (sceneName == "Menu")
        {
            if (!isMenuSceneReset) // only a call OnReset()
            {
                OnReset();
                isGameSceneReset = false;
                isMenuSceneReset = true;
            }
        }
        else if (sceneName == "Game")
        {
            if (!isGameSceneReset) // only a call OnReset()
            {
                OnReset();
                isGameSceneReset = true;
                isMenuSceneReset = false;
            }
        }
    }
 
 
    public void OnReset()
    {
        foreach (GameObject obj in bulletPool)
        {
            obj.SetActive(false);
        }
    }
 
 
    public GameObject bullet;
    private List<GameObject> bulletPool;
    public int bulletCreateCount;
    private void CreateBullet()
    {
        bulletPool = new List<GameObject>();
        for (int i = 0; i < bulletCreateCount; i++)
        {
            GameObject obj = Instantiate(bullet);
            obj.SetActive(false);
            bulletPool.Add(obj);
            DontDestroyOnLoad(obj);
        }
    }
 
 
    public GameObject GetBullet()
    {
        foreach (GameObject obj in bulletPool)
        {
            if (!obj.activeInHierarchy) { return obj; }
        }
 
        //오브젝트가 모두 활성화일 때
        if (more)
        {
            GameObject obj = Instantiate(bullet);
            obj.SetActive(false);
            bulletPool.Add(obj);
            DontDestroyOnLoad(obj);
            return obj;
        }
        else
        {
            return null;
        }
    }
}
 
cs