- Home /
Why would pressing the play button delete or recreate a list elements?
I have MonoBehaviour with two lists for nodes and edges. Edge has links to nodes witch is ends of this. When i am creating edge it works currectly, but when i am pressing play button edge already has links to another copies of nodes... and it's all. So how can i fix it?
Edge class:
using System;
using UnityEngine;
[Serializable]
public class Edge {
public Node[] nodes = new Node[2];
}
Node class:
using System;
using UnityEngine;
[Serializable]
public class Node
{
public Vector3 position;
}
Graph class:
using System.Collections.Generic;
using UnityEngine;
public class Graph : MonoBehaviour {
public List<Node> nodes;
public List<Edge> edges;
}
GraphEditor class:
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Graph))]
public class GraphEditor : Editor {
Graph graph;
private Node selectedNode;
private Node connectedNode;
private float handleSize = 0.1f;
private float pickSize = 0.1f;
private void OnEnable()
{
selectedNode = null;
graph = (Graph)target;
}
private void OnSceneGUI()
{
var transform = graph.transform;
for (int i = 0; i < graph.edges.Count; i++)
{
var edge = graph.edges[i];
Handles.DrawLine(transform.TransformPoint(edge.nodes[0].position), transform.TransformPoint(edge.nodes[1].position));
}
for (int i = 0; i < graph.nodes.Count; i++)
{
var node = graph.nodes[i];
var point = transform.TransformPoint(node.position);
if (Handles.Button(point, Quaternion.identity, handleSize, pickSize, Handles.DotHandleCap))
{
selectedNode = node;
if (connectedNode != null)
{
var edge = new Edge { nodes = new Node[] { selectedNode, connectedNode } };
graph.edges.Add(edge);
connectedNode = null;
}
}
if (selectedNode == node)
{
EditorGUI.BeginChangeCheck();
point = Handles.DoPositionHandle(point, Quaternion.identity);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(graph, "Move Node");
node.position = transform.InverseTransformPoint(point);
EditorUtility.SetDirty(graph);
}
}
}
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
if (GUILayout.Button("Connect Nodes"))
{
Undo.RecordObject(graph, "Connect Nodes");
EditorUtility.SetDirty(graph);
connectedNode = selectedNode;
}
}
}
Before play: After:
Answer by Baroque · Apr 15, 2017 at 06:21 PM
It's important to realize that the serializer does not preserve references, except to subclasses of UnityEngine.Object
. When it serializes out a list of Node references it will save a copy of those nodes. You should read the serialization documentation carefully when trying to save complex data structures. This blog post is also extremely useful.
You have a couple of options:
You could change your system to be implemented in terms of ScriptableObject. You would have to manually register the newly constructed Nodes and Edges with the AssetDatabase but then you can store references to those objects from anywhere, including MonoBehaviours on scene objects.
Store the indices of the vertices in your Edge structure and use those to store a naturally serializable version of the data structure. You can always reconstruct the references as a post-serialization step for optimization purposes.
How complex you plan on making your system will dictate which choice makes most sense. If this is intended to be lightweight and simple then I would use the second approach. If you want more advanced features--for example, being able to store subclasses of your Node type--then I would go with the first.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
How to find the element index from a list in Unity Inspector 0 Answers
A node in a childnode? 1 Answer
Custom Editor DragAndDrop for List 1 Answer