Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question GameObject -> UI -> Prefab in custom package

Discussion in 'Editor & General Support' started by c8theino, Feb 12, 2021.

  1. c8theino

    c8theino

    Joined:
    Jun 1, 2019
    Posts:
    20
    I am trying to create a script which adds my "DebugMenu" prefab to the create menu. When the script is fully functional I am going to move it to my custom package. Because of that I can't use Resources for loading the prefab nor can I use a Monobehaviour Singleton class, which holds the prefab reference in scene.

    I found this script from Unity forums which creates an empty GameObject from the create menu, in which you can add components to the Gameobject. Doing it this way is not really a preferrable option, since the gameobject which I want to create (prefab) has multiple child objects and scripts.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. /// <summary>
    5. /// Class that creates the Debug Menu.
    6. ///
    7. /// Credits to mirkojpn: https://forum.unity.com/threads/create-custom-ui-menu.739580/
    8. /// </summary>
    9. public static class DebugMenuItem {
    10.     /// <summary>
    11.     /// Creates a new item on UI to create Debug Menu object.
    12.     /// </summary>
    13.     [MenuItem("GameObject/UI/Debug Menu")]
    14.     static void CreateDebugMenu() {
    15.         // Create new Object then assign it's name
    16.         GameObject menu = new GameObject("DebugMenu");
    17.  
    18.         // Add RectTransform
    19.         menu.AddComponent<RectTransform>();
    20.  
    21.         // if no object is active on the editor go to create one
    22.         if (Selection.activeGameObject == null) {
    23.             // Get the Canvas Reference
    24.             Canvas canvas = GameObject.FindObjectOfType<Canvas>();
    25.  
    26.             // if Canvas Exists
    27.             if (canvas != null) {
    28.                 // Set object as child of it
    29.                 menu.transform.SetParent(canvas.transform);
    30.                 menu.transform.localPosition = Vector3.zero;
    31.             }
    32.         } else {
    33.             // else set the active object as parent of it
    34.             menu.transform.SetParent(Selection.activeGameObject.transform);
    35.         }
    36.  
    37.         // register root object for undo
    38.         Undo.RegisterCreatedObjectUndo(menu, "Create Debug Menu");
    39.  
    40.         // Set the activeobject in the editor as the created object
    41.         Selection.activeGameObject = menu;
    42.     }
    43. }
    So is there any way for me to get a reference to the prefab in the Editor script? Can I somehow reference it using its path if for example my package structure is like this:
    Code (text):
    1.  
    2. Package/
    3.     Editor/
    4.         DebugMenuItem.cs
    5.     Prefabs/
    6.         DebugMenu.prefab
    7.  
    Note: I already know how to make a custom package, so I don't need any help with that.
     
    Last edited: Feb 12, 2021
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,888
    Can you use a ScriptableObject which has a reference to your prefab?
     
  3. rigodev

    rigodev

    Joined:
    May 30, 2022
    Posts:
    1
    Any updates?
     
  4. c8theino

    c8theino

    Joined:
    Jun 1, 2019
    Posts:
    20
    Use this function to get the complete path to prefab:
    Code (CSharp):
    1. /// <summary>
    2. /// Finds complete path to provided path.
    3. ///
    4. /// Note: The more precise you are the less likely there will be "multipath" errors,
    5. /// but on the other hand if you change any directory name in your path,
    6. /// you will get "no path found" errors.
    7. /// </summary>
    8. /// <param name="assetStaticPath">static unchanging path to the asset (example: Prefabs/Prefab.asset)</param>
    9. /// <returns>found path, null if not found or found multiple</returns>
    10. public static string GetAssetPath(string assetStaticPath) {
    11.     List<string> foundPaths = new List<string>();
    12.     var allAssetPaths = AssetDatabase.GetAllAssetPaths();
    13.     var fileName = assetStaticPath;
    14.     for (int i = 0; i < allAssetPaths.Length; ++i) {
    15.         if (allAssetPaths[i].EndsWith(fileName))
    16.            foundPaths.Add(allAssetPaths[i]);
    17.     }
    18.  
    19.     if (foundPaths.Count == 1)
    20.         return foundPaths[0];
    21.  
    22.     if (foundPaths.Count == 0) {
    23.         Debug.LogError($"No path found for asset {assetStaticPath}!");
    24.     } else if (foundPaths.Count > 1) {
    25.         Debug.LogError($"Multiple paths found for asset {assetStaticPath}, use more precise static path!");
    26.  
    27.          for (int i = 0; i < foundPaths.Count; i++) {
    28.              string path = foundPaths[i];
    29.              Debug.LogError($"Path {i + 1}: {path}");
    30.          }
    31.      }
    32.  
    33.     return null;
    34. }
    And then instantiate a new object from the prefab like this:
    Code (CSharp):
    1. string path = EditorTools.GetAssetPath("Prefabs/Prefab.asset");
    2. GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(path, typeof(GameObject));
    3. GameObject obj = Object.Instantiate(prefab);