Crear un sensor volumétrico en Unity es sencillo: añades un componente Collider a un Transform, lo configuras como trigger, le das forma al Collider para definir el alcance del sensor, y añades un script al Transform que implemente los métodos OnTriggerEnter y OnTriggerExit. El Collider se encargará de activar esos métodos cuando otro collider entre o salga de su alcance, respectivamente.
Eso es todo, y suele bastar en la mayor parte de las ocasiones, pero hay otras en las que tenemos que definir la forma del sensor volumétrico en tiempo real, durante la ejecución del juego. Imagina, por ejemplo, que quieres dotar de un sensor volumétrico a un agente móvil para que detecte obstáculos que se puedan interponer en su rumbo. Lo normal será que pongas un sensor volumétrico con forma de caja delante del agente y que dicha caja se alargue hacia delante del agente a lo largo de una distancia proporcional a la velocidad del agente. Si la caja es demasiado corta, es probable que se detecten los obstáculos demasiado tarde como para que el agente pueda evitar la colisión. Si la caja es demasiado larga, el agente puede reaccionar a obstáculos demasiado lejanos, lo que sería poco realista.
Un agente móvil con un sensor volumétrico para detectar obstáculos |
Si el agente mantiene siempre una velocidad constante, nos bastará fijar manualmente el tamaño del sensor al diseñar el agente. Pero si el agente varía su velocidad, dependiendo de su comportamiento, es probable que no nos valga un único tipo de sensor para todas las posibles velocidades. En ese casos podríamos dotar al agente de varios sensores, con diferentes tamaños, y activar unos u otros en función de la franja de velocidad en la que se encuentre el agente. Sin embargo, esa solución será muy compleja y muy difícil de escalar si acabamos cambiando el abanico de velocidades del agente. Es mucho mejor si modificamos el tamaño del sensor durante la ejecución y lo adaptamos a la velocidad del agente en cada momento.
Te voy a explicar cómo lo hago yo con un BoxCollider2D. No digo que sea la mejor manera de hacerlo, pero sí que es la mejor manera con la que he dado hasta el momento. Te resultará fácil adaptar mis ejemplos a otras formas de collider y usarlo como punto de partida para encontrar el mecanismo que mejor se adapte a tu caso.
Un BoxCollider2D permite cambiar su tamaño a través de su propiedad size. Esta consiste en un Vector2 cuya primera componente define el ancho y la segunda la altura de la caja. Podemos cambiar el valor de esta propiedad en cualquier momento y el collider adaptará su forma a ella. El problema es que el BoxCollider se mantendrá centrado y crecerá en ambas direcciones de la componente que hayamos modificado. Si tenemos un caso como el de la captura de antes, lo que querremos es que el collider crezca hacia adelante, cuando aumentemos la velocidad, y no que el collider crezca también hacia la parte trasera del agente.
La manera de resolverlo es modificar la dimensión que nos interese, en el caso del agente de la captura será la altura de la caja, y al mismo tiempo desplazar la caja, manipulando su offset, para que parezca que sólo crece por uno de sus lados. En el ejemplo que nos ocupa, para hacer crecer el sensor, aumentaríamos la altura de la caja y al mismo tiempo desplazaríamos su offset hacia arriba para mantener el lado inferior de la caja en el mismo punto y que pareciese que sólo crece por el lado superior.
![]() |
Queremos que el collider crezca sólo por uno de sus lados |
Partiendo de lo anterior, voy a mostrarte el código que uso para generalizar los diferentes casos posibles para una caja. Para un BoxCollider, las modificaciones de tamaño posible son las del enum de la siguiente captura:
Posibles direcciones de crecimiento de una caja |
Las opciones se explican por si mismas: "Up" implica que queremos que la caja crezca solamente por su lado superior, "Down" por el inferior, "Left" por el lado de la izquierda y "Right" por el de la derecha. "Symmetric" viene a ser el comportamiento por defecto según el cual, al cambiar la altura la caja crecería tanto por su lado superior como por el inferior.
La cuestión es que, cuando aumentas el tamaño de una caja en una de sus dimensiones, dicho aumento se reparte equitativamente en un crecimiento de los dos lados de esa dimensión. Por ejemplo, si aumentas el tamaño de la altura de una caja en 2 unidades, puedes esperar que el lado superior ascienda una unidad y el inferior baje otra. Por tanto, si quisieras que la caja aparentase crecer sólo por el lado superior, deberías mantener el inferior en el mismo punto haciendo que la caja ascendiese una unidad.
La manera de generalizarlo es que la caja debe moverse la mitad del aumento de tamaño en la dirección de crecimiento que le hayamos marcado.
Cómo calcular el vector de movimiento de la caja |
El vector de movimiento de la caja se puede obtener de un método como el anterior (GetGrowOffsetVector). En el caso de nuestro ejemplo, en el que queremos que la caja aparente crecer por el lado superior, y que el inferior permanezca en su posición, el growDirection sería "Up" por lo que el método devolvería un Vector2 con los valores (0, 0.5). Fíjate que he definido OffsetBias como una constante de valor 0.5. Ese vector se multiplicará luego por el vector de crecimiento de la caja, lo que nos dará el desplazamiento de la caja.
El vector de crecimiento es el vector resultante de restarle al nuevo tamaño de la caja el tamaño que tenía inicialmente.
Cálculo del vector de crecimiento |
Por tanto, cada vez que queramos cambiarle el tamaño a la caja tendremos que calcular el vector de crecimiento y multiplicarlo por el vector de movimiento de la caja para obtener el nuevo ofsset de la caja para que aparente que sólo se ha movido por uno de sus lados.
Método para cambiar el tamaño de la caja |
El método SetBoxSize(), en el que implemento lo anterior, no puede ser más sencillo. En sus líneas 153 y 154 reseteo la caja a su tamaño inicial (1,1) y su offset a (0,0). Como el nuevo tamaño se fija acto seguido, el reseteo es instantáneo y no llega a percibirse.
Luego, en la línea 155 ejecuto el método GetGrowOffsetVector(), para obtener el vector de movimiento de la caja. Y en la línea 156, obtengo el vector de crecimiento al llamar al método GetGrowVector(). Ambos vectores se multiplican en la línea 158, para dar lugar al nuevo offset de la caja. Observa en esa misma línea, la 158, que utilizo el campo initialOffset (de tipo Vector2) para definir un offset por defecto de la caja. Ese será el offset que tendrá la caja cuando no se le haya aplicado movimiento alguno.
Fíjate también que utilizo el campo boxCollider para manipular las propiedades del collider. Este campo cuenta con una referencia a dicho collider. Puedes obtener esa referencia, bien exponiendo el campo en el inspector y arrastrando el collider sobre ese campo, o bien usando una llamada a GetComponent() en el Ready() del script.
Si incluyes los métodos anteriores en un script, y haces que este exponga métodos públicos, que acaben llamando a SetBoxSize() podrás manipular el tamaño del collider en tiempo real desde otros scripts del juego.
Y con esto ya lo tienes todo. Es bastante sencillo cuando ya lo tienes claro, pero si partes desde cero te puede llevar un rato hasta averiguar cómo hacerlo. Espero que este artículo te haya ahorrado ese rato y que te haya parecido interesante.