Por eso, hay nodos que, de hecho, no pueden aportar funcionalidad completa si no se ven complementados por otros nodos que se cuelguen de ellos. Un ejemplo clásico es el nodo RigidBody3D, el cual no puede funcionar si no se ve complementado por un CollisionShape3D que defina su forma física.
Godot ofrece un sistema de alertas para avisarte de que un nodo depende de otro para poder funcionar. Lo habrás visto muchísimas veces. Se trata de un triángulo de aviso amarillo que muestra una explicación si pasas el ratón por encima.
Mensaje de aviso de que falta un nodo hijo |
Cuando desarrollas escenas en Godot, estas se convierten en nodos dentro de otras. Si te tomas en serio, los principios del buen diseño, y separas responsabilidades, antes o después te encontrarás diseñando nodos que dependan de otros nodos para personalizarse.
Al llegar a ese punto es cuando sueles preguntarte si tú también puedes emitir alertas si a alguno de tus nodos le falta un nodo complementario. La respuesta es que sí, se puede hacer y te voy a enseñar cómo.
Por ejemplo, supongamos que tenemos un nodo denominado MovingAgent. Su implementación da igual, pero para ilustrar el ejemplo vamos a suponer que ese nodo define las características de movimiento (velocidad, aceleración, frenada, etc) de un agente. Para definir cómo queremos que el agente se mueva queremos implementar nodos con los diferentes algoritmos de movimiento (por ejemplo, en línea recta, zigzag, en inversa). Esos últimos nodos tienen implementaciones dispares, pero se comprometen a cumplir el interfaz ISteeringBehavior, ofreciendo una serie de métodos comunes que pueden ser llamados desde MovingAgent. Por tanto, el agente se moverá de una manera o de otra dependiendo del nodo (cumplidor de ISteeringBehavior) que colguemos de MovingAgent.
En este caso, nos interesará alertar de esa dependencia al usuario del nodo MovingAgent en caso de que lo use sin un nodo ISteeringBehavior que cuelgue de él.
Para alertar de esa dependencia, todos los nodos bases de Godot ofrecen el método _GetConfigurationWarnings(). Si queremos que el nuestro lance avisos sólo tenemos que implementar dicho método. En el caso de MovingAgent, este podría hacer la siguiente implementación;
Implementación de _GetConfigurationWarnings() |
El método espera devolver un array con todos los mensajes describiendo los errores que se hayan detectado (línea 148). En caso de que Godot vea que el método devuelve un array vacío, entonces interpretará que todo está correcto y no sacará el icono de alerta.
Como verás, lo primero que hace el método es mirar si el nodo MovingAgent tiene un nodo hijo que implemente ISteeringBehavior (línea 149). En caso de que no encontrar hijo alguno con esas características (línea 154), se genera un mensaje de error (línea 156).
No hay razón para que nos limitemos a comprobar un único tipo de nodo. Podemos buscar múltiples nodos, comprobar sus configuraciones y generar múltiples mensajes de error, mientras que guardemos los mensajes de error generados en un array que luego podamos devolver como resultado del método.
En este ejemplo, guardo los mensajes de error en una lista (línea 152) que convierto en un array antes de finalizar el método (línea 159).
_GetConfigurationWarnings() se ejecuta en las siguientes situaciones:
- Cuando se adjunte un nuevo script al nodo.
- Cuando se abra una escena que contenga al nodo.
- Cuando se cambie alguna propiedad en el inspector del nodo.
- Cuando se actualice el script que cuelga del nodo.
- Cuando se cuelga un nuevo nodo del que tiene el script.
Y ya está no tiene más misterio... o quizás sí. Los lectores atentos pueden haberse dado cuenta de que en la línea 150 he buscado un nodo hijo sólo por su tipo. Los que desarrollen en Unity estarán acostumbrados a buscar componentes por tipo porque este engine ofrece un método nativo para hacerlo (GetComponent<T>()). Sin embargo, Godot no ofrece ningún método para buscar por tipo. Las implementaciones nativas de FindChild buscan nodos por nombre y no por tipo. Eso era una molestia para mí porque quería poder colgar de MovingAgent nodos con diferentes nombres, identificativos de funcionalidad, mientras cumpliesen el interfaz ISteeringBehavior. Así que, a falta de un método nativo, he implementado uno que lo hiciese a través de un extension method:
Extension method para ofrecer búsqueda de nodos hijos por tipo |
El extension method recorre todos los nodos hijos (línea 20) y comprueba si son del tipo que se ha pasado como parámetro (línea 22).
En caso de localizar un nodo del tipo buscado, lo devuelve y finaliza el método (línea 24). En caso contrario puede seguir haciendo búsquedas recursivas en los nodos hijos de nuestros hijos (línea 28), si así se lo hemos pedido vía parámetros (línea 26).
Gracias a este extension method, cualquier instancia de una clase de Godot que herede de Node (¿hay alguna que no lo haga?) nos ofrecerá la posibilidad de hacer búsquedas por tipos, como en la línea 150 de _GetConfigurationWarnings().
En tu caso, puede que te valga con buscar por nombre a los nodos hijos. Si no es así, puede que la solución del extension method, para buscar por tipo, te encaje mejor. Es la única complejidad que le veo a este sistema de alertas que, por lo demás, es extremadamente sencillo de usar.
Alerta resultante de nuestra implementación |