Skip to content

Instantly share code, notes, and snippets.

@techanon
Last active January 13, 2021 01:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save techanon/379e22c964118f044974c7bb38e6ada4 to your computer and use it in GitHub Desktop.
Save techanon/379e22c964118f044974c7bb38e6ada4 to your computer and use it in GitHub Desktop.
Type-agnostic transform depth-search algorithm for any component within Udon, just change 'MyComponent' the type you are looking for.
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
public class GetMyComponents : UdonSharpBehaviour
{
public GameObject[] roots;
[HideInInspector] public MyComponent[] comps;
void Start() {
var i = 0;
var _comps = traverseAllFor(typeof(MyComponent), roots);
// traverse methods always return Component[], loop and cast.
comps = new MyComponent[_comps.Length];
for (i = 0; i < _comps.Length; i++) {
comps[i] = (MyComponent) _comps[i];
}
// additional initialization here
}
// Your other stuff for the class can go here
private Component[] traverseAllFor(System.Type T, GameObject[] objects)
{
var elements = new Component[objects.Length];
var index = 0;
log("Searching nodes for " + T);
foreach (GameObject obj in objects)
{
if (obj == null) continue;
log("Traversing node " + obj.name);
Component[] found = traverseFor(T, obj.transform);
foreach (Component element in found)
{
if (element == null) continue;
// check if next index exceeds bounds, expand if so
if (index >= elements.Length)
elements = expand(elements, 16);
elements[index] = element;
index++;
}
}
// remove excess nulls
var clean = new Component[index];
for (int i = 0; i < clean.Length; i++) {
clean[i] = elements[i];
}
elements = clean;
log("Total found: " + elements.Length);
return elements;
}
private Component[] traverseFor(System.Type T, Transform root)
{
Component[] elements = new Component[16];
Component[] stack = new Component[16];
stack[0] = root;
var found = 0;
while (stack[0] != null)
{
var cur = (Transform)pop(stack);
// log("Gathering elements within node " + cur.name);
if (cur != null)
{
var t = cur.GetComponent(T);
if (t != null)
{
found++;
elements = push(elements, t);
}
// add all children to stack in reverse order
for (int i = cur.childCount - 1; i >= 0; i--)
stack = push(stack, cur.GetChild(i));
}
}
if (found > 0) log("Found " + found + " matching component(s)");
return elements;
}
private Component[] push(Component[] stack, Component n)
{
var added = false;
for (int i = 0; i < stack.Length; i++)
{
if (stack[i] == null)
{
stack[i] = n;
added = true;
break;
}
}
// unable to add due to stackoverflow, expand stack and retry
if (!added)
{
stack = expand(stack, 16);
for (int i = 0; i < stack.Length; i++)
{
if (stack[i] == null)
{
stack[i] = n;
added = true;
break;
}
}
}
return stack;
}
private Component pop(Component[] stack)
{
// find first non-null entry in the stack, remove and return.
var last = -1;
for (int i = 0; i < stack.Length; i++)
{
var item = stack[i];
if (item != null) last = i;
if (item == null) break;
}
if (last == -1) return null;
var t = stack[last];
stack[last] = null;
return t;
}
private Component[] expand(Component[] arr, int add)
{
// expand beyond size of self if children are found
var newArray = new Component[arr.Length + add];
var index = 0;
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] == null) continue;
newArray[index] = arr[i];
index++;
}
return newArray;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment