[Unity UI] 별도 이미지 없이 미니맵과 저격 조준경 만들기
OUTPOST는 FPS 좀비 디펜스 게임입니다. 체력·무기·적 위치를 보여주는 UI가 필요한데, 작은 아이콘마다 이미지 파일을 준비하기보다는 Unity 코드에서 직접 형태를 그리는 방법을 사용했습니다.
1. UI 이미지를 직접 그릴 수 있을까?
Unity의 UI는 꼭 PNG 파일로 만들어야 하는 것은 아닙니다. MaskableGraphic을 상속하면 OnPopulateMesh()에서 VertexHelper를 사용해 사각형, 삼각형 등의 정점을 직접 생성할 수 있습니다.
이 방식을 이용해 HUDIconGraphic에서는 탄창·체력·소총·저격총·권총 모양을, MinimapGraphic에서는 지도 테두리와 위치 마커를 그립니다.
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
Rect r = rectTransform.rect;
if (drawBackground)
AddQuad(vh, r, new Color(0.055f, 0.065f, 0.04f, 0.90f));
AddBorder(vh, r, 4f, new Color(0.88f, 0.64f, 0.22f, 0.98f));
// 아래에서 목표, 좀비, 플레이어 마커를 순서대로 추가
}
VertexHelper는 UI에 표시할 정점과 삼각형 정보를 모으는 역할을 합니다. 이미지 리소스 대신 코드에서 도형을 정의하기 때문에 마커의 크기나 색을 바로 바꿀 수 있습니다.
2. 월드 좌표를 미니맵 좌표로 변환하기
미니맵에서 캐릭터의 위치를 나타내려면 Transform.position을 그대로 사용할 수 없습니다. 게임의 월드 좌표 범위와 UI 사각형의 크기가 다르기 때문입니다.
float x = Mathf.InverseLerp(worldBounds.xMin,
worldBounds.xMax, world.x);
float y = Mathf.InverseLerp(worldBounds.yMin,
worldBounds.yMax, world.z);
return new Vector2(
Mathf.Lerp(local.xMin + 10f, local.xMax - 10f, x),
Mathf.Lerp(local.yMin + 10f, local.yMax - 10f, y));
InverseLerp()는 월드 좌표를 0~1 범위의 비율로 바꾸고, Lerp()는 그 비율을 UI 좌표로 다시 변환합니다. 지면이 XZ 평면이기 때문에 미니맵의 세로 방향에는 월드의 z값을 사용했습니다.
적 위치는 ZombieAI.ActiveZombies에서 가져오고, 플레이어·발전기·탈출 목표는 각각 다른 색과 크기로 표시합니다. 적 목록은 지정된 간격마다 갱신하지만, 정점은 SetVerticesDirty()를 통해 화면 갱신 시 다시 구성합니다. 따라서 드로우콜이나 CPU 비용이 항상 낮다고 단정할 수는 없습니다.
3. 저격 조준경은 어떻게 만들었을까?
SniperScopeGraphic은 미니맵과 달리 Image를 상속하고, 실행 중 Texture2D를 만들어 사용합니다. 화면 비율을 기준으로 텍스처 크기를 정한 다음, 각 픽셀의 중심에서 거리를 구합니다.
float distance = Mathf.Sqrt(dx * dx + dy * dy);
bool outside = distance >= radius;
bool ring = distance >= radius - line;
bool vertical = Mathf.Abs(dx) <= line * 0.5f &&
Mathf.Abs(dy) >= gap && Mathf.Abs(dy) <= radius;
원의 바깥쪽은 어둡게, 안쪽은 투명하게, 십자선에 해당하는 위치는 밝은 색으로 채워 조준경 이미지를 구성합니다. 이 경우에도 이미지 에셋이 없을 뿐 메모리에 텍스처와 스프라이트는 생성된다는 점은 구분해야 합니다.
생성한 런타임 리소스는 OnDestroy()에서 해제하고, 화면 비율이 달라지면 새로 생성하도록 했습니다.
정리
미니맵과 아이콘은 VertexHelper로 도형을 직접 그렸고, 저격 조준경은 Texture2D의 픽셀을 계산해 만들었습니다. 파일로 된 UI 이미지가 없어도 원하는 기능을 구현할 수 있지만, 메시 재생성과 텍스처 생성 비용은 사용 빈도에 따라 확인할 필요가 있습니다.