나 개발자 진짜 되냐?

[ Unity 뱀서라이크 게임을 만들어보자 8 ] 오브젝트 풀이란 무엇인가 본문

유니티를 공부해봐요!/초급이에요!

[ Unity 뱀서라이크 게임을 만들어보자 8 ] 오브젝트 풀이란 무엇인가

Snow Rabbit 2024. 10. 11. 01:50

 

자, 지금까지 구현한 내용으로

우리는 움직이면서

화려하게 화살도 쓩쓩 쏜다.

 

하다보니..화살이 너무 많아서

문제가 되었다.

 

그래서 우리는 오브젝트 풀이라는 친구와 함께

이 화살을 어떻게 처리할지 공부해 보자!

 

고고!


오브젝트 풀이란

게임 개발에 널리 사용되는 테크닉으로,

게임의 성능을 개선하기 위해 사용된다.

 

보통 이제 생성과 소멸이 잦은 친구들이 있다.

뭐 화살, 몬스터 등등

이런 친구들이 소멸되면 쓰레기통으로 가는데

너어어어무 많이 쌓이면

그 쓰레기통도 한계가 오기 때문에

 

오브젝트 풀링은

생성(Instantiate)소멸(Destroy)이라는

비용이 큰 작업을 최소화함으로써 성능을 향상하는 데 중요한 역할을 해준다.

 

이런 객체들을

풀에 저장해 놓고 재사용함으로써

메모리 할당과 가비지 컬렉션에 따른 성능 저하를 방지!!

 

성능개선에는 최고인데

불필요한 메모리 사용이 될 때도 있기 때문에

적절히 조절하는 것이 중요!

 

우리한테.. 는 화살이 엄청 많다

 

너무 많으니 지워야 하는데

우리는 이 오브젝트 풀 + Queue를 이용해서

야무지게 지워볼 예정이다.

 

먼저

ObjectPool이라는 클래스 생성!,

pool이라는 클래스도 있는데

이 안에서 잠시 사용할 거라 그냥

이안에 클래스 생성!

 

using System.Collections.Generic;
using UnityEngine;

public class ObjectPool : MonoBehaviour
{
    // 오브젝트 풀 데이터를 정의할 데이터 모음 정의
    [System.Serializable]
    public class Pool // 내부적으로 쓰다 말거기 때문에 여기 안에 클래스 하나 정의
    {
        public string tag;
        public GameObject prefab; // 어떤 프리펩이여?
        public int size; //프리펩 몇개 생성할지
    }

    public List<Pool> Pools; // 기본적으로 직렬화가 되어서 안써줘도 된다.
    public Dictionary<string, Queue<GameObject>> PoolDictionary; // 이녀석은 직렬화가 안된다.

    private void Awake()
    {
        // 인스펙터창의 Pools를 바탕으로 오브젝트풀을 만들 것. 
        // 오브젝트풀은 오브젝트마다 따로이며, pool개수를 넘어가면 강제로 끄고 새로운 오브젝트에게 할당.
        PoolDictionary = new Dictionary<string, Queue<GameObject>>(); // 초기화 한번 해주기.
        foreach (var pool in Pools)// 풀에 있는 모든거 한번씩 거치면서
        {
            // 큐는 FIFO(First-in First-out) 구조로서, 줄을 서는 것처럼 가장 오래 줄 선(enqueue) 객체가 가장 먼저 빠져 나올(dequeue) 수 있는 구조
            Queue<GameObject> objectPool = new Queue<GameObject>(); // 큐 생성
            for (int i = 0; i < pool.size; i++) // 큐 사이즈 만큼 
            {
                // Awake하는 순간 오브젝트풀에 들어갈 Instantitate 일어나기 때문에 터무니없는 사이즈 조심
                GameObject obj = Instantiate(pool.prefab); // 새로 만들어준다! Instantiate는 복사한다는 의미
                obj.SetActive(false);
                // 줄의 가장 마지막에 세움.
                objectPool.Enqueue(obj); // 그 값을 큐에 넣는다.
            }
            // 접근이 편한 Dictionary에 등록
            PoolDictionary.Add(pool.tag, objectPool);
        }
    }

    public GameObject SpawnFromPool(string tag)
    {
        // 애초에 Pool이 존재하지 않는 경우
        if (!PoolDictionary.ContainsKey(tag))
            return null;

        // 제일 오래된 객체를 재활용
        GameObject obj = PoolDictionary[tag].Dequeue(); //제일 앞에 있는애 빼기
        PoolDictionary[tag].Enqueue(obj); //그리고 그친구를 다시 맨뒤에 넣기 뫼비우스 느낌
        obj.SetActive(true);
        return obj;
    }
}

 

자,

 보면

 

우리는 오브젝트의 이름에 따라서

리스트 pool로 저장할 건데

그것을 찾기 편하게

딕셔너리로 찾는다.

그래서 이런 식이 나온다. 15번째 줄

PoolDictionary = new Dictionary <string, Queue <GameObject>>(); 

 

Queue라는 친구인데

선입선출 친구이다.

 

먼저 들어온 애가 먼저 나간다.

그래서 Enqueue로 새 친구를 제일 뒤에 넣어주고

Dequeue로 맨 앞에 애를 빼준다.

 

❗❗❗❗주석을 읽어보면 편하다❗❗❗❗

 

자,

유니티로 와서

우리는 게임 매니저라는 빈 오브젝트를 만들고

오브젝트 풀을 실행해 보자

 

 

이렇게 설정!

풀에다가 1을 해주면 밑에 역삼각형이 생긴다.

그 부분을 눌러서 

값을 넣어주면 되고

프리펩은 

찾아서 드래그 드롭 해주는 거 잊지 말자!

 

이렇게 해주면 우리는 생성까진 완료 됐다.

이제 화살 20개는 만들어졌는데..

큐의 움직임이 없다

 

그 부분은 우리가

TopDownShooting.cs에서 만져줘야 한다.

 

 

먼저 pool친구 데려오고

일단 당장 코드를 움직이게 하기 위해 find를 사용한다.

 

다음에 우리가 중요하게 만져야 할 곳은 

 

 

지금은 testPrefab으로 해놔서 그런 것!

우리가 풀로 만든 친구로 수정해 보자!

한 줄이었다. 참 쓰는 건 쉽다.

이해가 어렵지

 

 간단하게 말하면

풀에만 들어둔 함수 Spawn 이 친구를 해줄 건데

RangedAttack에 있는 bulletNameTag를 보고

뭐 무기면 실행하고 아님 말고 를 할 수 있게 하는 것이다!

 

이렇게 하면 

 

삭제가 아니라

이렇게 20개 가지고 

썼다 뺐다 썼다 뺐다 할 수 있게 된다.