Ejemplo práctico de programación inútil. Parte 2

24

Hace un par de días en Ejemplo práctico de programación inútil. Parte 1, explicaba que era posible hacer un programa que encestara por nosotros en el juego de basketball de onlinegames, hoy toca la prometida explicación. Así que vamos a ello.

Antes de empezar cabe señalar que el problema puede resolverse de distintas formas y esta es solo una de ellas.

La descripción del problema sería, dado un punto de origen o lanzamiento, calcular la trayectoria parabólica para alcanzar el destino o canasta, pasando por un punto intermedio que será la altura máxima de la trayectoria. Como puede verse en el dibujo, tendremos una posición origen conocida, una posición destino conocida y una posición intermedia que deberemos calcular.

Antes de empezar ha realizar cualquier cálculo, lo primero que deberemos hacer es averiguar cuales son las coordenadas de las posiciones inicial y final.

La canasta

Empezaremos por la canasta por ser la más fácil.
Identificar la posición de un elemento gráfico arbitrario siempre será por normal general, complicado. En este caso que sea estático simplifica muy mucho el problema. Si tomamos como premisa que el juego se realiza a pantalla completa y la resolución de nuestra pantalla siempre será la misma, lo más fácil en este caso es realizar un pantallazo y con un programa de dibujo (como photoshop), y ver cuales son las coordenadas del centro de la canasta.

Otra opción que nos serviría para un caso más general (que funcionara para distintas resoluciones de pantalla), sería por ejemplo crearnos un patrón y buscar la canasta hasta dar con ella. En mi caso opto por la primera opción.

La pelota

Este es un poco más complicado ya que será móvil y cada vez estará en un sitio distinto. Aquí se presentan múltiples opciones:

Una forma sería hacerlo manualmente: Antes de cada tiro, decirle al programa donde está la pelota. Esto podría hacerse con el ratón mismo y alguna combinación de teclas o modo de hotkeys.

La otra, y más elegante, que nuestro programa lo haga por si mismo. La estrategia en cualquier caso, será buscar por la pantalla donde está la pelota mediante algún patrón.
He visto que alguna gente (otros ya han echo programas similares para este juego) se basa en el echo que después de cada tiro, la nueva posición sale recuadrada con un marco blanco. Una solución sería buscar este marco blanco.

Yo por mi parte, me decanté por buscar la pelota directamente. Para ello utilicé concordancias en el color, que básicamente consiste en buscar algo de color naranja en pantalla. La implementación de esta solución ya depende de la habilidad y conocimientos de cada uno: puede hacerse buscando colores concretos o buscando el más similar a uno dado.

En cualquier caso, deberemos encontrar el centro de la pelota.

Disertaciones

El siguiente paso es observar la mecánica del juego.
Observamos que el dato que se le facilita al juego  para el lanzamiento (y que deberemos calcular) es el punto más alto de la trayectoria y que, para un mismo lanzamiento existen múltiples trayectorias.

Instintivamente también observamos que cuanto mayor el la altura del tiro, menor es el ángulo de ataque de la pelota con la canasta, lo cual facilita que entre por el aro. Este detalle lo tendremos en cuenta más adelante para simplificar los cálculos.

También observamos que la física aplicada a la simulación se rige por las fórmulas de tiro balístico o movimiento parabólico.

Cálculos

Ahora es el momento de repasar viejos conocimientos de física clásica.
Sabemos que en un movimiento parabólico, este consta de dos partes diferenciadas: el movimiento horizontal o eje X que será un movimiento continuo y, el movimiento vertical o eje Y que será uniformemente acelerado. Las fórmulas son las siguientes:

De estas formulas sabemos (ya que las hemos obtenido antes) cuales son las posiciones iniciales (coordenadas de la pelota) y las posiciones finales (coordenadas de la canasta). También sabemos que en el punto más alto de la trayectoria, la velocidad vertical es cero, de lo que podemos deducir la velocidad inicial vertical:

De esta forma, y substituyendo en la fórmula de posición, podemos calcular el tiempo que tardará la pelota en llegar a esta altura máxima Ym:

También sabemos cual fue la velocidad vertical inicial substituyendo t en la formula de la velocidad vertical, ya que recordemos que en este punto la velocidad es cero:

Con estos datos, sustituimos en la formula de movimiento vertical y obtenemos:

De esta fórmula (que describe el movimiento vertical que buscamos), despejaremos la variable del tiempo t. De esta forma sabremos cuanto tiempo ha tardado la pelota en llegar a su destino.

Observar que hay dos posibles soluciones. La que buscamos el la mayor de ellas. La explicación es sencilla: hay dos puntos en los que la trayectoria pasa por una posición Ym (altura) dada: la primera que estará cerca de la posición de lanzamiento y la segunda que será la de la canasta, y es la que buscamos. Esto siempre y cuando la posición de tiro esté por debajo de la canasta, en cuyo caso solo habrá una solución válida (real).

Ahora que ya sabemos la posición vertical en su punto máximo Ym y cuando tiempo tarda la pelota en llegar a la canasta, nos centraremos en los cálculos sobre el eje horizontal para calcular la posición de tiro.
Sabemos, como hemos dicho al principio, que el movimiento en el eje X es de velocidad constante. También sabemos la posición horizontal final (la canasta). Lo que no sabemos es cual es la velocidad inicial en este eje, así que despejamos la velocidad de la fórmula:

Ahora resumiendo un poco: sabemos cual es la velocidad inicial en el eje horizontal (en función de las posiciones finales e iniciales en el eje X, y también sabemos la expresión del tiempo), la posición inicial horizontal y cuanto tiempo tarda en llegar la pelota al punto más alto. Si sustituimos estos valores en la fórmula de movimiento del eje X, obtenemos la expresión final de la coordenada Xm (en función de la vertical Ym) que estábamos buscando:

Ahora que ya hemos calculado la fórmula que necesitamos para averiguar la posición que nos interesa, es cuestión de substituir las variables por los valores que ya conocemos. Para verlo más fácil pongamos el siguiente ejemplo:

Para este caso tenemos que la resolución de la pantalla será de 1280×800 pixeles. Para esta resolución la canasta está en la posición (143, 365) y supongamos que encontramos la pelota en la posición (1000, 600). Sabemos que la aceleración (la gravedad en este caso) es de 9,8 ya que se trata de una simulación real. Esta es de signo positivo ya el sistema de coordenadas está invertido (las Y’s positivas van hacia abajo).

Ahora tendremos una fórmula en la cual, la posición que buscamos en Xm sólo depende de una posición arbitraria Ym. Como dijimos al principio, la práctica nos demuestra que cuanto mayor sea la altura del tiro más fácilmente entrará la pelota. Tomando esto como premisa, solo debemos elegir una valor lo suficientemente alto para el tiro. En mi caso he elegido una altura donde Y=30. Si aplicamos este valor, obtenemos que la coordenada X será 515.

Resumiendo: que si aparece la pelota en la coordenada (1000, 600), si colocamos el cursor en la posición (515, 30) y lanzamos, la pelota entrará limpiamente por el aro.

Una vez realizado todo este cálculo, solo nos quedará hacer que nuestro programa mueva el cursor del ratón a esta posición de pantalla y enviar un evento de click (mousedown-mouseup) al programa para que este interprete que queremos realizar el lanzamiento.

Ahora que ya os he explicado el cómo y el por qué, solo os queda programar todo esto en vuestro lenguaje preferido. Si alguien esperaba que publicara el programa, lo siento. Lo divertido de este tema está precisamente en hacer el programa en cuestión y no en meter canastas automáticamente 😉

9 Comments

  • jrg9
    25 febrero, 2010 a las 6:24

    jajaja, lo tengo, es muy divertido quedar siempre en primer lugar!!

  • jrg9
    25 febrero, 2010 a las 6:25

    ahora subo un screenshot p q lo vean

  • BiosZip
    25 febrero, 2010 a las 13:06

    Buenas, hace mucho que te sigo pero me a llamado la atención tu forma de resolver este reto xD
    Yo hice algo parecido para un juego llamado ThrowIt que era de lanzar una pelota a la mayor distancia. Lo que hice fue reducir el juego al mínimo y poner en la esquina inferior izquierda de la ventana, y con un hotkey hice que el raton se moviera a la otra punta superior.
    Se paso horas la bola botando…(luego probe de poner una pantalla extendida a 2500 de resolucion…)
    Lo que siempre he querido saber es como reconocer un objeto o color en una imagen. Puedes darme alguna referencia?

  • jrg9
    25 febrero, 2010 a las 17:14

    hola BiosZip, yo lo he hecho con .net, el tema de reconocer los colores se resuelve con una librería de .net: graphics, busca en google graphics,
    g.CopyFromScreen(MousePosition, New Point(0, 0), New Size(1, 1))

    esta pagina te puede ayudar: http://www.xtremevbtalk.com/showthread.php?t=288040

  • Polimalo Author
    26 febrero, 2010 a las 0:07

    BiosZip, cuando te refieres a reconocer un objeto en pantalla te refieres a como acceder a pantalla o como reconocer una pelota, por ejemplo?

    Porque el ejemplo que da Jrg9 para acceder a pantalla y saber el color concreto de un pixel ya puede servir, aunque muy lento para mi gusto. En c# por ejemplo, prefiero hacer una captura de pantalla y después bloquear el buffer para acceder directamente a la información, que es más rápido.

    Lo otro, depende del cada caso, en este buscar la pelota. En cualquier caso tendrás que programarte algún patrón de búsqueda. El mayor handicap siempre será la velocidad, ya que estos algoritmos suelen ser muy lentos por la gran cantidad de información a evaluar, y de encontrar el método más efectivo y optimizado.

    Para este caso concreto, lo más fácil será buscar un color exacto del balón hasta dar con el.

  • jrg9
    26 febrero, 2010 a las 1:00

    el problema que yo ví al querer detectar un pixel en particular fue que el balón gira, y eso hacia más difícil detectarlo, ya que cuando el «rastreador» pasaba x donde estaba el balón, el balón podría haber girado y no encontrar el pixel

  • BiosZip
    26 febrero, 2010 a las 13:14

    Buenas, esto ya parece un blog de programación xD
    Mi intención es tener una librería que pasándole una imagen(captura) y un patrón, te diga si existe y en que coordenadas.
    El tema de colores, se puede pasar un filtro para exagerarlos o atenuarlos y solo buscar una cosa redonda o algo naranja.
    Hay un filtro del visor IrfanView gratuito que usa una librería de filtros, y esta el Edge Detection que podría ir bien para detectar objetos, botones de aplicaciones y demás.
    Y como es gratuito, lo que usa debe ser gratuito también…
    Pero no tengo ni idea de tratamiento de imágenes a si que se me escapa todo esto un poco.

  • Guti
    28 febrero, 2010 a las 10:15

    Y el fuente?
    😉

  • XD
    1 julio, 2010 a las 6:01

    no entiendo un pomo la formula, la física no es lo mio.