- Home /
 
How to create shared color channels
The plan is to have a global list of colors that can be referenced by other objects.
 I would like it to function where I can can assign multiple objects the same color in the inspector (for example in their sprite renderer color field), and then when I change this color via script, all objects which use this color will also change.
 I was previously told I could use the color swatches to have objects share colors, but I then learned it was not possible to access the swatches with a script and edit the color values.
 Is this even possible?! Cuz I'm struggling to find anything that can help me, even though I feel like this should be something simple to implement. 
Answer by Hellium · May 24, 2020 at 08:39 PM
Unfortunately, what you want to achieve is not possible "out of the box". The Color type is a struct (value-type), not a class (reference type), so each instance of this struct is independent from the others.
You will have to wrap the struct around a class and make sure your objects manipulate the same instance of the class.
Here is my solution using Scriptable Objects. I have tested it and works fine. You might need to adapt the code a little bit to fit your needs.
ColorReference.cs
This is the wrapper of the Color struct. You can create ScriptableObjects from the Assets/Create menu, or by clicking the + / Create in your Project tab, or by right clicking in your Project tab
 using System;
 using UnityEngine;
 
 [CreateAssetMenu]
 public class ColorReference : ScriptableObject
 {
     [SerializeField] private UnityEngine.Color color;
 
     public float a
     {
         get => color.a;
         set => color.a = value;
     }
 
     public float r
     {
         get => color.r;
         set => color.r = value;
     }
 
     public float g
     {
         get => color.g;
         set => color.g = value;
     }
 
     public float b
     {
         get => color.b;
         set => color.b = value;
     }
 
     // Define every other function / property you need
 
     public void Set(UnityEngine.Color color)
     {
         this.color = color;
         Changed?.Invoke();
     }
 
     public event Action Changed;
 
     public static implicit operator UnityEngine.Color(ColorReference color)
         => color.color;
 
     public static implicit operator ColorReference(UnityEngine.Color color)
         => new ColorReference() { color = color };
 }
 
                ColorReferenceEditor.cs in an Editor folder
 
               Custom editor for the ColorReference scriptable object used to invoke the Change event when the color is changed from the scriptable object
 using UnityEngine;
 using UnityEditor;
 
 [CustomEditor(typeof(ColorReference))]
 public class ColorReferenceEditor : Editor
 {
     public override void OnInspectorGUI()
     {
         serializedObject.Update();
         EditorGUI.BeginChangeCheck();
         
         base.OnInspectorGUI();
 
         if(EditorGUI.EndChangeCheck())
         {
             ( target as ColorReference ).Set(( target as ColorReference ));
         }
     }
 }
 
               ColorAssigner.cs
Base class of the concrete ColorAssigners. The ColorAssigners have the responsibility to react to the change of the color
 using UnityEngine;
 
 [ExecuteInEditMode]
 public abstract class ColorAssigner : MonoBehaviour
 {
     [SerializeField] private ColorReference color;
 
     public ColorReference ColorReference
     {
         get => color;
         set
         {
             if (color == value)
                 return;
 
             ColorReference oldValue = color;
             
             if (oldValue != null && value == null)
                 UnsubscribeColorChange();
             
             color = value;
 
             if(oldValue == null && value != null)
                 SubscribeColorChange();
         }
     }
 
     protected abstract void AssignColor(Color color);
 
     private void SubscribeColorChange() => color.Changed += OnColorChanged;
 
     private void UnsubscribeColorChange() => color.Changed -= OnColorChanged;
     
     private void OnColorChanged() => AssignColor(color);
 
     private void Start()
     {
         if (color != null)
         {
             UnsubscribeColorChange();
             SubscribeColorChange();
             AssignColor(color);
         }
     }
 
     private void OnDestroy()
     {
         if (color != null)
             UnsubscribeColorChange();
     }
 
 #if UNITY_EDITOR
     private void OnValidate()
     {
         if (color != null)
         {
             UnsubscribeColorChange();
             SubscribeColorChange();
             OnColorChanged();
         }
     }
 #endif
 
 }
 
               GraphicColorAssigner.cs
This class is a concrete implementation of the ColorAssigner abstract class to change the color of any UI element (Text Mesh Pro included) when the color of the ScriptableObject changes
 using UnityEngine;
 using UnityEngine.UI;
 
 public class GraphicColorAssigner : ColorAssigner
 {
     protected override void AssignColor(Color color)
     {
         GetComponent<Graphic>().color = color;
     }
 }
 
               RendererColorAssigner.cs
This class is a concrete implementation of the ColorAssigner abstract class to change the color of the Renderer component (MeshRenderer / SpriteRenderer) when the color of the ScriptableObject changes
 using UnityEngine;
 public class RendererColorAssigner : ColorAssigner
 {
     protected override void AssignColor(Color color)
     {
         GetComponent<Renderer>().sharedMaterial.color = color;
     }
 }
 
                ColorReferencePropertyDrawer.cs in an Editor folder
 
               If you want to directly change the color from the ColorAssigners' inspector, place this script in an Editor folder
 using UnityEngine;
 using UnityEditor;
 
 [CustomPropertyDrawer(typeof(ColorReference))]
 public class ColorReferencePropertyDrawer : PropertyDrawer
 {
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
     {
         DrawLabel(position, label);
 
         position.xMin += EditorGUIUtility.labelWidth;
 
         DrawScriptableObjectField(position, property);
         if(property.objectReferenceValue)
             DrawColorField(position, property);
     }
 
     private static void DrawLabel(Rect position, GUIContent label)
     {
         GUI.Label(position, label);
     }
 
     private void DrawScriptableObjectField(Rect position, SerializedProperty property)
     {
         if (property.objectReferenceValue != null)
             position.xMin = position.xMax - 20;
 
         EditorGUI.ObjectField(position, property, typeof(ColorReference), GUIContent.none);
     }
 
     private void DrawColorField(Rect position, SerializedProperty property)
     {
         SerializedObject colorReference  = new SerializedObject(property.objectReferenceValue);
         SerializedProperty colorProperty = colorReference.FindProperty("color");
 
         EditorGUI.BeginChangeCheck();
 
         position.xMax -= 20;
         Color color = EditorGUI.ColorField(position, GUIContent.none, colorProperty.colorValue);
         
         if(EditorGUI.EndChangeCheck())
         {
             ( colorReference.targetObject as ColorReference ).Set(color);
             property.serializedObject.ApplyModifiedProperties();
             EditorUtility.SetDirty(property.serializedObject.targetObject);
         }
     }
 }
 
               I have tested the solution with the following simple script
 // Drag & drop the scriptable object in the inspector
 public ColorReference colorRef;
 private void Update()
 {
     if (Input.GetKeyDown(KeyCode.Space))
         colorRef.Set(Color.HSVToRGB(Random.Range(0, 1f), 1, 1));
 }
 
              Wow, thanks for such a thorough response!
I am kind of unclear on how to use these scripts though. I've added them, but nothing in the editor seems to change and I don't know which scripts I attach to which objects.
Could I get a bit of an explanation, maybe an example, of how I would go about assigning a color to a single object, and how I would change it's color in a script?
Thanks.
Attach the
RendererColorAssigner/GraphicColorAssignercomponent to your objects.Create a
ColorReferenceusing the Assets/Create menuSelect the scriptable object from the inspector of the
RendererColorAssigner/GraphicColorAssignercomponentsChange the color in the inspector of one of the components, the color of all the objects with the
RendererColorAssigner/GraphicColorAssignercomponent should change
thanks. there is an issue tho that the color doesn't seem to change during play when i change it with a script. Additionally, when changing the color in the inspector, I get a console error saying "The object of type 'RendererColorAssigner' has been destroyed but you are still trying to access it."
 Edit: I'm thinking it has to do with fact that ScriptableObjects can only be used in the editor not during runtime. which is a huge problem as modifying the colors during runtime is half of what i'm trying to do 
Your answer
 
             Follow this Question
Related Questions
Change startcolor of particle system through script 1 Answer
Instantiating multiple sprites and assigning different colors for each 1 Answer
How to change the color from code 1 Answer
Multiple Cars not working 1 Answer
When a ball is clicked and background color matches it's color I get a point? 0 Answers