Developing a game in Unity, I'm making liberal use of [RequireComponent(typeof(%ComponentType%))]
to ensure components have all dependencies met.
I'm now implementing a tutorial system which highlights various UI objects. To do the highlighting, I'm taking a reference to the GameObject
in the scene, then I clone it with Instantiate() and then recursively strip away all components which aren't needed for display. The problem is that with the liberal use of RequireComponent
in these components, many cannot be simply removed in any order, since they are depended on by other components, which have not been deleted yet.
My question is: Is there a way to determine whether a Component
can be removed from the GameObject
it is currently attached to.
The code I'm posting technically works, however it throws Unity errors (not caught in try-catch block, as seen in the image
Here's the code:
public void StripFunctionality(RectTransform rt)
{
if (rt == null)
{
return;
}
int componentCount = rt.gameObject.GetComponents<Component>().Length;
int safety = 10;
int allowedComponents = 0;
while (componentCount > allowedComponents && safety > 0)
{
Debug.Log("ITERATION ON "+rt.gameObject.name);
safety--;
allowedComponents = 0;
foreach (Component c in rt.gameObject.GetComponents<Component>())
{
//Disable clicking on graphics
if (c is Graphic)
{
((Graphic)c).raycastTarget = false;
}
//Remove components we don't want
if (
!(c is Image) &&
!(c is TextMeshProUGUI) &&
!(c is RectTransform) &&
!(c is CanvasRenderer)
)
{
try
{
DestroyImmediate(c);
}
catch
{
//NoOp
}
}
else
{
allowedComponents++;
}
}
componentCount = rt.gameObject.GetComponents<Component>().Length;
}
//Recursive call to children
foreach (RectTransform childRT in rt)
{
StripFunctionality(childRT);
}
}
So the way this code generated the last three lines of the debug log above is the following: It took as input a GameObject
with two components: Button
and PopupOpener
. PopupOpener
requies that a Button
component is present in the same GameObject with:
[RequireComponent(typeof(Button))]
public class PopupOpener : MonoBehaviour
{
...
}
The first iteration of the while loop (denoted by the text "ITERATION ON Button Invite(clone)") attempted to delete the Button
first, but couldn't as it is depended on by the PopupOpener
component. this threw an error. Then it attempted to delete the PopupOpener
component, which it did, since it is not depended on by anything else. In the next iteration (Denoted by the second text "ITERATION ON Button Invite(clone)"), it attempted to delete the remaining Button
component, which it now could do, since PopupOpener
was deleted in the first iteration (after the error).
So my question is whether it is possible to check ahead of time if a specified component can be removed from its current GameObject
, without invoking Destroy()
or DestroyImmediate()
. Thank you.
Destroy
removes the component at the end of the frame (as opposed toImmediate
ly).DestroyImmediate
is considered bad style anyways, but I'm thinking switching toDestroy
may actually eliminate these errors. \$\endgroup\$