Información y programación del tiro parabólico (pygame)

Solicite, consulte o publique recursos de referencia para desarrolladores.

Información y programación del tiro parabólico (pygame)

Notapor endaramiz » Lun Oct 15, 2007 3:09 pm

INTRODUCCIÓN
En este articulo se explican levemente conceptos básicos de física para luego entender el código (en Python + Pygame) del lanzamiento de un proyectil simple (piedra, bala redonda de cañón...).

CONCEPTOS BÁSICOS
0 Conceptos básicos en python:
Esta sección da información de Python que es útil para programar lo que se explica en este documento.
X**Y = X elevado a Y. Por ejemplo: 2 ** 3 = 2*2*2
sqrt(X) = raíz cuadrada de X. Por ejemplo: sqrt(9) = 3 (ya que 3**2 = 9)
radians(A) Devuelve el ángulo A pasado de grados a radianes
degrees(A) Devuelve el ángulo A pasado de radianes a grados

La tangente, el seno, el coseno... trabaja con el ángulo en radianes.
sin(A) = seno de A
cos(A) = coseno de A
tan(A) = tangente de A
atan(A) = arcotangente de A

Para utilizar estas funciones hace falta importarlas del modulo math. Por ejemplo:
from math import sqrt, radians, cos

1 La velocidad:
Es el desplazamiento en un cierto incremento de tiempo. Por ejemplo: km/h, m/s (Sistema internacional)... Pero para programar utilizaremos las unidades de píxeles / tiempo que tarda un ciclo del bucle.
Por lo tanto, si la velocidad es 0, el cuerpo estará quieto.

2 Aceleración:
Es el incremento de velocidad en un cierto incremento de tiempo. Por ejemplo: m/s^2 (S.I.). Pero para programar utilizaremos las unidades de píxeles / tiempo que tarda un ciclo del bucle^2.
Por lo tanto, si la aceleración es 0, la velocidad se mantiene constante, pudiendo ser o no 0.

3 Vectores:
Para hacer cálculos con la velocidad, la aceleración... es conveniente utilizar los vectores que son segmentos orientados que determinan la intensidad(modulo) y la dirección. Pueden dar la información del punto de aplicación (donde empieza), aunque puede no darse este dato y considerar el punto 0 sin importar su ubicación en el plano (vector libre).
Los datos del vector se pueden dar de dos maneras: en coordenadas polares o en coordenadas cartesianas.

3.1 En coordenadas polares:
Para ello es necesario el modulo (intensidad) y el ángulo que va al contrario de las agujas del reloj empezando desde donde se situaría la aguja cuando son las 3h.
Imagen
El ángulo puede darse en radianes o grados. Dependiendo del caso ara falta uno o otro. La relación que tienen es: una circunferencia tiene 360 grados o 2*pi radianes.

3.2 En coordenadas cartesianas:
Para ello es necesario dos ejes (ya que estamos en 2 dimensiones) de coordenadas. Un eje esta en posición horizontal (x) y el otro en vertical (y). El vector se descompone en la suma de dos vectores que tienen la misma dirección que los ejes de coordenadas y empiezan en un punto 0. Por ejemplo, si tenemos un “vector x” de modulo 3 unidades y un “vector y” de 2 unidades el vector se representaría:
Imagen
Para dar estos datos de una forma mas simple se pueden dar dentro de un paréntesis con dos valores en el que, por convenio, el primer dato es el modulo del “vector x” y el segundo el del “vector y”. Por ejemplo, con los mismos datos de antes: V = (3, 2)

3.3 De coordenadas polares a cartesianas:
Si se representa un vector dadas las coordenadas polares y luego los ejes horizontal y vertical, utilizando rectas paralelas obtenemos un triangulo rectángulo (Con un ángulo recto (90º) ).
Imagen
Una vez tenemos esto, el “lado y” es la componente “vector y” del vector. Y el “lado x”, “vector x”. Para obtener la longitud de estos lados se utiliza el seno y el coseno. En Python:
cos(a) = x / M --> x = cos(a) * M
sin(a) = y / M --> y = sin(a) * M

3.4 De coordenadas cartesianas a polares:
Una vez representada la suma de las dos componentes del vector, utilizando rectas paralelas obtenemos el triangulo rectángulo (imagen anterior).
Para obtener el ángulo se utiliza la tangente. En Python:
tan(a) = y / x --> a = atan( y / x)
Para obtener el módulo se utiliza el teorema de Pitágoras. En Python:
M**2 = x**2 + y**2 --> M = sqrt(x**2 + y**2)

4 Elegir el punto de referencia y convenio de signos:
Para hacer los calculo con los componentes de los vectores (velocidad x, gravedad...) hay que ponerles signos dependiendo del sentido que tengan. Por ejemplo: si tiramos una piedra hacia arriba, la gravedad y la “velocidad y” (inicial) están en el mismo eje (el “y”) pero tienen sentidos contrario por lo tanto uno será positivo y otro negativo.
En las pantallas, el punto 0 se toma en la esquina superior izquierda. El “eje x” es positivo hacia la derecha. El “eje y” es positivo hacia abajo. Si tomamos esto como referencia, una velocidad o aceleración hacia arriba es negativa, hacia abajo es positiva, hacia la izquierda es negativa y hacia la derecha, positiva.

6 Tiro parabólico:
Es el lanzamiento de un proyectil(por ejemplo una piedra, una pelota... ya que si fuera algo como un misil autopropulsado, la cosa se complica mas). El movimiento se puede descomponer en dos movimientos rectilíneos, uno horizontal y otro vertical (por esa razón se trabaja con las componentes del vector). Si se considera nula la fricción con el aire, el movimiento horizontal no tiene aceleración, por lo tanto es un movimiento rectilíneo uniforme. En el movimiento vertical actúa la fuerza de la gravedad que crea una aceleración constante, por lo tanto es un movimiento rectilíneo uniformemente acelerado.
En el tiro parabólico la velocidad tiene un cierto ángulo sobre la recta horizontal, si el ángulo fuese 0 se le llama tiro horizontal y si fuese de 90º se le llama tiro vertical.

CÓDIGO:
(Proyectil utilizado: Imagen )
Código: Seleccionar todo
import pygame
from pygame.locals import *
from math import sin, cos, radians

# Aceleracion que produce la fuerza de la gravedad
gravedad = 0.2

# Vector velocidad en coordenadas polares
velocidad_inicial = 12.5 # Modulo (unos 63 m/s)
angulo_inicial = 45 # Direccion

# El punto donde comienza el movimiento el proyectil
posicion_inicial = [50, 550]

def main():
   pygame.init()
   screen = pygame.display.set_mode ((800,600)) # Define una pantalla con resolucion de 800x600
   proyectil = pygame.image.load("bolap.png").convert_alpha() # Carga la imagen
   proyectil_rect = proyectil.get_rect() # Crea una superficie a partir de la imagen
   
   proyectil_rect.center = posicion_inicial # Situa el proyectil en su posicion inicial
   
   # Pasa de coordenadas polares a coordenadas cartesianas
   velocidad_inicial_x = cos(radians(angulo_inicial)) * velocidad_inicial
   velocidad_inicial_y = sin(radians(angulo_inicial)) * velocidad_inicial
   
   # Pone signo a las velocidades dependiendo de su direccion
   velocidad_x = +velocidad_inicial_x
   velocidad_y = -velocidad_inicial_y
   
   velocidad = [velocidad_x, velocidad_y] # Crea una lista con las dos componentes del vector
   
   clock = pygame.time.Clock() # Se utiliza para limitar los fotogramas por segundos
   while True:
      clock.tick(10) # Limita la ejecucion a 10 fotogramas por segundo
      velocidad[1] += gravedad # Incrementa la velocidad con el valor de la gravedad,
      #                          que solo actua en la componente "y" (acelera el cuerpo)
      
      # Incrementa la posicion del cuerpo sumandole las componentes de la velocidad
      # Funciana igual utilizando un metodo o otro
      #proyectil_rect.move_ip(velocidad[0], velocidad[1])
      proyectil_rect.center = [proyectil_rect.center[0] + velocidad[0], proyectil_rect.center[1] + velocidad[1]]
      
      
      # Descomentado imprime un fondo negro pero sin imprimirlo se puede apreciar mejor el movimiento
      #screen.fill((0,0,0))
      
      screen.blit (proyectil, proyectil_rect) # Imprime la imagen del proyectil en su posicion
      pygame.display.update() # Actualiza la pantalla

if __name__ == '__main__': main() # Ejecuta la funcion


David Ramírez

Se que este articulo no es perfecto así que espero vuestras críticas para poder mejorarlo entre todos. Por ejemplo: si alguna parte no quedó clara, no les pareció bien la estructura del articulo...
Y si tienen alguna duda les invito a postearla. Yo intentaré responderles pero si no puedo, también lo leerán otras personas que a lo mejor si pueden hacerlo.

Espero que les haya resultado interesante y/o útil.
Saludos.
Avatar de Usuario
endaramiz
 
Mensajes: 283
Registrado: Vie Ago 31, 2007 9:25 am
Ubicación: Barcelona

Notapor julen26 » Lun Oct 15, 2007 8:35 pm

Realmente interesante y útil para repasar un poco sobre el tema. Bueno para los que no saben aún mucho sobre ello (cada vez tenemos programadores mas jovenes :wink: ). No programo en Python pero es útil para cualquiera, sea cual sea el método.

Todo esta muy bien explicado, al menos no creo que nadie tuviera problemas para endenderlo. Yo creo que sería algo interesante comentar algo mas sobre la gravedad ademas de solamente mencionarla (al mismo tiempo que la fricción, podrías extenderlo mas adelante siendo mas detallado).
Algo como que la gravedad actúa también con la masa del objeto haciendo que la gravedad afecte de manera diferente al objeto, el realismo en los juegos es una buena opción.

suerte! :wink:

saludos
Avatar de Usuario
julen26
 
Mensajes: 10
Registrado: Dom May 13, 2007 3:04 pm

Notapor endaramiz » Mar Oct 16, 2007 2:45 pm

julen26 escribió:Realmente interesante y útil para repasar un poco sobre el tema. Bueno para los que no saben aún mucho sobre ello (cada vez tenemos programadores mas jovenes :wink: ). No programo en Python pero es útil para cualquiera, sea cual sea el método.

Me alegro de ello :D

julen26 escribió:Yo creo que sería algo interesante comentar algo mas sobre la gravedad ademas de solamente mencionarla (al mismo tiempo que la fricción, podrías extenderlo mas adelante siendo mas detallado).

Tienes razón ese tema se tiene que tener en cuenta, y lo tenia en mente cuando hice el articulo, pero como tu bien has dicho sería una extensión del articulo, el cual lo hice con la intención de ser básico. Pero no descarto, cuando tenga tiempo, explicar la fricción con el aire y desviación del proyectil por acción del viento (como pasa en el juego de los gusanos).

julen26 escribió:Algo como que la gravedad actúa también con la masa del objeto haciendo que la gravedad afecte de manera diferente al objeto, el realismo en los juegos es una buena opción.

Cuidado! esta frase puede confundir, es cierto que la gravedad tiene relación con la masa pero estos casos se dan en la gravitación universal. En la Tierra si dos cuerpos no caen a la misma velocidad no es por que tengan diferente masa sino por que hay una fricción con el aire que por lo general frena mas al que tiene menos masa, aunque depende mas de la forma.

Saludos.
Avatar de Usuario
endaramiz
 
Mensajes: 283
Registrado: Vie Ago 31, 2007 9:25 am
Ubicación: Barcelona

Expansión 1: Lanzamiento de misil

Notapor endaramiz » Sab Oct 20, 2007 8:54 pm

El tiro de una circunferencia puede servir para juegos de pelotas y cosas parecidas pero si lo que queremos lanzar es un misil, no basta solo con el código anterior. Para darle un mínimo de realismo, la dirección del misil tiene que ser la misma que el vector velocidad. Esto se puede conseguir añadiendo unas lineas al código, en bucle principal (Repasar el punto 3.4: De coordenadas cartesianas a polares):
Código: Seleccionar todo
angulo = atan( -velocidad[1] / velocidad[0])
centro_original = proyectil_rect.center
proyectil = pygame.transform.rotate ( proyectil_original, degrees(angulo))
proyectil_rect = proyectil.get_rect()
proyectil_rect.center = centro_original


Y hacer una copia al cargar la imagen:
Código: Seleccionar todo
proyectil_original = proyectil.copy()


El código completo quedaría así:
Imagen
Código: Seleccionar todo
import pygame
from pygame.locals import *
from math import sin, cos, atan, radians, degrees

gravedad = 0.2
velocidad_inicial = 12.5
angulo_inicial = 45
posicion_inicial = [50, 550]

def main():
   pygame.init()
   screen = pygame.display.set_mode ((800,600))
   proyectil = pygame.image.load("misil.png").convert_alpha()
   proyectil_original = proyectil.copy() # Hace una copia de la imagen proyectil
   proyectil_rect = proyectil.get_rect()
   
   proyectil_rect.center = posicion_inicial
   
   velocidad_inicial_x = cos(radians(angulo_inicial)) * velocidad_inicial
   velocidad_inicial_y = sin(radians(angulo_inicial)) * velocidad_inicial
   velocidad_x = +velocidad_inicial_x
   velocidad_y = -velocidad_inicial_y
   velocidad = [velocidad_x, velocidad_y]
   
   clock = pygame.time.Clock()
   while True:
      clock.tick(60)
      
      # Da el angulo en radianes de la direccion del vector velocidad
      angulo = atan( -velocidad[1] / velocidad[0])
      # Se guarda la situcion del centro de la imagen
      centro_original = proyectil_rect.center
      # Gira la imagen el angulo obtenido
      proyectil = pygame.transform.rotate ( proyectil_original, degrees(angulo))
      # Modifica el rectangulo respecto a las nuevas dimensiones de la imagen
      proyectil_rect = proyectil.get_rect()
      # Situa el centro del rectangulo donde estaba antes de ser girado
      proyectil_rect.center = centro_original
      
      velocidad[1] += gravedad
      proyectil_rect.center = [proyectil_rect.center[0] + velocidad[0], proyectil_rect.center[1] + velocidad[1]]
      
      screen.fill((0,0,0))
      screen.blit (proyectil, proyectil_rect)
      pygame.display.update()

if __name__ == '__main__': main()

Saludos.
Avatar de Usuario
endaramiz
 
Mensajes: 283
Registrado: Vie Ago 31, 2007 9:25 am
Ubicación: Barcelona


Volver a Artículos, traducciones y documentación

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado

cron