이번 프로젝트의 중요 부분 중 하나인 랜덤 맵생성 부분에서 랜덤 맵의 구성요소인 타일맵 오브젝트 프리팹들을 인스탄시에이트 하는 과정에서 문제가 발생하였다.
유니티 에디터 단에서는 문제 없이 정상적으로 프리팹들이 생성되었지만 막상 휴대폰에서 빌드하여 사용해보니 문제가 발생하였다.
해당 부분에서 어떠한 이유에서인지 (찾아봐도 나오질 않는다...) 인스탄시에이트 하는 부분에서 문제가 계속 발생하였다.
여기서 생각난 한가지가 우리 프로젝트의 경우 타일맵의 전체 크기만 유지된다면 굳이 타일맵 컴포넌트를 달고 있는 객체일 필요도 없고 ( 물론 타일맵 콜라이더를 쓰고 있다면 다른 얘기이지만 그것도 파회법이 있다)
그리드를 달고 있을 필요도 없었다.
오직 필요한건 딱 하나! 타일맵 구성 별 하나의 통짜 이미지!
선생님의 조언에 따라 Cmera.Main.Render(); 메서드를 이용하여 PNG 이미지로 추출이 가능하다는 걸 알게 되었다.
그래서 만들어본 타일맵 오브젝트 PNG 추출기 (이름 생각해봐야겠다)를 제작하게 되었다.
사용 방법은 간단하다. 우선 코드를 보고 가자
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.IO;
using UnityEngine.Tilemaps;
public class TilemapToSprite : MonoBehaviour
{
[SerializeField]
private GameObject TargetObj; // 타겟 오브젝트
private List<Tilemap> tilemapList; // 추출할 타일맵 오브젝트
public int pixelPerUnit = 100; // 스프라이트 픽셀당 단위 크기
private void ExtrackTileMapObject()
{
this.DisableChildrenWithoutTilemap(this.TargetObj.transform);
this.tilemapList = this.TargetObj.GetComponentsInChildren<Tilemap>().ToList<Tilemap>();
this.MakePNG();
}
void MakePNG()
{
this.tilemapList.ForEach(tilemap => { tilemap.gameObject.SetActive(false);});
Debug.Log("Start");
for (int i = 0; i < tilemapList.Count; i++)
{
this.RefreshComponent();
this.tilemapList[i].gameObject.SetActive(true);
// 타일맵 크기 구하기
Vector3Int size = this.tilemapList[i].cellBounds.size;
// 렌더 텍스쳐 생성
RenderTexture renderTexture = new RenderTexture(size.x * this.pixelPerUnit, size.y * this.pixelPerUnit, 32);
// 타일맵 렌더러 생성
TilemapRenderer tilemapRenderer = this.gameObject.AddComponent<TilemapRenderer>();
tilemapRenderer.sortOrder = TilemapRenderer.SortOrder.TopRight;
tilemapRenderer.mode = TilemapRenderer.Mode.Individual;
tilemapRenderer.sortingLayerName = "Default"; // 타일맵 렌더링 순서 지정
Tilemap tilemapComponent = tilemapRenderer.GetComponent<Tilemap>();
tilemapComponent.ClearAllTiles();
foreach (var pos in this.tilemapList[i].cellBounds.allPositionsWithin)
{
Vector3Int localPlace = new Vector3Int(pos.x, pos.y, pos.z);
if (!this.tilemapList[i].HasTile(localPlace)) continue;
Vector3 place = this.tilemapList[i].CellToWorld(localPlace);
tilemapComponent.SetTile(localPlace, this.tilemapList[i].GetTile(localPlace));
}
// 렌더 텍스쳐에 렌더링
tilemapComponent.RefreshAllTiles();
Camera camera = Camera.main;
camera.targetTexture = renderTexture;
camera.orthographicSize = Mathf.Max(size.x, size.y) / 2f;
camera.aspect = (float)size.x / size.y;
camera.Render();
camera.targetTexture = null;
// 스프라이트 생성
Texture2D texture = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false);
RenderTexture.active = renderTexture;
texture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
texture.Apply();
RenderTexture.active = null;
Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), this.pixelPerUnit);
byte[] bytes = texture.EncodeToPNG();
string filePath = Application.dataPath + string.Format("/{0}.png", this.tilemapList[i].gameObject.name);
File.WriteAllBytes(filePath, bytes);
this.tilemapList[i].gameObject.SetActive(false);
}
Debug.Log("End");
}
private void DisableChildrenWithoutTilemap(Transform parent)
{
foreach (Transform child in parent)
{
// 만약 자식 오브젝트에 Tilemap 컴포넌트가 없다면 SetActive(false) 실행
if (child.GetComponent<Tilemap>() == null)
{
child.gameObject.SetActive(false);
}
// 자식 오브젝트의 하위 자식들도 검사하기 위해 재귀적으로 실행
this.DisableChildrenWithoutTilemap(child);
}
}
private void RefreshComponent()
{
DestroyImmediate(this.GetComponent<TilemapRenderer>());
DestroyImmediate(this.GetComponent<Tilemap>());
}
public void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
this.ExtrackTileMapObject();
}
}
}
1. 스크립트를 빈 오브젝트에 부착시킨다.
2. 추출을 원하는 오브젝트를 하이어라키 창에 가져온뒤 TargetObj 에 할당한다
2. 재생버튼을 누른다
3. 메인 카메라를 추출을 원하는 오브젝트의 중앙에 둔다 (굳이 정확하게 중앙일 필요는 없고 적당히 카메라 안에 오브젝트가 들어오록 하면 된다.
4. 이후 스페이스바를 누른다 (키는 원하는 키로 바꾸어도 된다 - * UI 추출 버튼을 만들어야 겠다.)
5. 추출 완료되면 Asset 폴더 안에 타일맵 레이어 별로 추출한 PNG 이미지가 추가된다.
6. 자신이 만든 타일맵 레이어 만큼 2D 이미지 객체를 만들어 스프라이트 컴포넌트에 이미지를 할당하고 동일하게 레이어를 설정하면 기존 타일맵 오브젝트와 동일한 사이즈의 PNG 스프라이트 이미지 객체를 얻을수있다!!!
*이미지 열화도 없다.
여기서 추출할때 정확하게 Tilemap 컴포넌트가 있는 객체들의 이미지 만을 추출하기 때문에 기타 잡다한 오브젝트(타일맵이 없는 객체들) 이 있다 하더라도 문제 없이 추출할수 있다.
주의할점은 한가지 인데 추출대상 외에 카메라 범위 혹은 근처에 (타일맵 사이즈가 클지 작을지는 모르니 ) 다른 객체가 보이면 안된다는 것 정도인데 이것도 아마 추출해보면 아! 할것이다 ㅎㅎ
이렇게 타일맵을 미리 추출하여 사용하면 생기는 장점은 메모리 부담을 덜수 있다는 장점이 생긴다.
(단점은 귀찮은 작업이 추가된다는 것 정도)
여기서 아까 얘기한 타일맵 콜라이더를 대체 하기 위한 꼼수는 아래처럼 해볼수 있다.
1. 아래와 같이 타일맵을 찍을때 콜라이더가 필요한 부분을 채워준다 (가능하면 검은색 박스가 좋다)
2. 이후 폴리곤 콜라이더 컴포넌트를 부착시킨다.
그럼 이런식으로 기존 타일맵 콜라이더와 비슷한 느낌의 콜라이더를 가져갈수 있게된다.
'프로젝트 > 건즈앤 레이첼스' 카테고리의 다른 글
[유니티 프로젝트] DOTween을 이용한 팝업 UI 애니메이션 (0) | 2023.05.01 |
---|---|
[유니티 프로젝트] 유저 가이드 화살표 ( 포탈 화살표 ) 제작 (0) | 2023.04.30 |
[유니티 프로젝트] 타이틀 씬 to 던전 씬 까지 (1) | 2023.04.26 |
[유니티 프로젝트] 허브 (성소) -> 던전 -> 허브 루프 (윤회) (1) | 2023.04.23 |
[유니티 프로젝트] 본 프로젝트용 맵 씬 제작 (0) | 2023.04.20 |