简体   繁体   中英

Populate Scriptable Objects Automatically

A few of my Scriptable Objects(used for seeding my initial game data) contain large 2 dimensional arrays (like 10x10), the data of which i am generating with an external Python script. I do use the Odin inspector plugin as well, to serialize the 2d array for me and provide me with a nice representation of that array inside the Unity editor.

I am simply doing it like this :

[TableMatrix()]
public int[,] table = new int[10, 10];

and this is just an Odin SerializedScriptableObject class.

The problem is, I really want to avoid having to add the 10x10 elements by hand using the Unity editor and also I want my objects to have variable 2d array sizes, one could beb (10,10), another could be (5,5). Is there a way to populate my scriptable objects programmatically to achieve that ? (Or does the Odin inspector plugin support something like that if anyone knows ?)

Thanks !

Sorry for the late response @Spyros.

My approach will be similar to @D Manokhin approach, but instead of using jagged array I'll use a multidimensional array (cause you can build a custom editor script to visualize them, I'm pretty sure you can visualize jagged arrays on editor without plugins, I've never used Odin plugin).

So I delcare one class who will store the structs called TileData :

using UnityEngine;
using System.Collections;

[System.Serializable]
public class TileData
{
    /*
     * rows
        [rowData][rowData][rowData]
        [cell]  ->value
                ->type
        [cell]  ->value
                ->type
        [cell]  ->value
                ->type
    */

    [System.Serializable]
    public struct cell
    {
        public float value;
        public string type;
    }


    [System.Serializable]
    public struct rowData
    {
        public cell[] row;
    }

    public rowData[] rows;

}

I used value and type as an "examples", it's absolutly up to you, you can also store Vector3 if you want!

Then, how to call and use this kind of structure? Let's see:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Matrix : MonoBehaviour {

    //declare the structure that will store the data
    public TileData tileData = new TileData();    

    //those are public so you could make the matrix with the size you want..
    //..ideally dynamically call it from your python file requisits
    public int horizontalMatrixSize = 10;  
    public int verticalMatrixSize = 10;

    // Use this for initialization
    void Start()
    {        
        //Create the matrix structure and fill it
        tileData.rows = new TileData.rowData[horizontalMatrixSize];
        for (int i = 0; i < tileData.rows.Length; i++)
        {
            tileData.rows[i].row = new TileData.cell[verticalMatrixSize];
            for (int u = 0; u < tileData.rows[i].row.Length; u++)
            {                
                tileData.rows[i].row[u].value = GetValuesFromPythonFileOrWhatever();
                tileData.rows[i].row[u].type = GetValuesFromPythonFileOrWhatever();
            }
        }
    }

}

But if you really like the jagged structure, you can still use it (but remember that will not be represented on editor) like this:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Matrix : MonoBehaviour {
    //declare the structure that will store the data
    [SerializeField] private float[,] grayscaleBidimensional = null;

    //those are public so you could make the matrix with the size you want..
    //..ideally dynamically call it from your python file requisits
    public int horizontalMatrixSize = 10;  
    public int verticalMatrixSize = 10;

    // Use this for initialization
    void Start()
    {        
        //Create the matrix structure and fill it
        tileData.rows = new TileData.rowData[horizontalMatrixSize];

        grayscaleBidimensional = new float[horizontalMatrixSize, verticalMatrixSize];
        for (int x = 0; x < horizontalMatrixSize; x++)
        {
            for (int y = 0; y < verticalMatrixSize; y++)
            {
                grayscaleBidimensional[x, y] = GetValuesFromPythonFileOrWhatever();
            }
        }
    }

}

Remember that you can make the values of the objects as you want, so they don't need to have an static size!

To change an individual value, you can do table[x,y] = (your value) . Lets say you want to fill every value with the number one, you could do:

for (int y = 0; y < 10; y++)
{
    for (int x = 0; x < 10; x++)
    {
        table[x, y] = 1;
    }
}

Hope that answers your question and sorry if the code is wrong - I don't have access to Unity at the moment, so you may need to fiddle around with it.

You should serialize the arrays out to files in python, and then use a Scripted Importer to import them into Unity, construct the arrays in the ScriptableObject, and fill in their values.

https://docs.unity3d.com/Manual/ScriptedImporters.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM