[XNA] Detección de colisiones en un mundo 3D (Episode III)

Continuando con el ejemplo del episodio anterior, por fin aplicaremos detección de colisiones al nivel 3D que hemos generado para “el videojuego”. Tenemos un XML en el que se definen los objetos BoundingBox y BoundingSphere que se usarán en el nivel para la detección de colisiones contra el mismo, tenemos también un mundo que se carga a partir de este XML… y tenemos además un robot que se mueve con animaciones propias por este mundo tridimensional. ¿Qué nos falta ahora? Es bien sencillo… detectar las colisiones entre el robot y el mundo! Es decir, hacer que el robot no pueda “traspasar las paredes” como lo hacía en el vídeo anterior. Lo que vamos a conseguir es lo siguiente:

Superados los pasos anteriores, añadir esta funcionalidad no va a ser demasiado difícil…  lo primero que haré es asegurarme de que se rendericen los boundingbox y boundingsphere cuando lo necesite. En un videojuebo “en producción” obviamente estos objetos no se renderizan, pero durante el desarrollo puede ser muy útil, con objeto de debugación. Y además, en nuestro caso tenemos que definir la posición de los boundings en un XML sin un editor de niveles visual… así que nos será muy útil poder ver donde queda cada bounding, así será más fácil editar dicho XML. Así pues el código sería el siguiente:

   1: public void Draw(GameTime gameTime, Matrix vista, Matrix proyeccion) 

   2: {

   3:     // Pintar modelos

   4:     foreach (ObjetoInerte modelo in nivel.modelosMundo)

   5:     {

   6:         modelo.Draw(gameTime, vista, proyeccion);

   7:     }

   8:  

   9:     if (Configuracion.Debug)

  10:     {

  11:         // Pintar cajas

  12:         BoundingBoxRender renderCaja = new BoundingBoxRender();

  13:  

  14:         foreach (BoundingBox caja in nivel.boundingBoxes)

  15:         {

  16:             renderCaja.Render(caja, Configuracion.graficos, vista, proyeccion, Color.Orange);

  17:         }

  18:  

  19:         // Pintar esferas

  20:         BoundingSphereRender renderEsfera = new BoundingSphereRender();

  21:  

  22:         foreach (BoundingSphere esfera in nivel.boundingSpheres)

  23:         {

  24:             renderEsfera.Render(new BoundingSphere(esfera.Center, esfera.Radius), Configuracion.graficos, vista, proyeccion, Color.Orange);

  25:         }

  26:     }            

  27: }

 

¿Algo extraño? Supongo que habréis observado la existencia de una instancia de una clase que se llama BoundingBoxRender y otra BoundingSphereRender. Esta es una clase que permite renderizar BoundingBox y BoundingSpheres respectivamente (con ese nombre nádie lo diría eh? :-P). Estas son clases sencillas pero extermadamente útiles, que supongo que bajé algun día de Ziggyware (snif, snif, esa web “ha muerto…”). Pues bien, esta pequeña clase nos ayudará a debugar nuestros juegos.

Ahora que tenemos los boundings cargados y pintándose… hay que comprobar si el robot colisiona contra ellos. Para ello añadiré algunas líneas al método que ya existía en el ejemplo anterior: LeerInput.

   1: Vector3 posicionInicial;

   2:  

   3: posicionInicial = base.transformacionRaiz.ObtenerMundo().Translation;

Básicamente aquí guardo la posición del robot antes de aplicarle todas las transformaciones. El método Matrix.Translation permite obtener la posición de la misma en un vector 3D.

Aplicamos las transformaciones pertinentes a las matrices, tal y como hacíamos en el ejemplo anterior, todavía dentro de LeerInput, y comprobaremos si tras las mismas existe colisión entre el robot y el mundo. Si eso ocurre, devolvemos al robot a su posición inicial antes de leer el input de teclado. ¡El resultado es que el robot ya no puede atravesar las paredes!

   1: if (nivel.HayColision(this.esfera))

   2: {

   3:     base.transformacionRaiz.Traslacion.Translation = posicionInicial;

   4:     this.esfera.Center = Posicion + desplazamiento;

   5: }

El método “HayColision” no hace magia… simplemente recorre los boundings del nivel para ver si hay colisión contra el boundingsphere que tiene el propio robot.

   1: public bool HayColision(BoundingSphere bounding) 

   2: {

   3:     foreach (BoundingSphere boundingSphereCheck in boundingSpheres)

   4:     { 

   5:         if(boundingSphereCheck.Intersects(bounding))

   6:             return true;

   7:     }

   8:     foreach(BoundingBox boundingBoxCheck in boundingBoxes)

   9:     {

  10:         if (boundingBoxCheck.Intersects(bounding))

  11:             return true;

  12:     }

  13:  

  14:     return false;

  15: }

Importante: En un juego “real” tendríamos que limitar la comprobación de colisiones de alguna manera. Existen múltiples formas, y en uno de mis artículos hablaba de una de ellas, así que para no repetirme os dejo con el enlace.

Como siempre… os dejo aquí el código del ejemplo calentito para descargar.

4 comentarios en “[XNA] Detección de colisiones en un mundo 3D (Episode III)”

  1. Hay muchas cosas que no entiendo ..sobretodo la parte del serializado en XML.. por favor sube el código al igual que en los ejemplos anteriores….no esta el link..lo olvidaste!!!

  2. Estoy haciendo un proyecto con colisiones con esferas, con dos modelos uno con el original y otro con las esferas , despues los dibujo los dos , y me realiza las colisiones, pero en mi modelo hay como una rampa y con las esferas no se como hacer que suba, ¿como podria hacer para que pueda subir la rampa?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *