본문 바로가기
스파르타 내배캠

스파르타 내배캠 Unity 3기 36일차

by LemongO 2024. 2. 13.

이번 과제는 진짜...

 

 

어렵다고 느끼는건 로직을 처음 써보는거라 그렇겠지??? 익숙해지면 나아질거야...

 


PoolManager - 1

 

자동화의 두번째 PoolManager...

 

오늘은 PoolManager의 내부 클래스인 Pool을 작성해본다.

 

PoolManager는 Pooling을 사용하는 모든 오브젝트에 대한 Pool을 가지고 그 Pool들을 총괄하는 역할이다.

그리고 내부 클래스 Pool 은 각각의 오브젝트에 대한 Pool이다.

 

기본적으로 가지고있어야 하는 것에는 해당 오브젝트의 오리지널.

public GameObject Origin {  get; private set; }

 

그리고 실제 사용 시, 오브젝트가 들어있는 자료구조에서 하나씩 써야한다. 여기선 Queue를 사용.

Queue<Poolable> _poolQueue = new Queue<Poolable>();

 

Queue 에서 가지고 있는 클래스는 Poolable이다.

이 클래스는 따로 무슨 기능을 하는것은 아니고 오브젝트에

Poolable 컴포넌트가 붙어있으면 Pooling 대상이라는 일종의 증표이다.

 

또한 마구잡이로 풀링되면 하이어라키 창이 보기 안 좋으므로 Root를 가지고 있자.

public Transform Root { get; set; }

 

 

이제 Pool 에서 쓰일 함수들을 알아보자.

private Poolable Create()
{
    GameObject go = Object.Instantiate(Origin);
    go.transform.SetParent(Root);
    go.name = Origin.name;
    return go.GetOrAddComponent<Poolable>();
}

 

Poolable을 반환하는 Create 함수.

 

실제 씬에 나타날 오브젝트를 생성하는 함수이다.

쓰이는 순간은 처음 Pool 이 생성될 때, 그리고 Pooling을 통해 오브젝트를 꺼냈을 때, Queue에 남은 오브젝트가 없을 때.

 

public void Push(Poolable poolable)
{
    if (poolable == null)
        return;
    
    poolable.gameObject.SetActive(false);
    poolable.IsUsing = false;
    poolable.transform.position = new Vector3(100, 0, 0);

    _poolQueue.Enqueue(poolable);
}

 

Poolable을 받아 Queue에 보관하는 Push 함수.

 

당장 사용하지 않는 오브젝트를 보관하는 작업이기 때문에 SetActive(false) 로 비활성화를

Poolable에 IsUsing을 false로. 하지만 당장의 쓰임새는 없다.

Push가 실행되는 순간의 위치에서 다시 재사용되는 것 보단 어느 공간에 모두 모여있는게 좋아보이기 때문에

position을 100 으로 이동시킨다.

 

그리고 마지막으로 Enqueue로 보관한다.

 

 

public Poolable Pop()
{
    Poolable poolable;

    if (_poolQueue.Count > 0)
        poolable = _poolQueue.Dequeue();
    else
        poolable = Create();

    poolable.gameObject.SetActive(true);            
    poolable.IsUsing = true;

    return poolable;
}

 

보관되어있는 오브젝트를 꺼내 쓸 때 호출하는 Pop함수

 

실제 꺼내질 빈 Poolable을 하나 만들고,

Queue에 보관된 오브젝트가 1개 이상이면 Dequeue를 통해 하나 꺼내쓴다.

Queue에 보관된 오브젝트가 없다면 Create 함수를 호출해 새로 하나를 만든다.

 

보관되어있는 오브젝트는 비활성화 상태이므로 SetActive(true) 그리고 Poolable.IsUsing = true

꺼낼 준비가 되었으니 poolable을 반환한다.

 

 

그러면 Pool 에서 사용할

생성, 보관, 반출 세 가지를 모두 구현했다. Pool의 기능을 쓰기 전 처음 Pool이 생성될 때 내용물을 몇 개 만들도록하자.

 

public void Init(GameObject origin, int count)
{
    Origin = origin;
    Root = new GameObject($"{origin.name}_Root").transform;

    for (int i = 0; i < count; i++)
        Push(Create());
}

 

Pool 생성은 PoolManager 에서 하고 생성과 동시에 Init 함수를 호출해 count 개수만큼 오브젝트를 생성, 보관 한다.

처음 만들어지는 풀의 Root는 하이어라키 상에 없을테니 new GameObject를 통해 새로 만들어 Root에 할당한다.

 

 

그렇게 만들어진 Pool 내부 클래스의 전체코드는 다음과 같다.

class Pool
{
    public GameObject Origin {  get; private set; }
    public Transform Root { get; set; }

    Queue<Poolable> _poolQueue = new Queue<Poolable>();

    public void Init(GameObject origin, int count)
    {
        Origin = origin;
        Root = new GameObject($"{origin.name}_Root").transform;

        for (int i = 0; i < count; i++)
            Push(Create());
    }

    private Poolable Create()
    {
        GameObject go = Object.Instantiate(Origin);
        go.transform.SetParent(Root);
        go.name = Origin.name;
        return go.GetOrAddComponent<Poolable>();
    }

    public void Push(Poolable poolable)
    {
        if (poolable == null)
            return;
        
        poolable.gameObject.SetActive(false);
        poolable.IsUsing = false;
        poolable.transform.position = new Vector3(100, 0, 0);

        _poolQueue.Enqueue(poolable);
    }

    public Poolable Pop()
    {
        Poolable poolable;

        if (_poolQueue.Count > 0)
            poolable = _poolQueue.Dequeue();
        else
            poolable = Create();

        poolable.gameObject.SetActive(true);            
        poolable.IsUsing = true;

        return poolable;
    }
}