jsonunity-game-enginenested-for-loopjson-arrayagg

Write a JSON file with cubePosition Data to spawn a 10x10x10 cube


Here I'm trying to write a code that can write and create a JSON File for me with the data I provide like row, column and depth. For example, I need to spawn a 10 x 10 x 10 cube. And I give this data in unity Inspector also in the code when I'm serializing it. I tried achieving this in a for loop and writing the JSON file. But I'm not getting the output I wanted. I am expecting output where the cube locations are different and in place what happens instead is all the data or cube position in my data is the one before the number I give. that is if I gave my row, column, and depth to be 10. So my data is like x: 9, y: 9, z:9 for the whole 1000 elements.Better explained in image down below.I know I'm doing a mistake at some point just not able to figure out where. Thanks for the help in Advance

Image Reference of what I'm expecting vs how my output is coming

public class JSONWriter : MonoBehaviour
{
       
    [SerializeField] int rows , columns, depth = 10;
        
    [SerializeField] float padding;
        
    public enum CubeType
        
    {
            
    white,
            yellow,
            blue,
            red,
            green
        
    }

    private readonly IReadOnlyDictionary<CubeType, Color> colors = new Dictionary<CubeType, Color>
    {
        {CubeType.white, Color.white},
        {CubeType.yellow, Color.yellow},
        {CubeType.blue, Color.blue},
        {CubeType.red, Color.red},
        {CubeType.green, Color.green}
    };

    [System.Serializable]
    public class CubeData
    {
        public Vector3 cubePosition;
        public CubeType Cube;
    }
    
    [System.Serializable]
    public class CubeDataList
    {
        public CubeData[] cubeDatas;
    }

    public void outputJSON()
    {
        string strOutput = JsonUtility.ToJson(myCubeDataList);
        File.WriteAllText(Application.dataPath + "/Resources/10x10x10.txt", strOutput);
    }

    //CubeData myCubeData = new CubeData();
    public CubeDataList myCubeDataList = new CubeDataList();

    void Start()
    {
        for (int x = 0; x < myCubeDataList.cubeDatas.Length; x++)
        {
            //Debug.Log(myCubeDataList.cubeDatas.Length);
            for (int i = 0; i < depth; i++)
            {
                for (int j = 0; j < columns; j++)
                {
                    for (int k = 0; k < rows; k++)
                    {
                        myCubeDataList.cubeDatas[x].cubePosition = new Vector3(i, j, k) * padding;
                        //myCubeDataList.cubeDatas[x].Cube = Random.Range(CubeType, 3f);
                    }
                }
            }
        }
    }
}

Solution

  • You do not want to go through all i, j, k for each and every element x!

    What you are doing is basically overwriting each and every element with the values for i=9, j=9, k=9.


    Instead of an array I would rather simply use a dynamic List like

    [Serializable]
    public class CubeDataList
    {
        public List<CubeData> cubeDatas;
    }
    

    and then dynamically add them via

    myCubeDataList.cubeDatas = new List<CubeData>(i * j * k);
       
    for (int i = 0; i < depth; i++)
    {
        for (int j = 0; j < columns; j++)
        {
            for (int k = 0; k < rows; k++)
            {
                var data = new CubeData();
       
                data.cubePosition = new Vector3(i, j, k) * padding;
                data.Cube = Random.Range(CubeType, 3f);
    
                myCubeDataList.cubeDatas.Add(data);
            }
        }
    }
        
    

    Or if you really want to go with an array

    for (int i = 0; i < depth; i++)
    {
        for (int j = 0; j < columns; j++)
        {
            for (int k = 0; k < rows; k++)
            {
                var data = new CubeData();
       
                myCubeDataList.cubeDatas[x].cubePosition = new Vector3(i, j, k) * padding;
                myCubeDataList.cubeDatas[x].Cube = Random.Range(CubeType, 3f);
    
                x++;
            }
        }
    }
        
    

    Though, from your previous question I know you actually do not want to fill the cube completely!

    You actually only want the external shape (like a wall) and leave the cube empty on the inside.

    So what you actually want would probably rather be

    myCubeDataList.cubeDatas = new List<CubeData>(i * j * k);
       
    for (int i = 0; i < depth; i++)
    {
        for (int j = 0; j < columns; j++)
        {
            for (int k = 0; k < rows; k++)
            {
                if(i == 0 || i == depth - 1 
                   || j == 0 || j == depth - 1
                   || k == 0 || k == depth - 1)
                {
                    var data = new CubeData();
                    data.cubePosition = new Vector3(i, j, k) * padding;
                    // TODO random enum (see below)
    
                    myCubeDataList.cubeDatas.Add(data);
                }
            }
        }
    }
    

    For the random enum vlaue see e.g. this answer and do

    private Random random = new Random();
    

    and then where it says // TODO insert

    var values = Enum.GetValues(typeof(Bar));
    data.Cube = (CubeType)values.GetValue(random.Next(values.Length));