- Home /
Can't Serialize Color or Vector2
So according to https://docs.unity3d.com/Manual/script-Serialization.html , 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?
Seems like a bug, try delete Library and Temo folders and all Visual Studio (or whatever code editor you use) folders and files. The open up your project again
It's not a bug its just that Colors along with a few other Unity objects (Quaternion, Vector2, Vector3...) aren't marked as serializable.
Ah, I see, I thought you wasn't able to serialize them in unity inspector. If you want them to serialize with binary formatter you should create helper classes/structs containing primitive values and mark them serializable, so you need a mechanism to transform from and to these types, you can use implicit/explicit operators in your custom classes. Also, for these type of data you can tray json serialization. There is official .NET JSON serializer who can work with Unity standard types like Vector and Color and serialize/deserialize them, and you save it like text file.
Answer by akaBase · Jul 05, 2019 at 02:14 PM
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;
That is what I'm doing at the moment, Like I said, just wondering if anyone has a solution ins$$anonymous$$d of the annoying workaround of dismantling any variable I want to serialize.
I was never able to find one, I so just make generic serializable versions for ones that will need to be serialized.
No, there is no other way as Unity did not mark those structs as serializable. So your only options are to create serializable versions of the struct / class you want to serialize or to use surrogates. Surrogates are not really simpler however they are probably a more straight forward solution.
Though I wouldn't recommend the Binary formatter anyways. The binary format is often even larger than simple JSON (except you have really a lot data). Also it's a real pain when you need to have different serialization data versions. Any change to the classes (adding, removing, rena$$anonymous$$g, changing a type of a field) will break the deserialization completely.
Thanks, In my case the file is never gonna be more than a $$anonymous$$ilobyte or two, so file size won't really be a large issue. The main reason I'm using BinaryFormatter is for the protection of the data so any random person can't just edit their save data.
I cleaned up the code a litte more if anyone needs that:
using UnityEngine;
[System.Serializable]
public class SerializableColor
{
public float _r, _g, _b, _a;
public Color GetColor() => new Color(_r, _g, _b, _a);
public void SetColor(Color color)
{
_r = color.r;
_g = color.g;
_b = color.b;
_a = color.a;
}
public SerializableColor() { _r = _g = _b = _a = 1f; }
public SerializableColor(Color color) : this(color.r, color.g, color.b, color.a) { }
public SerializableColor(float r, float g, float b, float a = 0f)
{
_r = r;
_g = g;
_b = b;
_a = a;
}
}
Also note that this class creates a new Color every time you call .Color, so make sure to use it for serialization only.
Answer by misher · Jul 06, 2019 at 04:29 PM
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
};
}
}
Answer by dpoly · Apr 14 at 01:50 PM
@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]);
Your answer
Follow this Question
Related Questions
Serialization Exception Error When Trying to Load 2 Answers
Saving and Loading in Binary corrupted save help 1 Answer
how to properly save an int value ? 2 Answers
Serialized Data Not Saving on Android Build 0 Answers
I am getting a serialization exception error when trying to save and load in Unity? 2 Answers