쾌락없는 책임 (공부)/Unity

유니티 2D 아이템 드랍 오브젝트 폴링으로 구현하기

허스크 2021. 5. 8. 20:57
반응형

오브젝트 폴링

 몬스터가 아이템 드롭을 하는걸 계속 Instantiate로 생성을 하고 플레이어가 먹으면 Destroy를 하는데 이게 너무 지속되면 GC가 호출될 때 프레임이 튀는 경우가 있어 이걸 방지하기 위해 미리 오브젝트를 만들고 위치 변경만 해서 마치 '생성하는 것처럼 보이게'하는 메모리 관리 기법입니다.

 운영체제 강의들을 봤을 때 메모리 단편화에 대한 관리도 골치아프니 오브젝트 폴링을 해서 메모리 관리를 하는게 공간적으로나 시간적으로나 큰 이득을 볼 수 있습니다. 그래서 이번에 리스트를 이용해 간단한 오브젝트 폴링을 만들어 봤습니다.

 

소스코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ItemDropManager : MonoBehaviour{
    public static ItemDropManager Instance;
    [SerializeField]
    private GameObject itemPrefab;
    //private Queue<PickUpItem> dropItemPool = new Queue<PickUpItem>();
    private List<PickUpItem> itemPool = new List<PickUpItem>();
    int rand;

    private void Awake(){
        Instance = this;
        Init(5);
    }

    private PickUpItem Create(){
        var obj = Instantiate(itemPrefab).GetComponent<PickUpItem>();
        obj.gameObject.SetActive(false);
        obj.transform.SetParent(transform);
        return obj;
    }

    private void Init(int count){
        for(int i = 0; i < count; i++){
            itemPool.Add(Create());
        }
    }

    public static PickUpItem GetItem(){
        int rand = Random.Range(0, Instance.itemPool.Count);
        var obj = Instance.itemPool[rand];
        Instance.itemPool.RemoveAt(rand);
        obj.transform.SetParent(null);
        obj.gameObject.SetActive(true);
        return obj;
    }

    public static void ReturnItem(PickUpItem item){
        item.gameObject.SetActive(false);
        item.transform.SetParent(Instance.transform);
        Instance.itemPool.Add(item);
    }
}

 유튜브에 있는 폴링은 대부분 슈팅 게임을 가정하고 큐를 사용하는데 큐를 사용하게 되면 아이템들이 정해진 순서대로 나가 랜덤성이 떨어진다고 생각하고 리스트와 랜덤을 이용해서 제작을 했습니다.

    public static PickUpItem GetItem(){
        int rand = Random.Range(0, Instance.itemPool.Count);
        var obj = Instance.itemPool[rand];
        Instance.itemPool.RemoveAt(rand);
        obj.transform.SetParent(null);
        obj.gameObject.SetActive(true);
        return obj;
    }

    public static void ReturnItem(PickUpItem item){
        item.gameObject.SetActive(false);
        item.transform.SetParent(Instance.transform);
        Instance.itemPool.Add(item);
    }

 사실상 여기서 핵심인 내용인데 Random.Range를 통해서 리스트의 랜덤한 인덱스에서 아이템을 가져오고 RemoveAt을 통해서 중복없이 아이템을 가져갈 수 있게 했습니다. 따지자면 아이작의 아이템들과 비슷한 느낌입니다.

 또한 플레이어가 필드에서 아이템을 먹으면 Ui로만 표시되고 필드의 아이템은 사라져야 합니다. 이때 ReturnItem 함수를 호출해 아이템을 다시 오브젝트풀로 데리고 와서 없어진 것처럼 처리를 해줍니다.

 

더 생각해볼점

현재는 Init과 Create를 통해서 아이템을 생성하고 있으며 보면 같은 아이템만 생성하고 있습니다. 때문에 아이작같은 아이템이 많은 게임에서는 아이템들의 정보를 불러올 수 있는 방법들이 필요합니다.

반응형