.NET Tutorial 16. Colisiones 2D

Vamos a ver lo sencillo que resulta realizar "colisiones" en 2D bajo .NET

Para este ejemplo controlaremos un "caza de combate" que tendrá que destruir al típico "final boss" de casi cualquier juego de "naves". Hete aquí una foto del resultado de este tutorial:


(Haz click para agrandar la imagen)

Tal y como ya hemos visto en tutoriales anteriores, en cualquier sprite 2D tendremos lo siguiente:

  • Un sprite, independientemente de la "forma" que tenga, será siempre un "rectángulo".
  • Siempre deberemos tener en cuenta la coordenada superior izquierda, que tomaremos como "origen" del sprite.
  • También tendremos que tener en cuenta el "ancho" y el "alto" del sprite.

Teniendo en cuenta estos 3 puntos, la "región" o contorno de nuestros sprites serán los siguientes:


(Haz click para agrandar la imagen)

Como podéis ver, los rectangulos rojo y naranja representan toda el "área" que ocupan nuestros sprites en la pantalla de juego.

A bote pronto (y sobre todo depende de la "forma" de los sprites) con estas dos "áreas" (o regiones) podríamos llegar a calcular la colisión. Para ello, lo único que tendríamos que ver es si cualquiera de las dos "áreas" está dentro de la otra.

¿Y esto cómo se hace?

Pues fácil, con la función Rectangle.Intersect

Rectangle.Intersect devuelve un objeto de tipo "Rect" si existe una "intersección" entre dos "áreas"

El uso es tremendamente simple:

Dim isectRect As Rectangle = Rectangle.Intersect(rectBoss, rectPlayer)

Si hay "intersección", el alto y ancho de isectRect serán distintos de 0. En caso contrario no hay intersección entre rectBoss y rectPlayer.

Recordar que un objeto de tipo "Rect" se define como:

  1. Origen coordenada X
  2. Origen coordenada Y
  3. Ancho
  4. Alto

De ahí lo de "recordar" la coordenada superior izquierda (X,Y) y el ancho y alto del sprite.

Bien, como hemos dicho, este método nos serviría si los sprites fuesen "más o menos" de forma rectangular.

Como esto no será siempre así podríamos llegar a situaciones como la de esta foto:


(Haz click para agrandar la imagen)

En esta imagen, si que hay "intersección" entre el "área" del sprite de nuestra nave (rectángulo rojo) y el área del sprite del boss (rectángulo naranja)

Obviamente ahí vemos claramente que la nave (o el boss) realmente no se están tocando entre si, por lo tanto, esa situación no debería considerarse como "colisión".

La solución para este "problema" es "parametrizar" una seríe de regiones que actuarán como las regiones de colisión, utilizando para ello también la función Rectangle.Intersect

En nuestro ejemplo hemos definido las siguientes regiones (tanto para el boss como para nuestra nave):


(Haz click para agrandar la imagen)

Cuando dos de estás "regiones" tienen intersección es cuando consideramos que hay colisión:


(haz click para agrandar la imagen)

Como habréis comprobado esta técnica es tremendamente simple a la par que efectiva.

Existen más métodos de colisión, por ejemplo lo que se conoce como "Pixel Perfect Collisión", dónde aquí la colisión si que se realiza al "milímetro" o mejor dicho "al pixel".

 

PD: Antes de que nadie diga nada, este ejemplo se usa para mostraros la colisión por regiones, YA SÉ que la nave se mueve "lenta" y el boss también. El tema de velocidad lo solucionaremos en las próximas entregas utilizando para ello hilos (Threads).

PD 2: Sigo recordando que el botón de comentarios no muerde 😉

 

Saludos.
mov eax,ollydbg; Int 13h  

Descargar proyecto .NET Tutorial 16
(129 KB. Visual Studio 2008)

Controles:

  • Cursores para mover la nave
  • "C" para mostrar/ocultar el contorno de los sprites
  • "R" para mostrar/ocultar la regiones de colisión
  • "M" para que el boss se mueva automáticamente o se pare de mover
  • "H" para mostrar/ocultar el bitmap de fondo