Can't Serialize Color or Vector2

So according to Unity - Manual: Script serialization , I should be able to serialize Color and Vector2 Variables, but trying to do so gives the following error:

System.Runtime.Serialization.SerializationException: Type 'UnityEngine.Color' in Assembly 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.

I tested, and serializing it by simply deconstructing the Variables into Red, Green and Blue Float values for example, works fine, but I’m just wondering if anyone knows why this isn’t working, since it would be cleaner to just store the values directly instead of dismantling and putting them back together when saving and loading.

Here’s some of the lines interacting with the Serializeable “GameInfo” Class:

   public void SaveData()
    {
        FileStream file = null;
        try
        {   
            BinaryFormatter bf = new BinaryFormatter();
            file = File.Create(Application.persistentDataPath + path);
            data = new GameInfo(
            // The other Variables are being put here, just snipped out

                GameObject.FindGameObjectWithTag("PlayerHat").GetComponent<SpriteRenderer>().color)
            bf.Serialize(file, data);
        }
        catch (Exception e)
        {
            if (e != null)
            {
                Debug.Log(e);
            }
        }
        finally
        {
            if (file!= null)
            {
                file.Close();
            }
        }
    }
    public void LoadData()
    {
        FileStream file = null;
        try
        {
            BinaryFormatter bf = new BinaryFormatter();
            file = File.Open(Application.persistentDataPath + path,FileMode.Open);
            data = bf.Deserialize(file) as GameInfo;
            // The other Variables are being put here, just snipped out
            GameObject.FindGameObjectWithTag("PlayerHat").GetComponent<SpriteRenderer>().color = data.HatColor;
        }
        catch(Exception e)
        {
            if (e != null)
            {
                Debug.Log(e);
            }

        }
        finally
        {
            if (file != null)
            {
                file.Close();
            }
        }
    }

Heres the GameInfo Segment dealing with the HatColor (The Part I’m Testing with)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

[Serializable]
public class GameInfo
{
    private Color _HatColor;

    public GameInfo() { }

    public GameInfo(
        Color HatColor
    {
        _HatColor = HatColor;
    }

    public Color HatColor
    {
        get
        {
            return _HatColor;
        }
        set
        {
            _HatColor = value;
        }
    }
}

Can anyone spot what I’m doing wrong here?

I have had issues with Serialization and the solution I came up with is to convert the type into a serialazable class.

Example for your Hatcolor / any Color.

[Serializable]public class HatColor
{
	public float _r;
	public float _g;
	public float _b;
	public float _a;
	
	public Color Color
	{
		get{
			return new Color(_r, _g, _b, _a);
		}
		set{
			_r = value.r;
			_g = value.g;
			_b = value.b;
			_a = value.a;
		}
	}
}

This can be used when you have issues with any Unity object type that wont serialize.

You could further it to add methods to initialize it with the values for a color or a color itself but i will leave that to you.

EDIT: Added an example simple Serializable Color Class

using UnityEngine;

[System.Serializable]public class SerializableColor
{
    public float _r;
    public float _g;
    public float _b;
    public float _a;

    public Color Color
    {
        get
        {
            return new Color(_r, _g, _b, _a);
        }
        set
        {
            _r = value.r;
            _g = value.g;
            _b = value.b;
            _a = value.a;
        }
    }

    public SerializableColor()
    {
        // (Optional) Default to white with an empty initialisation
        _r = 1f;
        _g = 1f;
        _b = 1f;
        _a = 1f;
    }

    public SerializableColor(float r, float g, float b, float a = 0f)
    {
        _r = r;
        _g = g;
        _b = b;
        _a = a;
    }

    public SerializableColor(Color color)
    {
        _r = color.r;
        _g = color.g;
        _b = color.b;
        _a = color.a;
    }
}

Usages

SerializableColor = new SerializableColor(0f, 0f, 0f); // with Color Values
SerializableColor = new SerializableColor(Color.white); // With a Color
SerializableColor = new SerializableColor(); // Default to White

renderer.material.color = SerializableColor.Color;

You can use one simple class for the most part of Unity structs, use impliciti operators for easy conversion between Unity types and serialized type. Something like this:

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;

public class Ser : MonoBehaviour
{

    [ContextMenu("Test Serialize")]
    void TestSerialize()
    {
        BinaryFormatter bf = new BinaryFormatter();

        Vector2 vector2 = new Vector2(1, 4);
        SerializableVector4 s_vector2 = vector2;
        FileStream file = File.Open(Path.Combine(Application.persistentDataPath, "serialization_test_vector2.dat"), FileMode.OpenOrCreate);
        bf.Serialize(file, s_vector2);

        SerializableVector4 s_quaternion = transform.rotation;
        file = File.Open(Path.Combine(Application.persistentDataPath, "serialization_test_quaternion.dat"), FileMode.OpenOrCreate);
        bf.Serialize(file, s_quaternion);

        SerializableVector4 s_color = Color.magenta;
        file = File.Open(Path.Combine(Application.persistentDataPath, "serialization_test_color.dat"), FileMode.OpenOrCreate);
        bf.Serialize(file, s_color);
        file.Close();

        Debug.Log("Serialized");
    }


    [ContextMenu("Test Deserialize")]
    void TestDeserialize()
    {
        BinaryFormatter bf = new BinaryFormatter();

        FileStream file = File.Open(Path.Combine(Application.persistentDataPath, "serialization_test_vector2.dat"), FileMode.Open);
        Vector2 d_vector2 = (SerializableVector4)bf.Deserialize(file);
        file.Close();
        Debug.Log(d_vector2);

        file = File.Open(Path.Combine(Application.persistentDataPath, "serialization_test_quaternion.dat"), FileMode.Open);
        Quaternion d_quaternion = (SerializableVector4)bf.Deserialize(file);
        file.Close();
        Debug.Log(d_quaternion);

        file = File.Open(Path.Combine(Application.persistentDataPath, "serialization_test_color.dat"), FileMode.Open);
        Color d_color = (SerializableVector4)bf.Deserialize(file);
        file.Close();
        Debug.Log(d_color);
    }
}

[System.Serializable]
public class SerializableVector4
{
    public float a;
    public float b;
    public float c;
    public float d;

    // Quaternion
    public static implicit operator Quaternion(SerializableVector4 sv)
    {
        return new Quaternion(sv.a, sv.b, sv.c, sv.d);
    }

    public static implicit operator SerializableVector4(Quaternion q)
    {
        return new SerializableVector4()
        {
            a = q.x,
            b = q.y,
            c = q.z,
            d = q.w
        };
    }

    // Color
    public static implicit operator Color(SerializableVector4 sv)
    {
        return new Color(sv.a, sv.b, sv.c, sv.d);
    }

    public static implicit operator SerializableVector4(Color c)
    {
        return new SerializableVector4()
        {
            a = c.r,
            b = c.g,
            c = c.b,
            d = c.a
        };
    }

    // Vector2
    public static implicit operator Vector2(SerializableVector4 sv)
    {
        return new Vector2(sv.a, sv.b);
    }

    public static implicit operator SerializableVector4(Vector2 v)
    {
        return new SerializableVector4()
        {
            a = v.x,
            b = v.y
        };
    }
}

@AaronBacon : I think the code is nicer with (a) arrays (b) extension methods (c) expression body. The end result is typically a one-liner.

    public static int[] ToArray(this Vector2Int value) => new int[] { value.x, value.y };
    public static Vector2Int ToVector2Int(this int[] value) => new Vector2Int(value[0], value[1]);