How Can I Stop my Array Being Cleared on Runtime via Serialisation?
So I'm designing a robots simulation in Unity, which at the moment just instantiates a square grid and performs some A* pathfinding on it. The grid is instantiated via a custom editor so that I can then set up robots, obstacles, etc.
Before I press play, I have a NavGrid object which holds an array of its associated nodes (i.e. grid tiles). Note that these are of a custom class called Node rather than GameObjects. However, when runtime starts, the array is cleared and its length becomes zero.
I have tried serialising the array and the Node object but to no avail. My next thought would be to instantiate the Nodes as ScriptableObjects, but as they need to reference the GameObject to which they are attached, it looks like this is unfeasible. I think I'm missing something fundamental to serialisable variables, since I've difficulty believing this is really this awkward.
Any help would be appreciated.
NavGrid code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class NavGrid : MonoBehaviour
{
public int gridSize = 16; // size of the square grid
[SerializeField] public Node[] nodes;
public GameObject nodePreset;
public float nodeSize = 1; //size of square node in actual lentgh units
public void BuildGrid()
{
print("Hello");
if (Application.isPlaying)
{
Debug.Log("ERROR: Cannot build new grid at runtime.");
return;
}
for (int i = nodes.Length-1; i >= 0; i--)
{
nodes[i].DestroyNode();
}
nodes = new Node[gridSize*gridSize];
for (int i = 0; i < gridSize; i++)
{
for (int j = 0; j < gridSize; j++)
{
Vector3 nodePosition = new Vector3(j * nodeSize + nodeSize / 2, transform.position.y, i * nodeSize + nodeSize / 2);
GameObject g = Instantiate(nodePreset, nodePosition, Quaternion.Euler(-90, 0, 0), transform);
Node n = g.GetComponent<Node>();
n.associatedGrid = this;
n.id = j + i * gridSize;
n.Rescale(nodeSize);
n.SetGoal(false);
nodes[n.id] = n;
}
}
}
}
Node code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Node: MonoBehaviour
{
public int id;
public bool isGoal;
public bool isObstacle;
public int team;
public int priority;
public GameObject robotPrefab;
public NavGrid associatedGrid;
public Route asscociatedRoute;
public HolonomicRobot associatedRobot; //this will have to be changed to type 'robot' upon implementation of that class
public void DestroyNode()
{
DestroyImmediate(this.gameObject);
}
public void Rescale(float newSize)
{
float size = this.GetComponent<Renderer>().bounds.size.x;
Vector3 rescale = transform.localScale;
rescale.x = newSize * rescale.x / size;
rescale.y = newSize * rescale.y / size;
rescale.z = newSize * rescale.z / size;
transform.localScale = rescale;
}
public void ToggleGoal()
{
UnityEngine.Debug.Log($"Toggled node #{id} as isGoal.");
SetGoal(!isGoal);
}
public void SetGoal(bool trueFalse)
{
isGoal = trueFalse;
SpriteRenderer goalRenderer = gameObject.GetComponentsInChildren<SpriteRenderer>()[1];
goalRenderer.enabled = trueFalse;
string setRemovedString = (isGoal) ? "Set" : "Removed";
UnityEngine.Debug.Log($"{setRemovedString} goal at node #{id}.");
}
public void ToggleRobot()
{
bool robotPresent = associatedRobot != null;
SetRobot(!robotPresent);
UnityEngine.Debug.Log($"Toggled robot on node #{id}.");
}
public void SetRobot(bool trueFalse)
{
//if false, check if associated robot exists and destroy if so
//if true, spawn robot directly on tile and make it associated robot
string setRemovedString = (trueFalse) ? "Created" : "Destroyed";
UnityEngine.Debug.Log($"{setRemovedString} robot at node #{id}.");
if (!trueFalse) {
DestroyImmediate(associatedRobot.gameObject);
associatedRobot = null;
}
else if(associatedRobot == null)
{
GameObject g = Instantiate(robotPrefab, transform.position + Vector3.up * 0.1f , Quaternion.identity);
associatedRobot = g.GetComponent<HolonomicRobot>();
associatedRobot.currentNode = this;
associatedRobot.associatedGrid = this.associatedGrid;
} else
{
UnityEngine.Debug.Log($"ERROR: Robot already present at node #{id}.");
}
}
public void ToggleObstacle() {
SetObstacle(!isObstacle);
}
public void SetObstacle(bool trueFalse)
{
isObstacle = trueFalse;
SpriteRenderer s = gameObject.GetComponent<SpriteRenderer>();
s.color = trueFalse ? new Color(80f/255f, 68f/255f, 68f/255f, 1f): new Color(1f, 1f, 1f, 1f);
}
}
Your answer
Follow this Question
Related Questions
How to save a two-dimensional array, as part of the variable inspector? 0 Answers
Array of custom classes not saving to Playmode 0 Answers
A script behaviour has a different serialization layout... 7 Answers
HideFlags and Prefabs 1 Answer
Undo Redo Custom Editor Error ("Assertion failed on expression: '!GetUndoManager().IsProcessing()'") 0 Answers