At first glance, flashing text in a custom Unity editor window may sound like an annoyance, and it certainly can be if used inappropriately. But it can be a useful tool for catching a user’s attention if used responsibly. I use it in a few of my custom editors to alert the user to various situations:
- Missing components. For example, my vertex painters won’t work if the selected game object does not contain a mesh component.
- When you’re locking standard scene selection. For example, when my vertex painters are in “Paint Mode”, you cannot select scene objects when clicking in the scene. This can be confusing if you forget you are in “Paint Mode”, or you are using the tool for the first time.
- Warning messages. “Changes cannot be undone” might be a good candidate.
How I use it
How it works
Really the only thing you need to understand is that you cannot use Time.DeltaTime in edit mode, because the game is not running. This means you can’t use tools like iTween to change the color of your text, because it rely’s on Time.DeltaTime to perform all of it’s calculations (yes, even FloatUpdate). So, in order to make the animation happen, you’ll have to write a little extra code yourself. EditorApplication.update is called approximately 100 times per second, even in edit mode, so you can perform your animation logic in there.
Feel free to use or modify the code below for any purpose. I only use it to animate text color, but you could easily adapt it to perform animations of any kind. Maybe you’d like to have a small, animated company logo at the top of editors you release to the asset store for example. The sky’s the limit. Hopefully this code will be of use to someone.
- namespace Assets.Editor
- {
- using UnityEditor;
- using UnityEngine;
- /// <summary>
- /// Class definition for FlashingTextInEditorWindow.cs.
- /// </summary>
- public class FlashingTextInEditorWindow : EditorWindow
- {
- private const float FlashingTextCycleDuration = 2.0f;
- private Color _flashingTextColor = Color.red;
- private float _realTimeLastFrame;
- private bool _fadingColorIn;
- /// <summary>
- /// Register our editor window.
- /// </summary>
- [MenuItem("Sector12/Flashing Text")]
- protected static void Init()
- {
- GetWindow(typeof(FlashingTextInEditorWindow), false, "Flashing Text");
- }
- /// <summary>
- /// Setup a hook into an update method so that we can display flashing text
- /// over time in the editor window.
- /// </summary>
- private void OnEnable()
- {
- // Make sure we're never registered twice
- EditorApplication.update -= UpdateHook;
- EditorApplication.update += UpdateHook;
- }
- /// <summary>
- /// Draw our flashing text.
- /// </summary>
- private void OnGUI()
- {
- Color originalGUIColor = GUI.color;
- GUI.color = _flashingTextColor;
- GUILayout.Label("My flashing warning message!", EditorStyles.boldLabel);
- GUI.color = originalGUIColor;
- }
- /// <summary>
- /// Update() is not automatically called in UnityEditor.Editor controls.
- /// We can, however, hook into the EditorApplication.update delegate.
- /// </summary>
- private void UpdateHook()
- {
- // Determine the amount of time elapsed since last frame. Remember that
- // we are in edit mode, so we cannot use Time.deltaTime.
- float timeElapsed = Time.realtimeSinceStartup - _realTimeLastFrame;
- _realTimeLastFrame = Time.realtimeSinceStartup;
- // Update our flashing text color
- UpdateFlashingTextColor(timeElapsed);
- }
- /// <summary>
- /// Updates our flashing text color (for displaying warning messages in
- /// the inspector).
- /// </summary>
- /// <param name="timeElapsed"></param>
- private void UpdateFlashingTextColor(float timeElapsed)
- {
- // Don't fade the text out entirely, just to low opacity, so it can
- // flash but still always be easily read.
- float minOpacity = .3f;
- // Determine how much to change the color based on the time elapsed
- float amountToChange = (timeElapsed / FlashingTextCycleDuration) * (1f - minOpacity) * 2;
- // Fade the color in or out
- if (_fadingColorIn)
- _flashingTextColor.a += amountToChange;
- else
- _flashingTextColor.a -= amountToChange;
- // When we've fully faded out, start to fade in, and vice versa
- if (_flashingTextColor.a < minOpacity)
- {
- _flashingTextColor.a = minOpacity;
- _fadingColorIn = true;
- }
- if (_flashingTextColor.a > 1)
- {
- _flashingTextColor.a = 1;
- _fadingColorIn = false;
- }
- // Repaint our inspector window
- Repaint();
- }
- }
- }