콘텐츠로 이동

Unity Gizmos와 Handles로 에디터 시각화 구현

Gizmos는 씬 뷰에서 디버그 정보를 시각화하는 도구입니다. Handles는 씬 뷰에서 직접 조작 가능한 UI 요소를 만들어 컴포넌트 값을 인터랙티브하게 편집할 수 있습니다. 두 API 모두 에디터 전용이므로 빌드에 영향을 주지 않습니다.


using UnityEngine;
public class PatrolAgent : MonoBehaviour
{
[SerializeField] private float detectionRadius = 5f;
[SerializeField] private float attackRadius = 2f;
[SerializeField] private Transform[] waypoints;
// 항상 표시
void OnDrawGizmos()
{
// 감지 반경 (반투명)
Gizmos.color = new Color(1, 1, 0, 0.1f);
Gizmos.DrawSphere(transform.position, detectionRadius);
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, detectionRadius);
// 순찰 경로
if (waypoints != null && waypoints.Length > 1)
{
Gizmos.color = Color.cyan;
for (int i = 0; i < waypoints.Length; i++)
{
if (waypoints[i] == null) continue;
// 포인트 표시
Gizmos.DrawSphere(waypoints[i].position, 0.2f);
// 경로 연결
int next = (i + 1) % waypoints.Length;
if (waypoints[next] != null)
Gizmos.DrawLine(waypoints[i].position, waypoints[next].position);
}
}
}
// 선택 시만 표시
void OnDrawGizmosSelected()
{
// 공격 반경 (빨간색)
Gizmos.color = new Color(1, 0, 0, 0.3f);
Gizmos.DrawSphere(transform.position, attackRadius);
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, attackRadius);
// 전방 방향
Gizmos.color = Color.blue;
Gizmos.DrawRay(transform.position, transform.forward * 3f);
}
}

void OnDrawGizmos()
{
// 구체
Gizmos.DrawSphere(center, radius);
Gizmos.DrawWireSphere(center, radius);
// 박스
Gizmos.DrawCube(center, size);
Gizmos.DrawWireCube(center, size);
// 선
Gizmos.DrawLine(from, to);
Gizmos.DrawRay(origin, direction);
// 메시
Gizmos.DrawMesh(mesh, position, rotation, scale);
Gizmos.DrawWireMesh(mesh, position, rotation, scale);
// 아이콘 (Assets/Gizmos/ 폴더에 이미지 배치)
Gizmos.DrawIcon(transform.position, "MyIcon.png", allowScaling: true);
// 프러스텀 (카메라 시야각 시각화)
Gizmos.DrawFrustum(transform.position, 60f, 100f, 0.1f, 1.77f);
// 행렬 변환 적용
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.DrawWireCube(Vector3.zero, Vector3.one); // 로컬 공간
Gizmos.matrix = Matrix4x4.identity; // 리셋
}

3. Handles — 드래그 가능한 에디터 핸들

섹션 제목: “3. Handles — 드래그 가능한 에디터 핸들”
#if UNITY_EDITOR
using UnityEditor;
[CustomEditor(typeof(LightSource))]
public class LightSourceEditor : Editor
{
void OnSceneGUI()
{
var light = (LightSource)target;
// 드래그 가능한 반경 핸들
EditorGUI.BeginChangeCheck();
float newRadius = Handles.RadiusHandle(
Quaternion.identity,
light.transform.position,
light.radius);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(light, "Change Light Radius");
light.radius = newRadius;
}
// 레이블 표시
Handles.Label(
light.transform.position + Vector3.up * (light.radius + 0.5f),
$"반경: {light.radius:F1}m",
EditorStyles.boldLabel);
// 색상 원 표시
Handles.color = new Color(1f, 0.8f, 0f, 0.5f);
Handles.DrawSolidDisc(light.transform.position, Vector3.up, light.radius);
}
}
#endif

4. Handles.PositionHandle — 이동 핸들

섹션 제목: “4. Handles.PositionHandle — 이동 핸들”
void OnSceneGUI()
{
var target = (WaypointPath)this.target;
for (int i = 0; i < target.points.Count; i++)
{
EditorGUI.BeginChangeCheck();
Vector3 newPos = Handles.PositionHandle(
target.points[i],
Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "Move Waypoint");
target.points[i] = newPos;
}
// 번호 레이블
Handles.Label(target.points[i] + Vector3.up * 0.3f, $"#{i}");
}
// 경로 연결
Handles.color = Color.green;
for (int i = 0; i + 1 < target.points.Count; i++)
Handles.DrawLine(target.points[i], target.points[i + 1], 2f);
}

5. 조건부 컴파일로 빌드에서 제거

섹션 제목: “5. 조건부 컴파일로 빌드에서 제거”
public class DebugVisualizer : MonoBehaviour
{
[SerializeField] private bool showGizmos = true;
#if UNITY_EDITOR
void OnDrawGizmos()
{
if (!showGizmos) return;
DrawDebugInfo();
}
void OnDrawGizmosSelected()
{
DrawDetailedInfo();
}
void DrawDebugInfo()
{
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(transform.position, 1f);
}
void DrawDetailedInfo()
{
// 선택 시에만 상세 정보 표시
var style = new GUIStyle();
style.normal.textColor = Color.white;
Handles.Label(transform.position, $"Position: {transform.position}", style);
}
#endif
}

public class SpawnZone : MonoBehaviour
{
[SerializeField] private Vector3 size = Vector3.one * 10f;
[SerializeField] private int maxEnemies = 20;
[SerializeField] private Color zoneColor = new Color(0, 1, 0, 0.1f);
void OnDrawGizmos()
{
Gizmos.matrix = transform.localToWorldMatrix;
// 반투명 박스
Gizmos.color = zoneColor;
Gizmos.DrawCube(Vector3.zero, size);
// 외곽선
Gizmos.color = zoneColor * 3f;
Gizmos.color = new Color(zoneColor.r, zoneColor.g, zoneColor.b, 1f);
Gizmos.DrawWireCube(Vector3.zero, size);
}
#if UNITY_EDITOR
void OnDrawGizmosSelected()
{
Gizmos.matrix = transform.localToWorldMatrix;
// 스폰 포인트 미리보기
var rng = new System.Random(42);
Gizmos.color = Color.red;
for (int i = 0; i < Mathf.Min(maxEnemies, 10); i++)
{
Vector3 point = new Vector3(
(float)(rng.NextDouble() - 0.5) * size.x,
(float)(rng.NextDouble() - 0.5) * size.y,
(float)(rng.NextDouble() - 0.5) * size.z);
Gizmos.DrawSphere(point, 0.2f);
}
// 정보 레이블
Handles.Label(transform.position,
$"스폰 존\n최대 적: {maxEnemies}\n크기: {size}");
}
#endif
}

API용도
Gizmos.DrawWireSphere와이어프레임 구체
Gizmos.DrawLine
Gizmos.matrix좌표 변환 적용
Handles.PositionHandle드래그 이동 핸들
Handles.RadiusHandle반경 조절 핸들
Handles.Label씬 뷰 텍스트
OnDrawGizmos항상 표시
OnDrawGizmosSelected선택 시만 표시