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 GameObject
escena, 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 RequireComponent
estos 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 Component
se puede eliminar un archivo al GameObject
que 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 GameObject
con dos componentes: Button
y PopupOpener
. PopupOpener
requiere que un Button
componente 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 Button
primero, pero no pudo, ya que depende del PopupOpener
componente. Esto arrojó un error. Luego intentó eliminar el PopupOpener
componente, 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 Button
componente restante , lo que ahora podría hacer, ya que PopupOpener
se 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.
Destroy
elimina el componente al final del marco (en lugar deImmediate
ly).DestroyImmediate
De todos modos, se considera un mal estilo, pero estoy pensando que cambiarDestroy
podría eliminar estos errores.Respuestas:
Definitivamente es posible, pero requiere bastante trabajo preliminar: puede verificar si hay un
Component
adjunto alGameObject
que tiene unAttribute
tipoRequireComponent
que 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
GameObjectExtensions
en 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
Component
derive deMonoBehaviour
oIPointerClickHandler
.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.Update
método.fuente