I want to share a Gizmo helper

While watching Gizmos static helpers, I see it’s lacking of a method to display a text, that can be useuful
So I googled to find a solution and I find a snippet that I adapted to my needs, so I created an extension of Component, here the code (I used UnityEngine namespace so it should always be available)

namespace UnityEngine
{
    public static class ComponentExtensions
    {
        static public void DrawGizmoString(this Component component, string text, Vector3 worldPos, Color? color = null)
        {
            var view = UnityEditor.SceneView.currentDrawingSceneView;
            if (view == null) return;

            UnityEditor.Handles.BeginGUI();

            var previousColor = GUI.color;

            if (color.HasValue) GUI.color = color.Value;

            Vector3 screenPos = view.camera.WorldToScreenPoint(worldPos);

            if (screenPos.y < 0 || screenPos.y > Screen.height || screenPos.x < 0 || screenPos.x > Screen.width || screenPos.z < 0)
            {
                GUI.color = previousColor;
                UnityEditor.Handles.EndGUI();
                return;
            }

            Vector2 size = GUI.skin.label.CalcSize(new GUIContent(text));
            GUI.Label(new Rect(screenPos.x - (size.x / 2), -screenPos.y + view.position.height + 4, size.x, size.y), text);
            GUI.color = previousColor;
            UnityEditor.Handles.EndGUI();
        }
    }
}

and I used it to display Health points on every GameObject using Health component (not just for selected ones)

just add this to your Health component

private void OnDrawGizmos()
{
   this.DrawGizmoString($"Health: {this.healthPoints}", this.transform.position, Color.black);
}

the result is something like this
image

(this extension could be generalized and e.g. we should update it to accept test positioning like center, left, right etc…)

1 Like

@sampattuzzi ^

and while in the mood, I’ve created a GizmoColor diposable class that can be used to change gizmo color and restore to original one on dispose

using System;

namespace UnityEngine
{
    /// <summary>
    /// Disposable utility class to set a color used for Gizmos and restore it when the using block ends or Dispose is called.
    /// Color can be changed during GizmoColor lifetime, calling <see cref="ChangeColor"/> or even directly changing on <see cref="Gizmos.color"/>.
    /// </summary>
    /// <seealso cref="System.IDisposable" />
    public class GizmoColor : IDisposable
    {
        private Color originalColor;

        /// <summary>
        /// Initializes a new instance of the <see cref="GizmoColor"/> class applying current <paramref name="color"/> to Gizmos generated after this call.
        /// </summary>
        /// <param name="color">The color. If <see langword="null"/>, Gizmos.color is used.</param>
        public GizmoColor(Color? color = null)
        {
            this.originalColor = Gizmos.color;

            if (color != null)
            {
                Gizmos.color = color.Value;
            }
        }

        /// <summary>
        /// Changes the color of the Gizmos generated after this call.
        /// </summary>
        /// <param name="newColor">The new color.</param>
        public void ChangeColor(Color newColor)
        {
            Gizmos.color = newColor;
        }

        /// <summary>
        /// Restores the original color of the Gizmos.
        /// </summary>
        public void RestoreOriginalColor()
        {
            Gizmos.color = originalColor;
        }

        public void Dispose()
        {
            Gizmos.color = this.originalColor;
        }
    }
}

so you can use it like

using (var color = new GizmoColor())
{
    if(UnityEditor.Selection.activeGameObject == transform.gameObject)
    {
        color.ChangeColor(Color.red);
    }
    Gizmos.DrawSphere(transform.position, 1);
}

useful when you want to render different gizmo in the same OnDrawGizmos

Really awesome stuff!

Just wondering why you did the first one as an extension. Doesn’t look like you use the component so why not make it static. Also, not sure about using the Unity namespace, I think can cause issues if they use that name in future.

@sampattuzzi being it an extension means that the method is always available when using the Component class or any of its subclasses (like MonoBehaviour) and the choice to set this in UnityEngine namespace is because I find useful to have these kind of extension in the same namespace where the extended class is defined so the user don’t have to remember to include the extension namespace to use these methods.
The chance of name collision is lower than the advantage I have on having them in the same namespace and in case this happen, just renaming the extension class fix everything (the only problem if they implement a DrawGizmoString but it’s unlikely since they use the Gizmo static class to deal with gizmos

Anyway in this case probably is better to follow the Gizmos design and implement a static class like GizmosEx to mimic Gizmos unity class so I can add my extended Gizmos features there, why not (W consistency).

Privacy & Terms