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.
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"));