Saltar a contenido

Mover la bola (1ª parte)

El siguiente paso es añadir un movimiento continuo de la bola. Vamos a crear un método mover() en el juego, que sea invocado continuamente desde el método bucle().

Como primer paso, vamos a hacer que la bola se mueva de arriba a abajo, rebotando en los bordes superior e inferior:

05MoverBola1.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
import tkinter

class Juego:
    def __init__(self, ventana):
        self.ventana = ventana

        # Configurar ventana
        self.ventana.title('Bola')
        self.ventana.resizable(False, False)
        self.ventana.wm_attributes('-topmost', True)

        # Crear lienzo
        self.lienzo = tkinter.Canvas(self.ventana,
                                     width=500,
                                     height=400,
                                     bd=0)
        self.lienzo.pack()
        self.ventana.update()

        # Crear bola y paleta
        self.bola = Bola(self)
        self.paleta = Paleta(self)        

        # Indicadores
        self.terminar = False
        self.en_juego=False

        # Asociar eventos de teclado
        self.ventana.bind_all('<KeyPress>', self.gestionar_tecla)

    def gestionar_tecla(self,evento):
        if evento.keysym=='Escape':
            self.terminar = True
        elif evento.keysym == 'space':            
            self.en_juego = True

    def bucle(self):
        while True:
            if self.terminar:
                break

            if self.en_juego:
                self.bola.mover()

            self.ventana.update_idletasks()
            self.ventana.update()

class Bola:
    def __init__(self, juego):
        self.juego  = juego

        tamaño = 15
        self.lienzo_ancho = self.juego.lienzo.winfo_width()
        self.lienzo_alto = self.juego.lienzo.winfo_height()

        self.juego.id_bola = self.juego.lienzo.create_oval(0, 0, tamaño, tamaño,
                                                           fill='red')
        centro_x = self.lienzo_ancho/2 - tamaño/2
        centro_y = self.lienzo_alto/2 - tamaño/2
        self.juego.lienzo.move(self.juego.id_bola, centro_x, centro_y)

        self.desplaz_y = -(velocidad_bola)

    def mover(self):
        # obtener coordenadas bola (x1, y1, x2, y2)
        coord_bola = self.juego.lienzo.coords(self.juego.id_bola)
        borde_sup_bola = coord_bola[1]
        borde_inf_bola = coord_bola[3]

        # si ha tocado el borde superior, empezar a bajar
        if borde_sup_bola <= 1:
            self.desplaz_y = abs(self.desplaz_y)

        # si ha tocado el borde inferior, empezar a subir
        if borde_inf_bola >= self.lienzo_alto-1:
            self.desplaz_y = abs(self.desplaz_y)*(-1)

        # desplazar
        self.juego.lienzo.move(self.juego.id_bola, 0, self.desplaz_y)

class Paleta:
    def __init__(self, juego):
        self.juego  = juego

        ancho = 60
        self.lienzo_ancho = self.juego.lienzo.winfo_width()
        self.lienzo_alto = self.juego.lienzo.winfo_height()

        self.juego.id_paleta = self.juego.lienzo.create_rectangle(0, 0, ancho, 10, fill='blue')

        centro_x = self.lienzo_ancho/2 - ancho/2
        centro_y = self.lienzo_alto - 50

        self.juego.lienzo.move(self.juego.id_paleta, centro_x, centro_y)

velocidad_bola=4
v = tkinter.Tk()
juego = Juego(v)
juego.bucle()
juego.ventana.update_idletasks()
juego.ventana.destroy()

En el bloque principal del programa, comenzamos por definir la velocidad de la bola, medida en número de pixels a desplazar en cada iteración del bucle:

velocidad_bola=4

Como es una variable global, será accesible desde cualquier punto del programa.

Al inicializar el juego, creamos una propiedad para controlar cuando está parado el juego:

self.en_juego=False

El juego se activa al pulsar la tecla Space

def gestionar_tecla(self,evento):
    if evento.keysym=='Escape':
        self.terminar = True
    elif evento.keysym == 'space':            
        self.en_juego = True

Y en el bucle principal, movemos la bola solo si el juego está activo:

if self.en_juego:
    self.bola.mover()

Para controlar el desplazamiento actual de la bola, creamos una propiedad al crear una nueva bola:

self.desplaz_y = -(velocidad_bola):

Siendo x,y las coordenadas de todo objeto, llamaremos desplaz_y al desplazamiento vertical y desplaz_x al horizontal. Inicialmente, el vertical es negativo, lo que hace que la bola comience desplazándose hacia arriba.

El método mover() es invocado continuamente. Consta de dos partes:

  • Calcular desplazamientos
  • Desplazar la bola. En este primer paso, no la desplazaremos horizontalmente:

    self.juego.lienzo.move(self.juego.id_bola, 0, self.desplaz_y)
    

    La bola guarda como propiedades:

    • el desplazamiento vertical self.desplaz_y
    • una referencia al juego. Este almacena una referencia al canvas, que tiene un método move(). Hay que pasarle la referencia al circulo dibujado, que está guardada como propiedad del juego.

La función abs(x) devuelve el valor absoluto de un número x, quitando el signo. Aquí la usamos para controlar el signo de los desplazamientos.