[Unity 2D] 나노봇 개발일지 : Object Pooling, Bitmap으로부터 맵 생성

thoho·2023년 2월 5일
0
post-thumbnail

구현 내용 요약

우선 Cell 클래스와 그로부터 상속받는 클래스는 NormalCell, TargetCell, BlockedCell이 있다.
지난 주에 각 클래스 스크립트는 생성해두었다. Cell이 필요할 때마다 Instance를 만들고 다 사용하면 Destroy하는 방식은 메모리 파편화, 시스템 과부하 등 많은 문제를 일으킬 수 있다고. 저번 회의 때 C가 Object Pooling에 대해 이야기해주어서 해당 부분을 적용해보기로 했다.

또한, Cell 오브젝트의 배치는 맵에 처음 들어갈 때 생성해주어야하는데, 이를 Bitmap으로부터 생성해보기로 하였다.

Object Pooling

참고 블로그. 정말 감사합니다.

개념

앞서 말했듯, Object가 필요해지고 필요없어질때마다 해당 Object를 생성, 삭제하는 방식은 연산에 있어 비효율적인 방식이다. 따라서, 미리 몇 개의 Object를 미리 생성해서 Pool에 넣어둔 후, 해당 Object가 필요해질 때마다 해당 Pool에서 Object를 꺼내 쓴다. 만일 해당 Object가 더 이상 필요없어진다면 다시 해당 Pool에 반환한다. 이것이 바로 Object Pooling.

직접 리스트로 구현하려고 했는데, 2021.3버전부터 Unity에서 Object Pooling을 지원해준다고 해서 해당 패키지를 활용하였다.

ObjectPool<T0> 명세 및 사용법

Unity Documentation

Contructor

Unity Documentation

public ObjectPool<T0>(
	Func<T> createFunc, // pool에 release할 오브젝트가 없을 때 오브젝트를 생성
    Action<T> actionOnGet, // pool에서 오브젝트를 Get
    Action<T> actionOnRelease, // 더 이상 사용하지 않는 오브젝트를 Release
    Action<T> actionOnDestroy, // 오브젝트를 Destroy
    bool collectionCheck, // pool에 돌려보내는 요청이 유효한지 확인
    int defaultCapacity, // 기본 크기. pool 생성시 해당 양의 object가 함께 생성됨
    int maxSize // pool의 최대 용량
);

Doc을 보면 예시가 나와있는데, ObjectPool이 포함해야하는 함수, 액션이 포함해야하는 parameter와 내용을 참고할 수 있다.

Method

Unity Documentation

  • Get() : Pool에서 Object 하나를 반환받는다.
  • Release() : 사용한 Object를 Pool에 돌려놓는다.

자세한 내용은 Doc 참고.

Import

using UnityEngine.Pool;

Object Pool 생성

void Start(){
	normalCellPool = new ObjectPool<GameObject>(CreateNormalCell, OnGet, OnRelease, OnDestroyCell, maxSize: 30);
}

// func, Action 정의
private GameObject CreateNormalCell()
{
    GameObject normalCell = Instantiate(normalCellPrefab);
    normalCell.GetComponent<NormalCell>().SetPool(normalCellPool);
    normalCell.transform.parent = this.transform;
    return normalCell;
}
private void OnGet(GameObject cell) { cell.SetActive(true); }
private void OnRelease(GameObject cell) { cell.SetActive(false); }
private void OnDestroyCell(GameObject cell) { Destroy(cell); }

Pool로부터 Object 반환받기

GameObject newCell = normalCellPool.Get();

Bitmap으로부터 Cell 배치 생성하기

Cell의 종류는 3가지가 있고, 이 Cell은 맵이 생성될 때 격자구조로 배치된다.
각 레벨의 종류 별로 다른 맵이 있어야할텐데, 이를 어찌 생성할까 고민하다가...
텍스트 파일로 작성하는 방법을 처음에 생각했으나, 다소 직관적이지 아닌듯하여 bitmap으로 뽑아내면 어떨까 생각해보았다. 마침 필요한 메소드들이 있어 구현할 수 있었다.

이러한 이미지 파일을 생성하였다. 각각의 색은 Cell의 종류를 구분하고, 검정색은 빈 공간.

Texture2D.GetPixel(int x, int y)

Unity Documentation
이미지 파일에서 해당 좌표에 맞는 픽셀의 Color Class를 반환해주는 함수이다.

❗ Sprite 파일을 Read 할 수 없을때

단순히 이 파일을 읽는 것이 허가되지 않았을 때. 허가해주면 된다.
해당 Project에서 해당 Sprite를 한 번 클릭하면, Inspector창에 해당 sprite의 속성이 뜬다.

Advanced라는 toggle 메뉴를 열면, Read/Write라는 항목이 있다. 이 항목에 체크.

픽셀의 정보를 읽어와 해당 좌표에 Cell 생성

for (int i = 0; i < CellMapHeight; i++)
{
    for (int j = 0; j < CellMapWidth; j++)
    {
        Color color = map.GetPixel(j, i);
        if (color == normalCell)
        {
            GameObject newCell = normalCellPool.Get();
            newCell.GetComponent<NormalCell>().Move(i, j);
            // ㄴ Cell 클래스 구현 함수. 인덱스 i, j를 y, x로 변환해준다.
        }
    }
}

❗ 어..? 너 방향이 이상하다?

인덱스와 좌표를 절대 헷갈리지 마시오...😭
GetPixel(int x, int y)인데, 위처럼 반복문을 돌리려면 GetPixel(j, i)로 써야하지만 GetPixel(i, j)로 써서 한참 헤맸다. 어떻게 이런 실수를...

아무튼 이렇게 해서 완료. 나중에 더 다듬어야하지만 기본적인 구현은 완료!


화면 해상도 고정

참고 블로그. 감사합니다!

화면 비율을 고정할 필요가 있을 것 같아, 1920*1080으로 고정하기로.
비어있는 Object를 생성한 후, 스크립트를 작성한다. Awake에 작성함.

Screen.SetResolution(1920, 1080, true);


파란 색으로 체크한 부분에 맞춰서 환경을 세팅해준다.

profile
어떻게든 굴러가고 있는

0개의 댓글