• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
Question by TheZoc · Mar 26, 2014 at 04:01 AM · editorserializationprocedural-generationserializefieldcustom-class

How to properly serialize fields and store them for use in play mode?

Hello,

I'm stuck with this for ~3 days already, and I'm browsing tons of questions in UnityAnswers. Sadly, I'm still stuck.

I'm working on a mesh generator based off the terrain, so in future it will be used as an A* navigation graph. The mesh seems to be working fine (I'm using a "OnDrawGizmos()" function to check it), but as soon as I hit the play button, all the data is gone. I could go the brute-force way and store it in a file after generation and load it as soon as the game starts, but... I want to do it the Unity way.

So, to sum it up: How can I properly declare the variables so they get saved when I'm done with my graph and stored for use when I press play?

The code is quite lengthy, so I'll only paste the class definitions - tell me if I need to post more.

 using UnityEditor;
 using UnityEngine;
 using System;
 using System.Collections;
 using System.Collections.Generic;
 
 //---------------------------------------------------------------
 // Since Unity currently lacks a Tuple<T> implementation,
 // lets use a simple one for coordinates
 //---------------------------------------------------------------
 [System.Serializable]
 public class Coordinate : IEquatable< Coordinate >
 {
     [SerializeField] private int _x;
     [SerializeField] private int _z;
 
     public int x { get { return _x;    } set { _x    = value; } }
     public int z { get { return _z;    } set { _z    = value; } }
 
     public Coordinate() {}
     
     public Coordinate(int first, int second)
     {
         this.x = first;
         this.z = second;
     }
 
     public override bool Equals( object obj )
     {
         var other = obj as Coordinate;
         if( other == null ) return false;
         
         return Equals (other);             
     }
     
     public override int GetHashCode()
     {
         int hash = 13;
         hash = (hash * 7) + x;
         hash = (hash * 11) + z;
         return hash;
     }
 
     public bool Equals( Coordinate other )
     {
         if    ( other == null )                    return false;
         if    ( GetType() != other.GetType()    )    return false;
         if    ( ReferenceEquals (this, other)    )    return true;
         if    ( x == other.x && z == other.z    )    return true;
         return false;
     }
 
     public override string ToString()
     {
         return string.Format ("[Coordinate: x={0}, z={1}]", x, z);
     }
 }
 
 //---------------------------------------------------------------
 // This is our GridNode class. The A* mesh will be stored here.
 //---------------------------------------------------------------
 [System.Serializable]
 public class GridNode
 {
     [SerializeField] private bool                _Valid;
     [SerializeField] private Vector3            _Position;
     [SerializeField] private List< Coordinate >    _Neighbours;
     
     public    bool                Valid            { get { return _Valid;        }    private    set { _Valid        = value;    }    }    // Whether this node is usable or not.
     public    Vector3                Position        { get { return _Position;    }            set { _Position        = value;    }    }    // Spatial position
     public    List< Coordinate >    Neighbours        { get { return _Neighbours;    }            set { _Neighbours    = value;    }    }    // We store our neighbours here.
 
     public    void                MarkAsValid()    { this.Valid = true;        }    // This seems to be kinda stupid, but lets just be VERY safe here.
     public    void                MarkAsInvalid()    { this.Valid = false;        }
 
     public GridNode()
     {
         Valid        = false;
         Position    = Vector3.zero;
     }
 }
 
 [ExecuteInEditMode]
 public class GridGenerator : MonoBehaviour
 {
     #region Variable Declarations
     // The editor will complaint these should be either private or Capitalized. Keep as is for the Editor counterpart.
     [SerializeField] private    bool            m_bDrawGridArea        = true;            // Should we display the grid on the editor? 
     [SerializeField] private    bool            m_bDrawMeshNodes    = true;            // Should we display the nodes on the editor? 
     [SerializeField] private    bool            m_bDrawMesh            = true;            // Should we display the mesh on the editor?
 
 
     public    int                    m_iSquareSideSize    = 50;            // Max size of the graph (and the matrix it generates ;) )
     public    int                    m_iStartNodeX        = 0;            // Column coordinate
     public    int                    m_iStartNodeZ        = 0;            // Row coordinate
     public    float                m_flScale            = 1.0f;            // Unit scale!
     public    float                m_flGroundDistance    = 0.1f;            // Desired ground distance. This is NEVER scaled!
     public    bool                m_bBuildingGraph    = false;        // Using this, we control the grid build stage (Internal control only, don't touch please.)
     public    float                m_flGroundTraceSize = 10.0f;        // Haw far can we search for the ground (halved for each axis)
 
     public    float                m_flMaxMeshNodeStraightDistance    = 1.42f;
     public    float                m_flMaxMeshNodeDiagonalDistance    = 2.0f;
 
     // Both variables are temporary and used for Mesh generation
     private HashSet<Coordinate>    m_Closed;                            // Used in Grid generation
     private Queue<Coordinate>    m_ProcessQueue;                        // Used in Grid generation
 
     [SerializeField]
     private    GridNode[,]            _m_Grid;                            // Our sexy grid storage
     public    GridNode[,]            m_Grid
     {
         get { return _m_Grid;    }
         set { _m_Grid = value;    }
     }
 
 
     #endregion
     
     // Use this for initialization
     void Start ()
     {
 //        Debug.Log("test: " + m_Grid[0,0].Position);
     }
     
     // Update is called once per frame
     void Update()
     {
 //        Debug.Log("test: " + m_Grid[0,0].Position);
     }
 }


For initialization (for tests, etc.) you can use this:

         for ( int f = 0; f < m_iSquareSideSize; f++ )
             for ( int g = 0; g < m_iSquareSideSize; g++ )
             {
                 m_Grid[ f, g ] = new GridNode();
                 m_Grid[ f, g ].Neighbours = new List< Coordinate >();
             }

Thank you in advance! I really hope someone out there knows a solution for this :) Also improvements are welcome!


PS: I found this link prior posting this question, but I couldn't find what's wrong with my code :(

Comment
whydoidoit

People who like this

1 Show 7
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image TheZoc · Mar 26, 2014 at 05:14 AM 0
Share

Update: I edited my code and, if I replace GridNode[,] with GridNode[], it works. Any clue why a bidimensional array doesn't get saved, but a single dimension array does ?

avatar image whydoidoit · Mar 26, 2014 at 05:25 AM 1
Share

Good old Unity serialization - you are stuck with writing your own mapping function for a 1d to 2d array.

avatar image TheZoc · Mar 26, 2014 at 05:28 AM 0
Share

Yeah... Sad I'm stuck for 3 days with this :(

I'm already converting the code to use mapping on a single dimension: y * m_iSquareSideSize + x

Thank you :)

avatar image whydoidoit · Mar 26, 2014 at 05:30 AM 0
Share

I've got an implementation of Tuple I wrote - though your specific looks fine to me (and probably has a better version of GetHashCode).

avatar image whydoidoit · Mar 26, 2014 at 05:34 AM 0
Share

So only 1D arrays and lists serialize (no dictionaries, queues, hashsets etc) and also watch references to your serializable classes, multiple references to the same thing get deserialized as separate instances (unless the object inherits from ScriptableObject and you do the necessary rain dance).

Show more comments

1 Reply

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by TheZoc · Mar 26, 2014 at 06:13 AM

The class and variables declaration are fine - Sadly, Unity can't serialize bidimensional arrays. As a workaround, I changed my GridNode[,] to GridNode[] and I'm using this auxiliary function:

     private int SolveGridIndex( int x, int z )
     {
         return x * m_iSquareSideSize + z;
     }

I hope this save some time to someone having the same issue I had :)

Comment
whydoidoit

People who like this

1 Show 0 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

21 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Why can't a MonoBehaviour subtype with generic arguments be serialized in a list since Unity 4.5? 0 Answers

[SerializeField] Not Working Properly? 1 Answer

How to serialized a variable in a c# method? 1 Answer

Field not Serializing in a custom class 0 Answers

What would be the best way to go about loading and saving a Serializable object in JSON with Unity? 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges