5. Objetos controlables por los usuarios¶
Hasta ahora puodés crear una ventana de Pygame y renderizar una pelota que volará por la pantalla. El siguiente paso es crear algunos bates que el usuario pueda controlar. Esto es potencialmente más simple que la pelota, porque no requiere física (a menos que el objeto controlado por el usuario se mueva de manera más compleja que hacia arriba y abajo, por ejemplo, un personaje de plataforma como Mario, en cuyo caso necesitarás más física) Los objetos controlados por el usuario son bastante fácil de crear, gracias al sistema de cola de Pygame, como ya verás.
5.1. Una clase simple de bate¶
El principio detrás de la clase de bate es similar al de la clase de pelota. Necesitás una función __init__
para inicializar
el bate (para que puedas crear instancias de objeto para cada bat), una función update
para realizar cambios por cuadro
en el bate antes de que sea blitteado en la pantalla, y las funciones que definirán lo que esta clase realmente hará. Aquí tenés
un ejemplo de código:
class Bat(pygame.sprite.Sprite):
"""Movable tennis 'bat' with which one hits the ball
Returns: bat object
Functions: reinit, update, moveup, movedown
Attributes: which, speed"""
def __init__(self, side):
pygame.sprite.Sprite.__init__(self)
self.image, self.rect = load_png("bat.png")
screen = pygame.display.get_surface()
self.area = screen.get_rect()
self.side = side
self.speed = 10
self.state = "still"
self.reinit()
def reinit(self):
self.state = "still"
self.movepos = [0,0]
if self.side == "left":
self.rect.midleft = self.area.midleft
elif self.side == "right":
self.rect.midright = self.area.midright
def update(self):
newpos = self.rect.move(self.movepos)
if self.area.contains(newpos):
self.rect = newpos
pygame.event.pump()
def moveup(self):
self.movepos[1] = self.movepos[1] - (self.speed)
self.state = "moveup"
def movedown(self):
self.movepos[1] = self.movepos[1] + (self.speed)
self.state = "movedown"
Como puedes ver, esta clase es muy similar en estructura a la clase de la pelota, pero hay diferencias en lo que hace cada función. En primer lugar, hay una función "reinit", que es utilizada cuando una ronda finaliza y el bate debe volver a su lugar de inicio con cualquier atributo establecido de vuelta a sus valores necesarios. A continuación, la forma en que se mueve el bate es un poco más compleja que con la pelota, porque acá su movimiento es simple (arriba/abajo), pero depende de que el usuario le diga que se mueva, a diferencia de la pelota que simplemente sigue moviéndose en cada cuadro. Para entender cómo se mueve el bate, es útil mirar brevemente un diagrama para mostrar la secuencia de eventos:
.. image:: tom_event-flowchart.png
Lo que sucede aquí es que la persona controlando el bate presional la tecla que mueve el bate hacia arriba. Para cada interación
de el bucle principal del juego (para cada cuadro), si la tecla sigue presionada, entonces el atributo state
de ese objeto
de bate se establecerá en "moviendose" y se llamará a la función moveup
, lo que hará que la posición 'y' de la pelota se
reduzca por el valor de atributo speed
(en este ejemplo, 10). En otras palabras, mientras la tecla se mantenga presionada,
el bate se moverá hacia arriba de la pantalla en 10 píxeles por cuadro. El atributo state
no se utiliza aquí, pero es útil
saberlo si estás tratando con giros o si deseas obtener alguna salida de depuración útil.
Tan pronto como el jugador suelte la tecla, se invoca el segundo conjunto de cajas y el atributo state
del objeto de bate
se establecerá de nuevo en "still" y el atributo movepos
volverá a establecerse en [0,0], lo que significa que cuando se
llame a la función update
, ya no movera el bate. Así que cuando el jugador suelta la tecla, el bate se detiene. ¡Simple!
5.1.1. Digresión 3: Eventos de Pygame¶
Entonces, ¿cómo sabemos cuándo el jugador está presionando teclas y luego las suelta? ¡Con el sistema de cola de eventos de Pygame, tontuelo! Es un sistema realmente fácil de usar y entender, así que esto no debería llevar mucho tiempo :) Ya has visto la cola de eventos en acción en el programa básico de Pygame, donde se usó para verificar si el usuario estaba cerrando la aplicación. El código para mover el bate es tan simple como eso:
for event in pygame.event.get():
if event.type == QUIT:
return
elif event.type == KEYDOWN:
if event.key == K_UP:
player.moveup()
if event.key == K_DOWN:
player.movedown()
elif event.type == KEYUP:
if event.key == K_UP or event.key == K_DOWN:
player.movepos = [0,0]
player.state = "still"
Aquí se asume que ya has creado una instancia de un bate y has llamado al objeto player
. Podés ver el familiar diseño
de la estrictura for
, que itera a través de cada evento encontrado en la cola de eventos de Pygame, que se recupera con
la función event.get()
. A medida que el usuario presiona teclas, pulsa botones del ratón y mueve
el joystick, esas acciones se bombean en la cola de eventos de Pygame, y se dejan allí hasta que se traten. Así que en cada
iteración del bucle principal del juego, se pasa por estos eventos, comprobando si son los que se desean tratar, y luego
tratándolos adecuadamente. La función event.pump()
que estaba en la función Bat.update
se
llama entonces en cada iteración para eliminar los eventos antiguos y mantener la cola actual.
Primero verificamos si el usuario está saliendo del programa, y lo cerramos si es así. Luego verificamos si se está
presionando alguna tecla, y si lo están, verificamos si son las teclas designadas para mover la paleta hacia arriba
y hacia abajo. Si lo son, llamamos a la función de movimiento correspondiente y establecemos el estado del jugador
adecuadamente (aunque los estados moveup (moverarriba) y movedown (moverabajo) se cambian en las funciones moveup()
y movedown()
, lo que hace que el código sea más ordenado y no rompe la encapsulación, lo que significa que se
asignan atributos al objeto en sí, sin referirse al nombre de la instancia de ese objeto). Aquí notamos que tenemos
tres estados: still (quieto), moveup (moverarriba), movedown (moverabajo). De nuevo, estos son útiles si se quiere
depurar o calular giros, efectos de rotación. También verificamos si alguna tecla ha sido "soltada" (es decir, que
ya no está siendo presionada), y nuevamente, si son las teclas correctas, detenemos el movimiento del bate.
Edit on GitHub