Juego en PyGame - PONG - Parte 2

Jugando PONG en la Magnavox Odyssey

En la entrada anterior:
Juego en PyGame - PONG - Parte 1
terminamos con
nuestras 2 barras funcionando adecuadamente, así que en esta segunda parte nos
dedicaremos a la construcción de nuestra pelota.

Sin más, comenzamos!......



Sin pelota no hay juego!
Vamos a nuestra clase Bola() y establecemos sus características:

__init__ de Bola()
En self.pos
le asignamos las coordenadas para que la pelota inicie en el centro de la
cancha (ventana), self.radio determina el
tamaño de la pelota, self.velocidad
y self.incremento_velocidad
determinan la velocidad a la que se moverá la pelota y el incremento que tendrá
cada vez que reboten contra una barra, en self.lado_impacto
vamos a guardar en qué lado de la cancha la bola impacto y por último en self.sonido_rebote  cargamos el sonido que emitirá la pelota cada
vez que rebote.

*más
información del módulo pygame.mixer.Sound
aquí:
http://www.pygame.org/docs/ref/mixer.html#pygame.mixer.Sound

Ahora vamos al método dibujar y escribe lo siguiente:

Método dibujar de Bola()
Con pygame.draw.circle()
nos permite dibujar un circulo en la pantalla, este nos pide donde se va a
dibujar (
pantalla), de que color
sera, su 
posición y su radio.

Características de la pelota
El punto central de toda la pantalla
lo obtenemos con [ANCHO / 2, ALTO / 2]
y se lo pasamos al dibujar el circulo para que lo deje bien centrado.

Nuestra pelota debera tener un movimiento, quiere decir que
verticalmente tendra un movimiento “y
y horizontalmente un movimiento “x”.

En self.velocidad, x = 4 e y = 4 * random.random() + 4, ¿y ese random.random() que hace?

Pues random.random() lo que hace es que cada vez que lo
llamemos nos genera un numero decimal al azar entre el 0 y el 1 (por ejemplo
0.56874), 
así que con esa formula, cada vez que una pelota inicie su
movimiento, 
saldrá en una dirección diferente (con respecto al eje de las “y”),
si no lo entiendes, escribelo y al final 
sabrás a lo que me refiero.

*puedes
probar el  modulo random en el interprete o shell de Python escribiendo import random y
cada vez que escribas random.random()
te generara un numero decimal diferente del 0 al 1.

Es hora de dibujarla, así que vamos a la función principal main() y agregamos la siguiente línea:

Creando la pelota
Creamos la pelota con bola
= Bola()


Ahora en el bucle while, en la sección de dibujo ponemos:

Dibujando la pelota
Una vez hecho esto, ejecutamos veremos nuestra pelota
perfectamente centrada.


Y tal como lo hicimos con las barras, ahora necesitamos
decirle a nuestra pelota como debe comportarse, 
así que regresemos a la clase 
Bola() y en el método actualizar() escribimos lo siguiente:

Método actualizar de Bola()
¿Recuerdas que en la barra modificábamos su posición vertical (self.pos[1]) para darle ese efecto
de movimiento? Pues con la pelota es 
prácticamente lo mismo con la diferencia
de que 
también modificaremos su posición horizontal para que la pelota se mueva
en todas las direcciones, asi que a los valores que tengan
self.pos le sumamos los valores que contengan self.velocidad.

Ahora solo nos queda probar si la pelota se mueve pero para
que funcione, tal y como lo hicimos con las barras hay que agregar la 
lógica al
bucle
while de la función principal así:

Ejecución de la lógica de la pelota
Una vez hecho, ejecutas y …………………

PAW!!!  Un error!! 
 



Que no cunda el pánico!, hay que analizar el error que nos muestra la consola:

Mensaje de error de la consola
El cual en mi caso me dice que
tuve un error en la linea 47, con pygame.draw.circle(pantalla,
BLANCO, self.pos, self.radio)
en TypeError
me dice que esperaba un numero entero (int) y yo le di un numero con decimales
(float).

¿Entonces Python, me estas diciendo que
el modulo
pygame.draw.circle() admite
solamente 
números enteros? muy bien Python dame un segundo y solucionare esto.....

Bueno, resulta
que en
self.velocidad = [4, 4 *
random.random() + 4]
se genera un numero con décimas en el segundo valor (4 * random.random() + 4) el cual lo habíamos sumado a self.pos en el método actualizar(), así que
volvamos al método 
actualizar() y
hacemos una pequeña modificación:

Método actualizar de Bola()
Con int() nos aseguramos de que self.pos
siempre tendrá números enteros.


*es muy común tener errores a la hora de programar particularmente este que realmente me paso, es por eso que es muy importante detectarlos apoyándonos con la consola y aprender a interpretarla, todo esto lo logras con
la practica.

Bien me salí un poco del tema para mostrarte que hasta yo cometo errores xD, ahora si
ejecuta y tu pelota ¡se mueve!, pero….. desaparece (-_-
) por lo que necesitamos establecer sus limites.

En el método actualizar() primero
establecemos los limites superior e inferior:

Estableciendo sus limites superior e inferior
Con esto le decimos que si la posición de la pelota se pasa del limite superior o el limite inferior, entones cambia su sentido vertical con self.velocidad[1]
*= -1

Si ejecutas te darás cuenta que tu
pelota rebota pero de forma incorrecta, es decir, cambia su 
dirección cuando el
centro de la pelota toca el limite de la pantalla pero queremos que rebote
cuando toque el extremo de la pelota, para eso tenemos que considerar el radio
de la pelota y lo logramos con la siguiente 
modificación:

Estableciendo sus limites superior e inferior
Ahora vamos a establecer los
limites izquierdo y derecho:

Situaciones de la pelota
Es hora de
ponernos serios que viene lo bueno!
 ( ͠° ͟ل͜ ͡°)

Aquí se complica un poco porque la pelota al llegar al limite
de la barra, esta debe de detectar si esta tocando la barra para rebotar o de
lo contrario iniciar un juego nuevo.

Para esto la pelota necesita
conocer 3 valores de la barra que son: su largo, ancho y 
posición vertical, a que volvemos a la clase
Barra() a
crear 3 sencillos 
métodos para poder tener acceso a estos valores.

En nuestra
clase
Barra() creamos los siguientes métodos:

ancho, largo y posición de Barra()

Con estos 3 métodos; ancho(), largo(), y posicion()
vamos a poder accesar a estos valores.



Pero para que nuestra clase Bola() pueda accesar a ellos
necesitamos hacer 2 modificaciones al 
código que llevamos:

agregando parámetros barra1 y barra2
1- El método actualizar() de la clase Bola()
va a recibir 2 
parámetros; barra1 y barra2:


pasando parámetros barra1 y barra2
2- En el
bucle
while en la lógica del juego
le pasamos las barra1 y barra2 a nuestra Pelota:


Con esto nuestra Pelota va a tener
acceso a los 
métodos de ambas barras.

Bien,
regresamos al método 
actualizar() de
la clase
Bola() y …..

Detectando los limites
agregamos las condiciones que
detectaran si la pelota toca el limite izquierdo y el derecho tomando en cuenta
el ancho de las barras. Por el momento no hacen nada.


Ahora escribimos lo siguiente:

Detectando si tocamos la barra o el vació
Detectando si tocamos la barra o el vació


Bien, la condición if es la que detectara si la pelota al
llegar al limite se encuentra dentro del largo de la barra, es decir, si la
toco (por el momento no hace nada) y de no tocarla guardara en
self.lado_impacto el lado que impacto
(
perdió).




Y por
ultimo le diremos que debe hacer si toca la barra:

Agregando el comportamiento si tocamos una barra
Reproducimos
el sonido de rebote con
self.sonido_rebote.play(),
con
self.pos[0] = barra1.ancho() +
self.radio
esta linea se encarga de mantener la pelota siempre dentro de
los limites izquierdo y derecho porque cuando la pelota alcanza una velocidad
considerable, veríamos errores en el rebote y al final cambiamos el sentido
de la pelota multiplicando su velocidad horizontal por
-1 y la incrementamos multiplicándola por self.incremento_velocidad (1.1 es igual al 10%).

Esta entrada estuvo bastante agitada ¿no creen?

Hasta aquí la segunda parte de esta guía, en la siguiente, concluiremos este tutorial.

Saludos! (◕‿◕)

Salvador Ramirez  Google+




Parte 1 - Parte 2 - Parte 3


  1. Anónimo dice:

    Extraordinario. Saludos!

  2. El rincón de David dice:

    Este comentario ha sido eliminado por el autor.

  3. El rincón de David dice:

    espero que me respondas lo más pronto amigo... en esa parte del error que mencionabas yo sigo tus pasos y aun asi me vuelve a salir el mismo tipo de error.. que podria estar pasando?

    1. PythonDiario dice:

      Hola, cual es el error??

    2. El rincón de David dice:

      Traceback (most recent call last):
      File "D:UserDownloadsPONGplantilla.py", line 206, in
      main()
      File "D:UserDownloadsPONGplantilla.py", line 194, in main
      bola.dibujar(pantalla)
      File "D:UserDownloadsPONGplantilla.py", line 100, in dibujar
      pygame.draw.circle(pantalla,BLANCO,self.pos,self.radio)
      TypeError: integer argument expected, got float
      Me sale ese error a pesar de haber puesto int() en el argumento que mencionaba el autor del juego
      def actualizar(self, barra1, barra2):
      self.pos[0]+=int(self.velocidad[0])
      self.pos[1]+=int(self.velocidad[1])

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir

Te has suscrito correctamente al boletín

Se produjo un error al intentar enviar tu solicitud. Inténtalo de nuevo.

Mi Diario Python will use the information you provide on this form to be in touch with you and to provide updates and marketing.