Разрабатывая игру в 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
может на самом деле устранить эти ошибки.Ответы:
Это, безусловно , возможно, но это требует довольно много беготни: вы можете проверить, есть ли
Component
приложенные кGameObject
которой имеетAttribute
типа ,RequireComponent
который имеет одну из своихm_Type#
полей , присваиваемый типа компонента , который вы собираетесь удалить. Все завернуто в метод расширения:после удаления в
GameObjectExtensions
любом месте проекта (или, наоборот, сделать его обычным методом в сценарии), вы можете проверить, можно ли удалить компонент, например:Однако могут быть другие средства для создания неинтерактивного объекта GUI - например, рендеринг его в текстуру, наложение его на почти прозрачную панель, которая будет перехватывать щелчки или отключать (вместо того, чтобы уничтожать) все
Component
элементы, полученные изMonoBehaviour
илиIPointerClickHandler
.источник
catch
Е. Log, continue), а не предотвращает сбои (т. Е.if
Возможные, тогда). Это, однако, не так много стиля C # (например, один в этом ответе). В конце концов, ваш исходный код, возможно, был ближе к тому, как обычно это делается ... и наилучшая практика - это вопрос личных предпочтений.Вместо того, чтобы удалять компоненты клона, вы можете просто отключить их, установив
.enabled = false
их. Это не вызовет проверки зависимостей, потому что компонент не должен быть включен для выполнения зависимости.Update
метод.источник