1

I'm working with Unity and I am trying to create a class that can store specific components states and restore them at a later stage. This is however not tied to Unity and should be able to be used anywhere with any type of property. This is however the example I will use since it is intuitive and the solution to that example should give a complete answer.

I have a GameObject which has an object of the type Transform attached to it which stores the location, rotation and scale of the object. This is what I would like to store and be able to restore at a later time.

Storing the state

The state of the object is saved by creating a deep copy of the Transform and is then saved in a dictionary with the type as key, and the copy as value. The deep copy can be achieved by either via a Serializable class or an Object extension. Mind that using IClonable is not possible since I do not own the code of the class Transform. Using the Object extension the code is easy. Inside a class:

// The object that should have its state (re)stored
public GameObject _parent;
// Dictionary to hold the object state and its underlying type
public Dictionary<Type, object> _states;

// Store a deep copy of the component of type T
public void StoreState<T>() {
    _states.Add(typeof(T), _parent.GetComponent<T>().Copy());
}

// Alternatively
public void StoreState(Type t) {
    _states.Add(t, _parent.GetComponent(t).Copy());
} 

Restoring the state

This is the part where I am stuck. I cannot simply create a new instance of the Transform and assign it to the GameObject since its not accessible. How do I copy all values from the dictionary values back?

public void RestoreInitialState() {
    foreach (var pair in _states) {
        // Copy to original?
        _parent.GetComponent(pair.Key) = pair.Value.Copy();
        // Error: The left-hand side of an assignment must be a variable, property or indexer
        //        This expression cannot be used as an assignment target
    }
}

It might be sufficient to copy all public fields and/or properties?

Community
  • 1
  • 1
Didii
  • 1,194
  • 12
  • 36

3 Answers3

1

Use the new unity json serializer http://docs.unity3d.com/Manual/JSONSerialization.html , its easy , simple and faster then any json library I have worked with unity , it even serializes your vectors without any problem.Create a class and save its object with all its variables and to restore them just use jsontoObject and all ur values are back and restored , if thats what you asked for .

LumbusterTick
  • 1,067
  • 10
  • 21
  • This is exactly what I wanted! Sadly tough, using `JsonUtility.ToJson` on an engine class is forbidden for some reason. For self-implemented Mono-Behaviours this works fine. – Didii May 17 '16 at 15:31
  • I would also recommend using simpleJson library with it if you want data out like this data["itemName"], ofc this depends on your choice of code and need but its handy for testing json . Also I find it a better solution for create custom json through code. – LumbusterTick May 18 '16 at 07:34
  • Thanks for the help btw. I asked a similar question on the forums and found that it is impossible to create a generic save method for all classes (including engine classes). For more info, [see this forum post](http://forum.unity3d.com/threads/jsonutitlity-not-supporting-engine-classes.405115/#post-2642085). – Didii May 20 '16 at 10:43
  • the problem was that when they released json parser in unity 5 they didnt mention it any update , strange , even I stumbled upon it by chance – LumbusterTick May 20 '16 at 12:10
0

I have been using XML serialization to achieve things like that. It feels a bit like a hack, but it's been working well for me this far.

Here are a couple of helper methods to serialize and deserialize an object, which could obviously be your "Transform" object:

        /// <summary>
        /// Serializes an object to an xml string
        /// </summary>
        public static String Serialize(Object obj)
        {
            if (obj == null)
            {
                return "";
            }

            string xml = string.Empty;          

            try
            {
                // Remove xml declaration.
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.OmitXmlDeclaration = true;

                using (StringWriter sw = new StringWriter())
                {
                    using (XmlWriter xw = XmlWriter.Create(sw, settings))
                    {
                        XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
                        xmlSerializer.Serialize(xw, obj);
                    }

                    xml = sw.ToString();
                }
            }
            catch (Exception) { }

            return xml;
        }

        /// <summary>
        /// Deserializes a xml string to an object
        /// </summary>
        public static Object Deserialize(String xml, Type type)
        {
            Object obj = null;

            try
            {
                if (xml != string.Empty)
                {
                    using (StringReader sr = new StringReader(xml))
                    {
                        XmlSerializer x = new XmlSerializer(type);
                        obj = x.Deserialize(sr);
                    }
                }
            }
            catch (Exception e)
            {
                throw new PageException("XmlDeserialization failed", e);
            }

            return obj;
        }

Like I said, I'm not sure if it's "good", but it works. =) Pointers appreciated!

Culme
  • 1,065
  • 13
  • 21
0

There's a Serialize Helper posted on Unity forums, full and complete (more or less). But I would save and restore the values instead. I'm not a fan of manipulating runtime objects for several reasons (fragile, if anything goes wrong I'll have no idea what, why and where, platform builds may not possible, etc)