Al desarrollar un juego en Unity, estoy haciendo un uso liberal [RequireComponent(typeof(%ComponentType%))]para asegurar que los componentes tengan todas las dependencias satisfechas.
Ahora estoy implementando un sistema tutorial que destaca varios objetos de la interfaz de usuario. Para resaltar, tomo una referencia a la GameObjectescena, luego la clono con Instantiate () y luego elimino recursivamente todos los componentes que no son necesarios para mostrar. El problema es que con el uso liberal de RequireComponentestos componentes, muchos no pueden eliminarse simplemente en cualquier orden, ya que dependen de otros componentes que aún no se han eliminado.
Mi pregunta es: ¿Hay alguna manera de determinar si Componentse puede eliminar un archivo al GameObjectque está conectado actualmente?
El código que estoy publicando técnicamente funciona, sin embargo, arroja errores de Unity (no atrapados en el bloque try-catch, como se ve en la imagen
Aquí está el código:
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);
}
}
Entonces, la forma en que este código generó las últimas tres líneas del registro de depuración anterior es la siguiente: tomó como entrada a GameObjectcon dos componentes: Buttony PopupOpener. PopupOpenerrequiere que un Buttoncomponente esté presente en el mismo GameObject con:
[RequireComponent(typeof(Button))]
public class PopupOpener : MonoBehaviour
{
...
}
La primera iteración del bucle while (denotado por el texto "ITERATION ON Button Invite (clone)") intentó eliminar el Buttonprimero, pero no pudo, ya que depende del PopupOpenercomponente. Esto arrojó un error. Luego intentó eliminar el PopupOpenercomponente, lo que hizo, ya que no depende de nada más. En la siguiente iteración (Denotado por el segundo texto "ITERATION ON Button Invite (clone)"), intentó eliminar el Buttoncomponente restante , lo que ahora podría hacer, ya que PopupOpenerse eliminó en la primera iteración (después del error).
Entonces, mi pregunta es si es posible verificar con anticipación si un componente específico se puede eliminar de su actual GameObject, sin invocar Destroy()o DestroyImmediate(). Gracias.


Destroyelimina el componente al final del marco (en lugar deImmediately).DestroyImmediateDe todos modos, se considera un mal estilo, pero estoy pensando que cambiarDestroypodría eliminar estos errores.Respuestas:
Definitivamente es posible, pero requiere bastante trabajo preliminar: puede verificar si hay un
Componentadjunto alGameObjectque tiene unAttributetipoRequireComponentque tiene uno de susm_Type#campos asignables al tipo de componente que está a punto de eliminar. Todo envuelto en un método de extensión:después de soltar
GameObjectExtensionsen cualquier parte del proyecto (o, alternativamente, convertirlo en un método regular en el script), puede verificar si un componente puede eliminarse, por ejemplo:Sin embargo, puede haber otros medios para crear un objeto GUI no interactivo: por ejemplo, convertirlo en textura, superponerlo con un panel casi transparente que interceptará los clics o deshabilitará (en lugar de destruir) todo lo que se
Componentderive deMonoBehaviouroIPointerClickHandler.fuente
catch, registrar, continuar) en lugar de prevenir fallas (es decirif, posible, entonces). Sin embargo, eso no es mucho estilo C # (como uno en esta respuesta). Al final, su código original podría haber estado más cerca de cómo se hacen las cosas normalmente ... y la mejor práctica es cuestión de preferencia personal.En lugar de eliminar los componentes del clon, puede deshabilitarlos configurándolos
.enabled = false. Esto no activará las comprobaciones de dependencia, ya que no es necesario habilitar un componente para cumplir con la dependencia.Updatemétodo.fuente