1. Cpu 2
ai l
to
GI
UA J td .
e ui l
s o c
Po rmai d v e je o
rga c n e i o u g s
ó d
J s In c Aa s
oe g ai l
o mo J v r eee R i
a i L tlr u
e i z
2. Capitulo
Colisiones, Dinamismo y animaciones..
En la entrega anterior, aprendimos el esquema básico de un juego simple
(bastante, diría yo). En ésta tocaremos el tema de las colisiones, el dinamismo
de los juegos, y la animación. Por otro lado, analizaremos sistemas más óptimos
de programación.
Ya sabemos la teoría del movimiento, de las entradas, y todas esas
parafernalias. Sin embargo, necesitamos una serie de conceptos que harán
posible el desempeño de un juego. El primer concepto es la colisión.
¿Qué demonios es una colisión?
Nos referimos a una colisión a la intersección o unión de 2 o más objetos en un
juego.
Supongamos que estamos programando un juego estilo Pong Arcade. La bola
debe saber si ha “chocado” con el bate, con las paredes, o con las fichas. Este
“choque” es analizado y comprobado por un sistema de colisiones.
Analizaré 2 sistemas de colisión: El primero basado en colisión circular, y el
segundo en colisión rectangular. En futuras entregas, analizaremos un sistema
de colisión perfecta basado en la detección de imágenes sobrepuestas.
Colisión circular:
Más de alguno ha escuchado hablar sobre el teorema de Pitágoras, fórmula útil
para obtener el lado restante en un triángulo rectángulo.
3. a2 + b2 = c2
Donde a y b son los catetos, y c es la hipotenusa.
Imaginemos que tenemos 2 puntos en un plano, uno con coordenadas ( x1 , y1 ) ,
el segundo con coordenadas ( x 2 , y 2 ) . Podemos obtener la distancia entre estos
puntos utilizando un plano cartesiano y éste conocido teorema: Si en uno de los
puntos trazamos una recta paralela al eje X, y en el otro trazamos otra paralela
al eje Y, veremos que hay un punto de intersección, y que el ángulo de esta
intersección es 90º (definición del plano cartesiano). Si creamos un segmento
desde el primer punto hasta la intersección, y otro segmento desde la
intersección hasta el segundo punto, notaremos que estos segmentos, cumplen
los requisitos para ser catetos de un triángulo rectángulo. Por lo tanto, la
distancia entre estos puntos, es la hipotenusa de éste triángulo.
Podemos obtener las medidas de los catetos (pues el primero es x 2 − x1 , y el
segundo es y 2 − y1 ). Conociendo esto, podemos reemplazar la información en la
fórmula original:
( x 2 − x1 ) 2 + ( y 2 − y1 ) 2 = dist 2
Donde dist es la distancia entre los 2 puntos.
Aplicando raiz cuadrada en ambos lados, podemos despejar la variable dist,
pero en términos computacionales, no es necesario: Si el lado izquierdo de la
ecuación es menor o igual al lado derecho de la ecuación, entonces hay
colisión. No es necesario calcular con raiz cuadrada la distancia en todos los
ciclos, pues, quitaría recursos.
En resumen, hay colisión, si el cuadrado de la suma de ambas diferencias de
los componentes X e Y son menores o iguales al cuadrado de la suma de los
radios de ambos objetos
4. Por ejemplo, supongamos que tenemos 2 objetos circulares, uno de radio 5, y el
otro de radio 3. Habrá colisión si la distancia de los centros de ambos objetos es
menor o igual a 8.
Implementación:
Booleano Colisión
Objeto PLAYER
{
Entero X, Y
Entero Radio // Podría no ser entera esta variable, depende del caso
}
PLAYER jugador1, jugador2
Función InicializarTodo()
{
jugador1.x = jugador1.y = 30 // las coordenadas del jugador 1 serán (30,
30), por dar un ejemplo
jugador2.x = 100
jugador2.y = 20
// Las del jugador 2, serán (100, 20)
jugador1.Radio = 5
jugador2.Radio = 3
Colision=False
}
Función EntradayProcesamiento()
{
Si (Usuario_aprieta_izquierda())
{
Jugador1.x = Jugador1.x Ð 1
}
5. Si (Usuario_aprieta_derecha())
{
Jugador1.x = Jugador1.x + 1
}
Si (Usuario_aprieta_arriba())
{
Jugador1.y = Jugador1.y Ð 1
}
Si (Usuario_aprieta_abajo())
{
Jugador1.y = Jugador1.y + 1
}
Colisión=DetectarColision(Jugador1, Jugador2)
}
Función DetectarColision(OBJETO Jugador1, OBJETO Jugador2) // Válida. Si no
acomoda, pasa los 6 argumentos (Radios, Coordenadas)
{
Si ( ( (Jugador2.x-Jugador1.x)* (Jugador2.x-Jugador1.x) ) + ( (Jugador2.y-
Jugador1.y)* (Jugador2.y-Jugador1.y) ) <=
(Jugador1.Radio+Jugador2.Radio)*(Jugador1.Radio+Jugador2.Radio) )
{
//Colisión detectada. Devolvemos True
Devolver True;
//Return true en la mayoría de los lenguajes
}
//Si no pasa nada, devolvemos False
Return False
}
Función Salida()
{
Dibujar_en_pantalla(IMAGEN_DEL_JUGAGOR_1, Jugador1.x, Jugador1.y)
6. Dibujar_en_pantalla(IMAGEN_DEL_JUGAGOR_2, Jugador2.x, Jugador2.y)
Si (Colisión == True)
{
MostrarTexto(“Los objetos están colisionando”)
}
}
Función Principal (argumentos) // Entrada del programa, función main
{
InicializarTodo()
Mientras (Usuario_No_Presione_ESC())
{
EntradayProcesamiento()
Salida()
}
}
Este es el esquema básico de un sistema de colisión circular. Es bastante útil en
los juegos.
Sin embargo, en otros casos podríamos necesitar un tipo de colisión
rectangular.
Colisión Rectangular:
Este método es parecido al sistema “Bounding Box”, sin embargo, es más
optimizado, y requiere solo las coordenadas de los objetos, sus anchos y sus
alturas.
Imaginemos que hay 2 cuadrados en un plano, que no están colisionando. Al
centro de cada cuadrado, hay un punto actúa como pivote central (es decir, la
7. coordenada del cuadrado es relativa a ese punto). ¿Qué condición se debe
cumplir, para que ambos cuadrados colisionen?
Simple. Al igual que en el caso anterior de la colisión circular, generemos las
rectas perpendiculares a los ejes, para generar los catetos de un triángulo
rectángulo.
A la vista, podemos ver que habrá colisión si se cumplen 2 condiciones:
* Que la medida del cateto paralelo al eje X sea menor o igual que la suma de
las distancias de los centros a cualquier lado paralelo al eje Y, de ambos
cuadrados.
* Que la medida del cateto paralelo al eje Y sea menor o igual que la suma de
las distancias de los centros a cualquier lado paralelo al eje X, de ambos
cuadrados.
Si se cumplen estas condiciones, entonces existe colisión rectangular.
Implementación:
Booleano Colisión
Objeto PLAYER
{
Entero X, Y
Entero Alto
Entero Ancho
}
PLAYER jugador1, jugador2
Función InicializarTodo()
{
jugador1.x = jugador1.y = 30 // las coordenadas del jugador 1 serán (30,
30), por dar un ejemplo
jugador2.x = 100
8. jugador2.y = 20
// Las del jugador 2, serán (100, 20)
jugador1.Alto = 20
jugador2.Alto = 30
jugador1.Ancho = 20
jugador2.Ancho = 40
Colision=False
}
Función EntradayProcesamiento()
{
Si (Usuario_aprieta_izquierda())
{
Jugador1.x = Jugador1.x Ð 1
}
Si (Usuario_aprieta_derecha())
{
Jugador1.x = Jugador1.x + 1
}
Si (Usuario_aprieta_arriba())
{
Jugador1.y = Jugador1.y Ð 1
}
Si (Usuario_aprieta_abajo())
{
Jugador1.y = Jugador1.y + 1
}
Colisión=DetectarColision(Jugador1, Jugador2)
}
Función DetectarColision(OBJETO Jugador1, OBJETO Jugador2) // Válida. Si no
acomoda, pasa los 6 argumentos (Radios, Coordenadas)
9. {
Entero Dist1_x, Dist1_y // Almacenaran las distancias del centro del
primer cuadrado hasta ambos lados
Entero Dist2_x, Dist2_y // Almacenaran las distancias del centro del
segundo cuadrado hasta ambos lados
// Calculamos las distancias de los centros de cada cuadrado
Dist1_x = Jugador1.Ancho / 2
Dist1_y = Jugador1.Alto / 2
Dist2_x = Jugador2.Ancho / 2
Dist2_y = Jugador2.Alto / 2
// Planteamos ambas condiciones
Si( (Jugador2.x Ð Jugador1.x) <= ( Dist1_x + Dist2_x) Y (Jugador2.y Ð
Jugador1.y) <= ( Dist1_y + Dist2_y)
{
//Colisión detectada. Devolvemos True
Devolver True; //Return true en la mayoría de los lenguajes
}
//Si no pasa nada, devolvemos False
Return False
}
Función Salida()
{
Dibujar_en_pantalla(IMAGEN_DEL_JUGAGOR_1, Jugador1.x, Jugador1.y)
Dibujar_en_pantalla(IMAGEN_DEL_JUGAGOR_2, Jugador2.x, Jugador2.y)
Si (Colisión == True)
{
10. MostrarTexto(“Los objetos están colisionando (Utilizando colisión
rectangular)”)
}
}
Función Principal (argumentos) // Entrada del programa, función main
{
InicializarTodo()
Mientras (Usuario_No_Presione_ESC())
{
EntradayProcesamiento()
Salida()
}
}