1
\$\begingroup\$

In my Unity3D game I have blocks of the environment that are placed by script into the scene. Each block has some bezier paths created with this asset. I can access all points of the paths when I place the block into the scene but I would like store start and end points of these paths somewhere and be able to retrieve this data before I place the blocks into the scene.

The only solution I can currently think of is creating a scene which would run a script that would place all these blocks into the scene, one after another, store the data in a file and this file would then be loaded before the game starts. However this solution feels kinda hacky.

Is there any better way to obtain and store this data in Unity? Is it even possible to create the file and load it when the game starts and also add it to the built game?

\$\endgroup\$
  • \$\begingroup\$ Are these blocks saved as prefabs? Using the new prefab workflow, it's likely that you can write an editor script which opens the prefabs one-by-one, serializing each one's path data. \$\endgroup\$ – Chaosed0 Sep 12 at 19:30
  • \$\begingroup\$ Yes they are saved as prefabs. \$\endgroup\$ – Jakub Petriska Sep 12 at 19:35
  • \$\begingroup\$ Where would you save the data? \$\endgroup\$ – Jakub Petriska Sep 12 at 19:38
0
\$\begingroup\$

Assuming these two things:

  • The asset exposes some API from which you can read the data you need
  • Your "blocks" are saved as prefabs

Then you should be able to write an editor script to bake out the data into a format you can read at runtime without having to load the blocks.

Getting each block's path data

It looks like you can use PrefabUtility.LoadPrefabContents to obtain the block data. This will give you the root GameObject in the prefab, upon which you can use the normal Find/GetComponent methods to get to the bezier curve data.

If that doesn't work, you can use AssetDatabase.OpenAsset and PrefabStage to obtain your data.

Serializing the data

There's a couple of ways to do this. The easiest way is to save the data to a ScriptableObject. Simply create a subclass of ScriptableObject with serializable fields. At bake-time, create one of these assets, e.g. with the following code (from here):

        T asset = ScriptableObject.CreateInstance<T> ();

        string path = AssetDatabase.GetAssetPath (Selection.activeObject);
        if (path == "") 
        {
            path = "Assets";
        } 
        else if (Path.GetExtension (path) != "") 
        {
            path = path.Replace (Path.GetFileName (AssetDatabase.GetAssetPath (Selection.activeObject)), "");
        }

        string assetPathAndName = AssetDatabase.GenerateUniqueAssetPath (path + "/New " + typeof(T).ToString() + ".asset");

        AssetDatabase.CreateAsset (asset, assetPathAndName);

        AssetDatabase.SaveAssets ();
            AssetDatabase.Refresh();
        EditorUtility.FocusProjectWindow ();
        Selection.activeObject = asset;

Then you can modify the data contained inside. Make sure to use EditorUtility.SetDirty to mark it for saving after it's modified by your script.

At runtime, any objects which need that data can take a reference to that ScriptableObject (through inspector, Resources.Load or singleton pattern) and use the data accordingly.

Alternatively, if you don't like ScriptableObjects, you can always roll your own serialization using any of the various libraries out there. You can save the resulting file as a TextAsset and read it that way at runtime.

How do I start the bake?

To run this code, I'd use a MenuItem. Alternatively, if you have a collection of these utilities, you can create your own EditorWindow.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.