Home > Net >  Unity-How to make recursive function return correct value that only if condition is true
Unity-How to make recursive function return correct value that only if condition is true

Time:08-04

what I want to achieve is convert the relationship between current selected object and it's specific parent to path pattern in hierarchy window.For example, from the screenshot, the Test_01 and Test_02 is the specific parent, and if the current selected obj is ABBB under Test_01, then I will have a path like Test_01/AB/ABB/ABBB, my code is below, my problem is because the function findPathInScence is recursive, the variable pt seems only can get the first value it return, like the pt always empty but scenePath always what I want. How to make the function return the value only when if is true? please help.structure in hierarchy result

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

public class Test
{
    string tempPath;
    private string findPathInScence(GameObject gs)
    {

        string scenePath = "";
        if (gs.name.Contains("Test"))
        {
            scenePath = gs.name   tempPath;
            Debug.Log("scenePath:  "   scenePath);
            tempPath = "";

        }
        else
        {
            tempPath = "/"   gs.name   tempPath;
            findPathInScence(gs.transform.parent.gameObject);
        }
        return scenePath;
    }

    [MenuItem("GameObject/printPath", false, 20)]
    static void printPathInScene()
    {
        Test t = new Test();
        string pt = t.findPathInScence(Selection.activeGameObject);
        Debug.Log("pt:    "   pt);
    }
}

CodePudding user response:

Issue

In the case that your object does not match Test you set

scenePath = "";

and then regardless of the result of the recursive findPathInScence you simply return

return scenePath;

unlike the tempPath which is a field the scenePath is a local variable only existent during the individual run of the method.

The last recursive call for the object Test_01 actually returns the correct path, however you do not use it anywhere!

=> For any selected object that has not Test the return value is always empty!


Solution with recursion

If you really want to go recursive you have to properly get the path of the recursive run correctly. You could do it like e.g.

public static class TransformExtensions
{
    public static string GetScenePath(this Transform transform, string stopIfContains, StringBuilder path = null)
    {
        if (path == null)
        {
            path = new StringBuilder();
        }

        if (gs.name.Contains(stopIfContains))
        {
            var scenePath = path.Insert(0, transform.name);
            Debug.Log($"{nameof(scenePath)}: {scenePath}");
            return scenePath.ToString();
        }

        path.Insert(0, gs.name).Insert(0, '/');
        return GetScenePath(transform.parent, path);
    }
}

and

Debug.Log("pt:    "   Selection.activeGameObject.transform.GetScenePath("Test"));

Solution without recursion

But why even use recursion?

You can simply bubble up in a loop which is way easier to understand, maintain and debug.

like e.g. (source)

public static class TransformExtensions
{
    public static string GetScenePath(this Transform transform)
    {
         string path = transform.name;

         while (transform.parent != null)
         {
             transform = transform.parent;
             path = transform.name   "/"   path;
         }

         return path;
     }
}

or maybe without so many string concatenations

public static class TransformExtensions
{
    public static string GetScenePath(this Transform transform)
    {
         var sb = new StringBuilder(transform.name);

         while (transform.parent != null)
         {
             transform = transform.parent;
             sb.Insert(0, '/').Insert(0, transform.name);
         }

         return sb.ToString();
     }
}

now you can simply call

Debug.Log("pt:    "   Selection.activeGameObject.transform.GetScenePath());

Or with your additional exit strategy (name match)

public static class TransformExtensions
{
    public static string GetScenePath(this Transform transform, string stopIfContains)
    {
         var sb = new StringBuilder(transform.name);

         while (transform.parent != null && !transform.name.Contains(stopIfContains))
         {
             transform = transform.parent;
             sb.Insert(0, '/').Insert(0, transform.name);
         }

         return sb.ToString();
     }
}

and

Debug.Log("pt:    "   Selection.activeGameObject.transform.GetScenePath("Test"));
  • Related