Разрабатывая игру в Unity, я свободно использую ее, [RequireComponent(typeof(%ComponentType%))]
чтобы обеспечить соответствие всех компонентов.
Сейчас я реализую учебную систему, которая выделяет различные объекты пользовательского интерфейса. Чтобы сделать выделение, я беру ссылку на GameObject
сцену, затем клонирую ее с помощью Instantiate () и затем рекурсивно удаляю все компоненты, которые не нужны для отображения. Проблема заключается в том, что при свободном использовании RequireComponent
этих компонентов многие не могут быть просто удалены в любом порядке, поскольку они зависят от других компонентов, которые еще не были удалены.
Мой вопрос: есть ли способ определить, Component
можно ли удалить объект из того, к которому GameObject
он прикреплен.
Код, который я публикую, технически работает, однако он выдает ошибки Unity (не зафиксированные в блоке try-catch, как видно на рисунке).
Вот код:
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);
}
}
Таким образом, этот код сгенерировал последние три строки в журнале отладки, описанные выше: он принимается в качестве входных данных GameObject
с двумя компонентами: Button
и PopupOpener
. PopupOpener
требует, чтобы Button
компонент присутствовал в том же GameObject с:
[RequireComponent(typeof(Button))]
public class PopupOpener : MonoBehaviour
{
...
}
Первая итерация цикла while (обозначается текстом «Кнопка приглашения ITERATION ON (клон)») пыталась удалить Button
первую, но не смогла, так как это зависит от PopupOpener
компонента. это бросило ошибку. Затем он попытался удалить PopupOpener
компонент, что он и сделал, так как от него больше ничего не зависит. На следующей итерации (обозначается вторым текстом «Кнопка приглашения ITERATION ON (клон)») она попыталась удалить оставшийся Button
компонент, который он теперь мог сделать, поскольку он PopupOpener
был удален на первой итерации (после ошибки).
Поэтому мой вопрос заключается в том, можно ли заранее проверить, можно ли удалить указанный компонент из его текущего GameObject
, без вызова Destroy()
или DestroyImmediate()
. Спасибо.
Destroy
удаляет компонент в конце кадра (в отличие от Immediate
ly). DestroyImmediate
в любом случае считается плохим стилем, но я думаю, что переключение на Destroy
может на самом деле устранить эти ошибки.