[Unity] 에디터 프로그래밍 – 게임 오브젝트에 이름표(Name Tag) 달아보기

위의 이미지와 같이 Scene view에서 게임 오브젝트의 이름 정보가 UI로 표시되도록 구성해보려고 한다.  이를 위해 3단계로 나누어서 구현해 보았다.

  • 게임 오브젝트 생성
  • 이름표 정보 GUI 표시
  • 이름표와 게임 오브젝트사이에 연결선 그리기

첫번째인 게임 오브젝트 생성은 상황에 따라 다르겠지만, 여기서는 단순하게 Resources 폴더에 있는 MyCube.prefab을 로드하여 생성하는 것으로 해보았다. 

    private GameObject cubeObj;
    
    protected void OnEnable()
    {
        var obj = Resources.Load<GameObject>("MyCube");
        cubeObj = Instantiate(obj) as GameObject;
    }

    protected void OnDisable()
    {
        DestroyImmediate(cubeObj);
    }

자, 이제 오브젝트는 생성했으니, 두번째인 이름표 정보 GUI 표시를 해보자.

Scene view 상에 UI를 그리기 위해서는 update 콜백이 필요하다.  그래서 유니티에서는 Scene에서 오브젝트 정보 표시 및 이벤트 취합을 위해 콜백을 제공하는데, 이를 사용하기 위해서는 SceneView 클래스 onSceneGUIDelegate에 에디터 윈도우에서 사용할 콜백 함수를 추가하면된다.  그러면 Scene을 위한 update tick을 받을 수 있다.

    protected void OnEnable()
    {
        if (SceneView.onSceneGUIDelegate != this.OnSceneGUI)
        {
            SceneView.onSceneGUIDelegate += this.OnSceneGUI;
        }
        var obj = Resources.Load("MyCube");
        cubeObj = Instantiate(obj) as GameObject;
    }
    protected void OnDisable()
    {
        SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
        DestroyImmediate(cubeObj);
    }

    private void OnSceneGUI(SceneView sceneView)
    {
    }

이제 OnSceneGUI라는 함수에서 Scene 상에 표시되는 정보들을 다룰 수 있게 되었다.  이제 GUI.Box를 하나 만들고, 그 안에 게임 오브젝트의 이름이 표시되도록 해보자.

    private void OnSceneGUI(SceneView sceneView)
    {
        var guiLoc = HandleUtility.WorldToGUIPoint(cubeObj.transform.position);  // 오브젝트의 월드좌표를 2D 좌표로 변환
        var rect = new Rect(guiLoc.x - 50.0f, guiLoc.y - 150, 100, 25);    // 라벨 위치 지정
      
        Handles.BeginGUI();
        var oldbgcolor = GUI.backgroundColor;
        GUI.backgroundColor = Color.red;     // 배경 색 지정
       
        GUI.Box(rect, cubeObj.name);      // Box UI 표시
        
        GUI.backgroundColor = oldbgcolor;
        Handles.EndGUI();
    }

WorldToGUIPoint를 통해 월드 스페이스의 좌표를 2D GUI 좌표료 변환하고, 게임 오브젝트의 약간 위에 생성되도록 rect의 위치를 잡아보았다.  그리고 GUI.Box를 통해 cubeObj의 이름이 표시되도록 하였다.  배경 색 정보는 선택이지만, 여기서는 잘 보이도록 빨간색으로 해보았다.

이제 마지막 세번째인 이름표와 게임 오브젝트사이에 연결선 그리기가 남았다.  라벨의 3D 위치와 게임 오브젝트의 3D 위치를 구하고 그 사이를 라인으로 그리는 방법으로 진행해 보았다.

    private void OnSceneGUI(SceneView sceneView)
    {
        var guiLoc = HandleUtility.WorldToGUIPoint(cubeObj.transform.position);
        var rect = new Rect(guiLoc.x - 50.0f, guiLoc.y - 150, 100, 25);

        var ray = HandleUtility.GUIPointToWorldRay(rect.position + new Vector2(rect.width / 2, rect.height / 2));
        var lbWPos = ray.origin;
        var oldcolor = Handles.color;
        Handles.color = Color.red;
        Handles.DrawLine(cubeObj.transform.position, lbWPos);
        Handles.color = oldcolor;

        Handles.BeginGUI();
        var oldbgcolor = GUI.backgroundColor;
        GUI.backgroundColor = Color.red;
        GUI.Box(rect, cubeObj.name);
        GUI.backgroundColor = oldbgcolor;
        Handles.EndGUI();
    }

GUIPointToWorldRay를 통해 rect의 중심점을 바로 구하고 싶었으나, ray 정보만을 주는 API밖에 찾지 못해서, ray의 origin을 이용하여 rect의 월드 좌표를 구하였다.  그리고 cubeObj.transform.position의 좌표에서 rect의 월드 좌표까지 DrawLine을 통해 연결선을 그리도록 하였다.  색 정보는 마찬가지로 선택이지만, 잘 보이기 위해 빨간색으로 해보았다.

컴파일이 모두 잘 되었다면, 에디터 윈도우를 띄워보자.  오브젝트를 옮기고 변형시켜도 이름표가 다음과 같이 잘 따라다닌다면 성공이다.

이름표는 게임 오브젝트 이름을 표시한다든가 아이디를 표시하는 등 여러 정보를 표현할 수 있고, GUI.Box대신 Button을 사용하여 Scene에서 오브젝트를 선택할 수도 있다.  목적에 따라 여러가지 변형이 가능하니 잘 알아두면 유용할 것이다.  🙂 


Leave a Reply

Your email address will not be published. Required fields are marked *