우선 Cell
클래스와 그로부터 상속받는 클래스는 NormalCell
, TargetCell
, BlockedCell
이 있다.
지난 주에 각 클래스 스크립트는 생성해두었다. Cell
이 필요할 때마다 Instance를 만들고 다 사용하면 Destroy하는 방식은 메모리 파편화, 시스템 과부하 등 많은 문제를 일으킬 수 있다고. 저번 회의 때 C가 Object Pooling에 대해 이야기해주어서 해당 부분을 적용해보기로 했다.
또한, Cell
오브젝트의 배치는 맵에 처음 들어갈 때 생성해주어야하는데, 이를 Bitmap으로부터 생성해보기로 하였다.
참고 블로그. 정말 감사합니다.
앞서 말했듯, Object가 필요해지고 필요없어질때마다 해당 Object를 생성, 삭제하는 방식은 연산에 있어 비효율적인 방식이다. 따라서, 미리 몇 개의 Object를 미리 생성해서 Pool에 넣어둔 후, 해당 Object가 필요해질 때마다 해당 Pool에서 Object를 꺼내 쓴다. 만일 해당 Object가 더 이상 필요없어진다면 다시 해당 Pool에 반환한다. 이것이 바로 Object Pooling.
직접 리스트로 구현하려고 했는데, 2021.3
버전부터 Unity에서 Object Pooling을 지원해준다고 해서 해당 패키지를 활용하였다.
ObjectPool<T0>
명세 및 사용법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와 내용을 참고할 수 있다.
Get()
: Pool에서 Object 하나를 반환받는다.Release()
: 사용한 Object를 Pool에 돌려놓는다.자세한 내용은 Doc 참고.
using UnityEngine.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); }
GameObject newCell = normalCellPool.Get();
Cell의 종류는 3가지가 있고, 이 Cell은 맵이 생성될 때 격자구조로 배치된다.
각 레벨의 종류 별로 다른 맵이 있어야할텐데, 이를 어찌 생성할까 고민하다가...
텍스트 파일로 작성하는 방법을 처음에 생각했으나, 다소 직관적이지 아닌듯하여 bitmap으로 뽑아내면 어떨까 생각해보았다. 마침 필요한 메소드들이 있어 구현할 수 있었다.
이러한 이미지 파일을 생성하였다. 각각의 색은 Cell의 종류를 구분하고, 검정색은 빈 공간.
Texture2D.GetPixel(int x, int y)
Unity Documentation
이미지 파일에서 해당 좌표에 맞는 픽셀의 Color Class를 반환해주는 함수이다.
단순히 이 파일을 읽는 것이 허가되지 않았을 때. 허가해주면 된다.
해당 Project에서 해당 Sprite를 한 번 클릭하면, Inspector창에 해당 sprite의 속성이 뜬다.
Advanced라는 toggle 메뉴를 열면, Read/Write라는 항목이 있다. 이 항목에 체크.
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);
파란 색으로 체크한 부분에 맞춰서 환경을 세팅해준다.