Pues bien, en éste completo el script para considerar la implementación del movimiento del personaje cuando la plataforma no es perfectamente horizontal, como es el caso, por ejemplo, del juego que he tomado como referencia, 'Donkey Kong', ya que el cafre del gorila, en la pantalla de presentación y para dificultarle a 'Jumpman' (Mario) la existencia, se pone a saltar sobre la plataforma como un poseso y deforma los tramos de los diferentes niveles o pisos, dejándo éstos con forma escalonada.
Dicho esto, básicamente, el código modificado e incluido en el script del post anterior es el siguiente:
1.- Inicialización de determinados aspectos:
- Se incluye el sonido correspondiente a la muerte de 'Jumpman' cuando éste cae al piso inferior o salta fuera de la ventana.
sonido_morir = pygame.mixer.Sound(
'recursos/sonidos/morir.wav')
- Se crean dos grupos para los tramos del suelo, uno para cada piso o nivel de la plataforma, en lugar de uno.
# Grupo de sprites. Agrupamos los tramos del suelo de los diferentes pisos
# usando la clase sprite.Group de Pygame para hacer que dicha clase se
# encargue de actualizarlos y dibujarlos, sin necesidad de hacerlo
# manualmente.
grupo_tramos_0 = pygame.sprite.Group()
grupo_tramos_1 = pygame.sprite.Group()
# Colocar los tramos del suelo del piso 0 en la pantalla.
for num_tramo in range(14):
tramo = Tramo(24 + 48 * num_tramo, 396)
grupo_tramos_0.add(tramo)
# Colocar los tramos del suelo del piso 1 en la pantalla.
for num_tramo in range(13):
tramo = Tramo(72 + 48 * num_tramo, 327 - num_tramo * 2)
grupo_tramos_1.add(tramo)
- Se crea e inicializa la siguiente variable:
# Variable booleana que indica si Jumpman está vivo o muerto.
jumpman_vivo = True
2.- Manejo de teclas pulsadas:
- El control del aterrizaje de 'Jumpman' en el suelo del primer piso, piso en el que se le sitúa al principio, se realiza de idéntica forma que en el post anterior, es decir, mediante las colisiones del sprite de 'Jumpman' con los de los tramos de ese piso, y ese mismo sistema se utiliza para controlar el caminar de 'Jumpman' sobre el suelo escalonado, tanto hacia la derecha como hacia la izquierda.
- Se controla si 'Jumpman' cae al piso inferior mediante la colisión con los tramos de ese piso, y si salta fuera de la ventana mediante su posición en la misma, produciéndose su muerte en ambos casos.
- Y, finalmente, el manejo de las teclas pulsadas sólo se realiza si 'Jumpman' está vivo.
if jumpman_vivo:
# Obtener la lista de teclas pulsadas y gestión de las mismas.
teclas = pygame.key.get_pressed()
# Movimiento horizontal (tanto si Jumpman está en el suelo como si
# está saltando).
if en_suelo:
vel_x = 3
if teclas[pygame.K_LEFT]:
canal1.play(sonido_andar)
sentido = 'IZQUIERDA'
jumpman.mover('ANDAR', sentido, 2, -vel_x, 1)
finalizar_mover = True
elif teclas[pygame.K_RIGHT]:
canal1.play(sonido_andar)
sentido = 'DERECHA'
jumpman.mover('ANDAR', sentido, 2, vel_x, 0)
finalizar_mover = True
elif en_salto:
jumpman.mover('SALTAR', sentido, 2, sentido_salto * 6, vel_y)
# Salto.
if teclas[pygame.K_SPACE] and en_suelo:
canal1.play(sonido_saltar)
vel_x = 0
vel_y = -altura_salto
jumpman.mover('SALTAR', sentido, 1, vel_x, -altura_salto)
en_suelo = False
en_salto = True
# Guardar el sentido en el que se inicia el salto.
if teclas[pygame.K_LEFT]:
sentido_salto = -1
elif teclas[pygame.K_RIGHT]:
sentido_salto = 1
else:
sentido_salto = 0
# Aplicar gravedad.
vel_y += gravedad
# Comprobar si colisiona con algún tramo del piso en el que está,
# tanto cuando anda como cuando salta.
tramos_colision = pygame.sprite.groupcollide(grupo_jumpman,
grupo_tramos_1,
False, False)
if len(tramos_colision) > 0:
vel_x = 0
# Colisión con el suelo.
if en_suelo:
jumpman.mover('ANDAR', sentido, 2, vel_x, -1)
elif en_salto:
jumpman.mover('SALTAR', sentido, 1, vel_x,
tramos_colision[jumpman][0].
rect.top -
jumpman.rect.bottom -
tramo.alto_tramo // 2 - 1)
#jumpman.finalizar_mover()
finalizar_mover = True
vel_y = 0
en_suelo = True
en_salto = False
elif jumpman.rect.bottomright[0] <= grupo_tramos_1.sprites()[0]. \
rect.topleft[0] or \
jumpman.rect.bottomleft[0] >= grupo_tramos_1.sprites()[-1]. \
rect.topright[0]:
vel_x = 0
jumpman.mover('ANDAR', sentido, 1, vel_x, 3)
# Comprobar si colisiona con algún tramo del piso
# inmediatamnete inferior al que está.
tramos_colision = pygame.sprite.groupcollide(grupo_jumpman,
grupo_tramos_0,
False, False)
if len(tramos_colision) > 0:
canal1.play(sonido_morir)
jumpman.morir()
jumpman_vivo = False
elif jumpman.rect.bottom > 475:
canal1.play(sonido_morir)
grupo_jumpman.remove(jumpman)
jumpman_vivo = False
3.- Clases:
Se incluye el método morir en la clase 'Jumpman':
def morir(self):
# Método que permite mostrar la muerte de Jumpman cuando cae al piso
# inmediatamente inferior al que se encuentra o salta fuera de la
# ventana.
self.image = pygame.image.load('recursos/imagenes/' +
'jumpman_morir.png').convert_alpha()
4.- Poniendo todo junto:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# SALTAR 3:
#
# Tercera aproximación al salto de un personaje de videojuego.
#
# Autor: Mikel García Larragan.
# https://mikelgarcialarragan.blogspot.com/
import pygame
import os
class Jumpman(pygame.sprite.Sprite):
# Jumpman (Mario) estará definido por la clase Jumpman, que hereda de la
# clase sprite.Sprite de Pygame. Clase base para objetos visibles del
# juego.
def __init__(self, x, y):
super().__init__()
self.x, self.y = x, y
self.image = pygame.image.load('recursos/imagenes/' +
'jumpman_derecha_1.png').convert_alpha()
self.rect = self.image.get_rect(center=(self.x, self.y))
def mover(self, movimiento, sentido, paso, vel_x, vel_y):
# Método que permite que Jumpman se mueva (ande o salte) en el sentido
# indicado.
self.movimiento = movimiento
self.sentido = sentido
self.paso = paso
self.x += vel_x
self.y += vel_y
if self.movimiento == 'ANDAR':
self.image = pygame.image.load('recursos/imagenes/' +
'jumpman_' + self.sentido + '_' +
str(self.paso) + '.png') \
.convert_alpha()
elif self.movimiento == 'SALTAR':
self.image = pygame.image.load('recursos/imagenes/' +
'jumpman_saltar_' +
self.sentido + '.png') \
.convert_alpha()
def finalizar_mover(self):
# Método que permite completar el movimiento de Jumpman, tanto cuando
# anda como cuando salta, mostrando la imagen correspondiente a Jumpman
# parado.
self.image = pygame.image.load('recursos/imagenes/' +
'jumpman_' + self.sentido + '_1.png') \
.convert_alpha()
def morir(self):
# Método que permite mostrar la muerte de Jumpman cuando cae al piso
# inmediatamente inferior al que se encuentra o salta fuera de la
# ventana.
self.image = pygame.image.load('recursos/imagenes/' +
'jumpman_morir.png').convert_alpha()
def update(self):
# El método update() se ejecutará en cada frame y permite actualizar la
# posición de Jumpman.
self.rect = self.image.get_rect(center=(self.x, self.y))
class Tramo(pygame.sprite.Sprite):
# Los tramos del suelo por donde anda y salta Jumpman estarán definidos por
# la clase Tramo, que hereda de la clase sprite.Sprite de Pygame. Clase
# base para objetos visibles del juego.
def __init__(self, x, y):
super().__init__()
self.x, self.y = x, y
self.image = pygame.image.load('recursos/imagenes/tramo.png') \
.convert_alpha()
self.rect = self.image.get_rect(center=(self.x, self.y))
self.alto_tramo = self.image.get_height()
def update(self):
# El método update() se ejecutará en cada frame, y permite actualizar
# los tramos.
self.rect = self.image.get_rect(center=(self.x, self.y))
def donkey_kong():
# Inicializar módulos internos de pygame.
pygame.init()
# Establecer tamaño de la ventana.
# Crear una superficie de visualización: la ventana, y centrarla.
os.environ['SDL_VIDEO_CENTERED']='1'
ventana = pygame.display.set_mode((674, 430))
# Título de la ventana.
pygame.display.set_caption('Donkey Kong')
# Cargar la imagen del fondo y cambiar el formato de píxel para crear una
# copia que se dibujará más rápidamente en la pantalla.
fondo = pygame.image.load('recursos/imagenes/fondo_3.png')
fondo = fondo.convert()
# Cargar archivos de sonidos.
sonido_andar = pygame.mixer.Sound(
'recursos/sonidos/andar.wav')
sonido_saltar = pygame.mixer.Sound(
'recursos/sonidos/saltar.wav')
sonido_morir = pygame.mixer.Sound(
'recursos/sonidos/morir.wav')
# Crear canal para sonidos.
canal1 = pygame.mixer.Channel(0)
# Grupo de sprites. Agrupamos los tramos del suelo de los diferentes pisos
# usando la clase sprite.Group de Pygame para hacer que dicha clase se
# encargue de actualizarlos y dibujarlos, sin necesidad de hacerlo
# manualmente.
grupo_tramos_0 = pygame.sprite.Group()
grupo_tramos_1 = pygame.sprite.Group()
# Colocar los tramos del suelo del piso 0 en la pantalla.
for num_tramo in range(14):
tramo = Tramo(24 + 48 * num_tramo, 396)
grupo_tramos_0.add(tramo)
# Colocar los tramos del suelo del piso 1 en la pantalla.
for num_tramo in range(13):
tramo = Tramo(72 + 48 * num_tramo, 327 - num_tramo * 2)
grupo_tramos_1.add(tramo)
# Posición inicial de Jumpman.
x, y = 120, 296
# Grupo individual para Jumpman y dibujarlo.
grupo_jumpman = pygame.sprite.GroupSingle()
jumpman = Jumpman(x, y)
grupo_jumpman.add(jumpman)
# Variable booleana que indica si Jumpman está vivo o muerto.
jumpman_vivo = True
# Variables booleanas que indican si Jumpman se encuentra en el suelo o
# está saltando, respectivamente.
en_suelo = True
en_salto = False
# Sentido del movimiento de Jumpman, tanto cuando anda como cuando salta.
sentido = 'DERECHA'
# Velocidad de movimiento en ambos ejes.
vel_x, vel_y = 3, 0
# Variables correspondientes al salto.
sentido_salto = 0
altura_salto = 9
gravedad = 1
# Establecer el tiempo transcurrido (valor de un contador) desde el inicio
# del movimiento de Jumpman, tanto cuando está andando como cuando salta, y
# el que debe transcurrir hasta su finalización.
contador_inicio_mover = 0
contador_fin_mover = 10
# Variable booleana que indica si se debe finalizar de mostrar el
# movimiento de Jumpman (andar o saltar).
finalizar_mover = False
# Reloj para ejecutar el videojuego.
reloj = pygame.time.Clock()
# El juego se ejecutará a 60 frames por segundo.
fps = 60
while True:
# Ejecutar el siguiente frame.
reloj.tick(fps)
# Escuchar cada uno de los eventos de la lista de eventos de Pygame.
for evento in pygame.event.get():
# Finalizar el juego cuando se produzca el evento de terminación
# del programa (cierre de la ventana).
if evento.type == pygame.QUIT:
pygame.quit()
return
if jumpman_vivo:
# Obtener la lista de teclas pulsadas y gestión de las mismas.
teclas = pygame.key.get_pressed()
# Movimiento horizontal (tanto si Jumpman está en el suelo como si
# está saltando).
if en_suelo:
vel_x = 3
if teclas[pygame.K_LEFT]:
canal1.play(sonido_andar)
sentido = 'IZQUIERDA'
jumpman.mover('ANDAR', sentido, 2, -vel_x, 1)
finalizar_mover = True
elif teclas[pygame.K_RIGHT]:
canal1.play(sonido_andar)
sentido = 'DERECHA'
jumpman.mover('ANDAR', sentido, 2, vel_x, 0)
finalizar_mover = True
elif en_salto:
jumpman.mover('SALTAR', sentido, 2, sentido_salto * 6, vel_y)
# Salto.
if teclas[pygame.K_SPACE] and en_suelo:
canal1.play(sonido_saltar)
vel_x = 0
vel_y = -altura_salto
jumpman.mover('SALTAR', sentido, 1, vel_x, -altura_salto)
en_suelo = False
en_salto = True
# Guardar el sentido en el que se inicia el salto.
if teclas[pygame.K_LEFT]:
sentido_salto = -1
elif teclas[pygame.K_RIGHT]:
sentido_salto = 1
else:
sentido_salto = 0
# Aplicar gravedad.
vel_y += gravedad
# Comprobar si colisiona con algún tramo del piso en el que está,
# tanto cuando anda como cuando salta.
tramos_colision = pygame.sprite.groupcollide(grupo_jumpman,
grupo_tramos_1,
False, False)
if len(tramos_colision) > 0:
vel_x = 0
# Colisión con el suelo.
if en_suelo:
jumpman.mover('ANDAR', sentido, 2, vel_x, -1)
elif en_salto:
jumpman.mover('SALTAR', sentido, 1, vel_x,
tramos_colision[jumpman][0].
rect.top -
jumpman.rect.bottom -
tramo.alto_tramo // 2 - 1)
#jumpman.finalizar_mover()
finalizar_mover = True
vel_y = 0
en_suelo = True
en_salto = False
elif jumpman.rect.bottomright[0] <= grupo_tramos_1.sprites()[0]. \
rect.topleft[0] or \
jumpman.rect.bottomleft[0] >= grupo_tramos_1.sprites()[-1]. \
rect.topright[0]:
vel_x = 0
jumpman.mover('ANDAR', sentido, 1, vel_x, 3)
# Comprobar si colisiona con algún tramo del piso
# inmediatamnete inferior al que está.
tramos_colision = pygame.sprite.groupcollide(grupo_jumpman,
grupo_tramos_0,
False, False)
if len(tramos_colision) > 0:
canal1.play(sonido_morir)
jumpman.morir()
jumpman_vivo = False
elif jumpman.rect.bottom > 475:
canal1.play(sonido_morir)
grupo_jumpman.remove(jumpman)
jumpman_vivo = False
# Animar movimientos de Jumpman.
if finalizar_mover:
if contador_inicio_mover > contador_fin_mover:
jumpman.finalizar_mover()
contador_inicio_mover = 0
finalizar_mover = False
else:
contador_inicio_mover += 1
# Actualizar sprites.
grupo_tramos_0.update()
grupo_tramos_1.update()
grupo_jumpman.update()
# Copiar la imagen de fondo de la ventana en el canvas que la mostrará.
ventana.blit(fondo, (0, 0))
# Dibujar sprites.
grupo_tramos_0.draw(ventana)
grupo_tramos_1.draw(ventana)
grupo_jumpman.draw(ventana)
# Mostrar la ventana dibujada (cambiar buffers, buffer pantalla a
# disponible para dibujar y viceversa.
pygame.display.flip()
pygame.quit()
if __name__ == '__main__':
donkey_kong()
Si lo ejecutamos:
Comentarios
Publicar un comentario