Está en la página 1de 6

Programacin de videojuegos con XNA

Leccin 4: Colisiones pxel a pxel

Leccin 4

Bienvenido! En esta leccin vamos a continuar con el concepto de las colisiones que introdujimos en la leccin 3. Si completaste la leccin anterior pudiste notar que algunas colisiones no eran bastante realistas, pues aunque el personaje no tocaba la bala la colisin se daba. Esto, como lo explicamos en la leccin anterior, se debe a que la colisin se estaba dando entre los rectngulos que representaban cada una de las 2 imgenes en colisin. El siguiente paso para hacer nuestro juego mas realista es cambiar el sistema de colisiones por uno mas sofisticado, esto es, las colisiones pxel a pxel 1. En un sistema de colisiones pxel a pxel, se considera que se ha presentado una colisin, solo cuando 2 pxeles no transparentes hacen contacto (figura 1). Debemos recordar que los pxeles transparentes son aquellos que pintamos con el color magenta, pues por defecto el manejador de imgenes de XNA puede interpretar este color como transparente.

Figura 1 La colisin se da solo cuando los pxeles no transparentes entran en contacto

El objetivo principal de esta leccin es el de mejorar el juego que habamos construido en la leccin anterior, reemplazando la lgica de colisiones entre rectngulos por una entre pxeles. Paso 1: obtener los datos de las imgenes. Una colisin pxel a pxel requiere que todos y cada uno de los pxeles de las texturas que estn en la zona de contacto, sean evaluados para ver si se dio una colisin (figura 2).

Un pxel es la menor unidad en la que se descompone una imagen digital. Los pxeles se puede hacer notorios cuando haces zoom sobre una imagen hasta el punto en que se empieza a ver cuadriculada.

Manuel Echeverry

Pgina 1 de 6

Programacin de videojuegos con XNA

Leccin 4: Colisiones pxel a pxel

Figura 2 Zona de contacto en naranja. Los pxeles de esta zona son los que se evalan para ver si hay colisin

La forma de acceder a cada pxel de una textura se realiza por medio del mtodo Texture2D.GetData el cual nos entrega un arreglo en el que cada casilla es el color que representa cada pxel. Un arreglo no es mas que la forma mas sencilla de coleccin que existe en C#. Imagina un arreglo como una fila de casillas finito. En este caso se define un arreglo de colores del tamao exacto que sea el nmero de pxeles de la imagen. Es decir una imagen de 10 pxeles de alto por 20 de ancho tiene 10 x 20 = 200 pxeles por lo que necesitaramos un arreglo de colores de 200 casillas. 1. al inicio de la clase game1 (debes trabajar sobre la clase que dejamos hecha en la leccin 3) coloca las siguientes lneas.
// Los arreglos de colores para el personaje y para la bala Color[] datosTexturaPersona; Color[] datosTexturaBala;

2. a continuacin vamos a usar el mtodo Texture2D.GetData sobre cada textura para obtener los datos del color y almacenarlos en el arreglo correspondiente. Por lo tanto, debemos realizar este paso despus de cargar las imgenes en el mtodo LoadGraphicsContent, que tenamos listo desde la leccin 3 (las lneas nuevas estn en negrilla).
protected override void LoadGraphicsContent(bool loadAllContent) { if (loadAllContent){ // Cargar las texturas texturaBala = content.Load<Texture2D>("Content/Block"); texturaPersona = content.Load<Texture2D>("Content/Person"); // Tamao del arreglo = # pixeles Ancho x # pixeles Alto datosTexturaBala = new Color[texturaBala.Width * texturaBala.Height]; // Extraer los datos de los colores y colocarlos en el arreglo texturaBala.GetData(datosTexturaBala); // Tamao del arreglo = # pixeles Ancho x # pixeles Alto

Manuel Echeverry

Pgina 2 de 6

Programacin de videojuegos con XNA

Leccin 4: Colisiones pxel a pxel

datosTexturaPersona = new Color[texturaPersona.Width * texturaPersona.Height]; // Extraer los datos de los colores y colocarlos en el arreglo texturaPersona.GetData(datosTexturaPersona); // Crear el sprite batch para dibujar las texturas spriteBatch = new SpriteBatch(graphics.GraphicsDevice); } }

Paso 2: Escribir un mtodo para evaluar las colisiones. Ahora que ya tenemos toda la informacin necesaria para evaluar la colisin, vamos a escribir un mtodo que va a recibir los rectngulos que representan las 2 imgenes y los 2 arreglos de colores. El contenido de cdigo de este mtodo va mas all de las expectativas de esta leccin por lo que puede copiarlo y pagarlo simplemente y usarlo en tu juego; no obstante voy a dar algunas nociones sobre su funcionamiento. 1. aade el siguiente encabezado de mtodo en cualquier lugar dentro de la clase juego.
static bool EvaluaPixels(Rectangle rectanguloA, Color[] datosA, Rectangle rectanguloB, Color[] datosB){ }

2. aade el siguiente cdigo al inicio del mtodo.


// Hallar zona de contacto int ariba = Math.Max(rectanguloA.Top, rectanguloB.Top); int abajo = Math.Min(rectanguloA.Bottom, rectanguloB.Bottom); int izquierda = Math.Max(rectanguloA.Left, rectanguloB.Left); int derecha = Math.Min(rectanguloA.Right, rectanguloB.Right);

Aqu se trata de hallar las coordenadas de la zona de contacto (figura 2). Puede resultar confusa la forma como se halla, esto se debe a que el plano cartesiano que maneja XNA es como lo vimos en la leccin 2 (figura 3) La coordenada arriba (figura 4) representa el punto y ms alto de la zona de contacto, que en nuestro plano cartesiano de XNA es el tope del rectngulo B. (la funcin MAX evala el mayor de ambos topes y B es el mayor por la forma como funciona el plano cartesiano). La coordenada abajo representa el punto y ms bajo de la zona de contacto, que en nuestro plano cartesiano de XNA es el suelo del rectngulo A. Se sigue el mismo procedimiento para hallar derecha e izquierda.

Manuel Echeverry

Pgina 3 de 6

Programacin de videojuegos con XNA

Leccin 4: Colisiones pxel a pxel

Figura 3 A la izquierda un plano cartesiano tradicional, a la derecha un plano cartesiano de la forma como se interpreta en XNA

Figura 4 A la izquierda partes del rectngulo A, a la derecha partes de la zona de contacto entre A y B

3. completa el mtodo para que luzca as (las nuevas lneas estn en negrita):
static bool EvaluaPixels(Rectangle rectanguloA, Color[] datosA, Rectangle rectanguloB, Color[] datosB){ // Hallar zona de contacto int arriba = Math.Max(rectanguloA.Top, rectanguloB.Top); int abajo = Math.Min(rectanguloA.Bottom, rectanguloB.Bottom); int izquierda = Math.Max(rectanguloA.Left, rectanguloB.Left); int derecha = Math.Min(rectanguloA.Right, rectanguloB.Right); // verificar cada pixel de la zona de contacto for (int y = arriba; y < abajo; y++){ for (int x = izquierda; x < derecha; x++){ // obtener el color de los 2 pixeles Color colorA = datosA[(x - rectanguloA.Left) + (y - rectanguloA.Top) * rectanguloA.Width]; Color colorB = datosB[(x - rectanguloB.Left) + (y - rectanguloB.Top) * rectanguloB.Width]; //verificar si los 2 colores son transparenrtes if (colorA.A != 0 && colorB.A != 0){ // de no ser trasnparentes hay colisin return true;

Manuel Echeverry

Pgina 4 de 6

Programacin de videojuegos con XNA } } } // no hay colisin return false; }

Leccin 4: Colisiones pxel a pxel

El mtodo completo contiene algunos conceptos de programacin algo avanzados por lo que como dije antes puede obviarlos, sin embargo para los curiosos repasemos 2 puntos principales que hay aqu. - Primero miremos los dos ciclos repetitivos for. Como puedes ver hay uno dentro de otro, a esto se le llama un siclo anidado (se pueden anidar tantos como se quieran). Un siclo anidado tiene el siguiente comportamiento. El ciclo exterior de n repeticiones se repite n veces mientras el ciclo interior de m repeticiones se repetir n x m veces. En el caso de este ejemplo los ciclos anidados se usan para evaluar cada punto y (ciclo externo) con cada punto x (ciclo interno) formando as una pareja (x,y) en cada ciclo hasta evaluar todas las parejas de la zona de contacto. - Segundo, la palabra reservada return, como su nombre lo indica, se usa para retornar el valor que se espera del mtodo (en este caso un valor booleano). Cuando la sentencia return se ejecuta el mtodo se termina; por lo que en el caso del ejemplo si estamos a la mitad de la secuencia de los ciclos anidados y se cumple la condicin del if entonces se retorna true y no se continan evaluando los pxeles.

Paso 3: Invocar el mtodo EvaluaPixels Ahora que ya hemos escrito el mtodo que nos va a evaluar si existe colisin o no en cualquier instante, solo nos resta usarlo. Para esto vamos a reemplazar la lgica de colisin entre rectngulos que tenamos de la leccin anterior. 1. Modifica el mtodo Update del juego para que luzca de la siguiente manera (las lneas que cambiaron estn en negrilla).
// actualizar cada bala colision = false; for (int i = 0; i < posicionesBalas.Count; i++){ // animar la bala cayendo posicionesBalas [i] = new Vector2(posicionesBalas [i].X, posicionesBalas[i].Y + velocidadBalas); // obtener el rectangulo de la bala Rectangle rectanguloBala = new Rectangle((int) posicionesBalas[i].X, (int) posicionesBalas[i].Y, texturaBala.Width, texturaBala.Height); // evaluar colisin con el personaje if (EvaluaPixels(rectanguloPersona, datosTexturaPersona,

Manuel Echeverry

Pgina 5 de 6

Programacin de videojuegos con XNA rectanguloBala, datosTexturaBala)){ colision = true; }

Leccin 4: Colisiones pxel a pxel

// eliminar las balas cuando salen de la pantalla if (posicionesBalas[i].Y > Window.ClientBounds.Height){ posicionesBalas.RemoveAt(i); // decrecemos i, por que hay un bloque menos i--; } }

2. Eso es todo. Compila y corre el juego. Podrs notar como las colisiones ahora son 100% precisas

Algunas ideas para mejorar el juego: - Crea varias balas de diferentes formas y tamaos y escoge una diferente de manera aleatoria, cada vez que hagas aparecer una nueva bala. - Crea un grupo de tems especiales que el personaje debe recoger para aumentar una puntuacin.

Manuel Echeverry

Pgina 6 de 6

También podría gustarte