Curso Python. Volumen XXI: Pygame, videojuegos en python. Parte X

Escrito por Javier Ceballos Fernández

Bienvenidos un día más al curso de Python. En el capítulo anterior os enseñamos como podíais introducir efectos sonoros en el videojuego que estamos realizando con la librería Pygame. En este capítulo vamos a mejorar el juego tanto en el rendimiento como en la jugabilidad. Así que pongámonos manos a la obra.

Mejorando el juego

Según hemos ido evolucionando el juego, han aparecido unos puntos que se pueden mejorar, que son los siguientes:

  • Cuando se actualiza la pantalla, tenemos que cargar uno por uno los “sprites”, y esto puede resultar algo ineficiente.
  • El oponente es invencible.
  • Al marcar un punto, la bola debería volver al centro.

El primer punto es bastante fácil de corregir, lo único que tenemos que hacer es cargarlos todos a la vez de la siguiente forma “todos = pygame.sprite.RenderPlain(bola, jugador1, jugador2)” y una vez cargados los mostramos todos de una vez haciendo “todos.draw(screen)”.

Para el segundo punto, tendremos que realizar los siguientes:

def cpu(self, pelota):
    self.speed = [0, 2.5]
    if pelota.speed[0] >= 0 and pelota.rect.centerx >= SCREEN_WIDTH / 2:
        if self.rect.centery > pelota.rect.centery:
            self.rect.centery -= self.speed[1]
        if self.rect.centery < pelota.rect.centery:
            self.rect.centery += self.speed[1]

No ha variado mucho de la versión anterior, pero en este caso, hemos definido una velocidad (que en el eje “y” es de 2.5, lo cual es menor al 3 de la pelota) y luego se comprueba que la pelota se mueva a la derecha (hacia la paleta) con “pelota.speed[0] >= 0” y que la pelota haya pasado la mitad de la pantalla “pelota.rect.centerx >= SCREEN_WIDTH / 2”, si ambas condiciones se cumplen se comienza a mover la paleta, en caso contrario, se queda quieta.

En el caso que la pelota se mueva hacia la paleta, se compara la posición de la paleta con la pelota: si la pelota está más arriba que la paleta, ésta última se mueve hacia arriba, por otro lado, si la pelota está más abajo que la paleta, ésta se mueve hacia abajo.

Con esto el oponente ya no es invencible, debido a que:

  • Sólo se mueve si la pelota se acerca a él y ha pasado la mitad de la pantalla, por lo que el resto del tiempo está quieto (y por lo tanto la posición de la paleta y la pelota no coinciden siempre)
  • La paleta se mueve más lento que la pelota, por lo cual en tramos largos no es capaz de alcanzar a la pelota.
  • Combinando ambas, el ordenador puede perder, aunque la superficie de la paleta es mayor a la pelota.

Para el último problema, simplemente en la parte en donde se actualiza la bola, después de reproducir el sonido, reiniciamos la posición de la bola al centro.

La versión final del juego queda de la siguiente manera:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import os
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
IMG_DIR = "imagenes"
SONIDO_DIR = "sonidos"

# ------------------------------
# Clases y Funciones utilizadas
# ------------------------------


def load_image(nombre, dir_imagen, alpha=False):
    # Encontramos la ruta completa de la imagen
    ruta = os.path.join(dir_imagen, nombre)
    try:
        image = pygame.image.load(ruta)
    except:
        print("Error, no se puede cargar la imagen: " + ruta)
        sys.exit(1)
    # Comprobar si la imagen tiene "canal alpha" (como los png)
    if alpha is True:
        image = image.convert_alpha()
    else:
        image = image.convert()
    return image


def load_sound(nombre, dir_sonido):
    ruta = os.path.join(dir_sonido, nombre)
    # Intentar cargar el sonido
    try:
        sonido = pygame.mixer.Sound(ruta)
    except (pygame.error) as message:
        print("No se pudo cargar el sonido:" + ruta)
        sonido = None
    return sonido

# -----------------------------------------------
# Creamos los sprites (clases) de los objetos del juego:


class Pelota(pygame.sprite.Sprite):
    "La bola y su comportamiento en la pantalla"

    def __init__(self, sonido_golpe, sonido_punto):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image("bola.png", IMG_DIR, alpha=True)
        self.rect = self.image.get_rect()
        self.rect.centerx = SCREEN_WIDTH / 2
        self.rect.centery = SCREEN_HEIGHT / 2
        self.speed = [3, 3]
        self.sonido_golpe = sonido_golpe
        self.sonido_punto = sonido_punto

    def update(self):
        if self.rect.left < 0 or self.rect.right > SCREEN_WIDTH:
            self.speed[0] = -self.speed[0]
            self.sonido_punto.play()  # Reproducir sonido de punto
            self.rect.centerx = SCREEN_WIDTH / 2
            self.rect.centery = SCREEN_HEIGHT / 2
        if self.rect.top < 0 or self.rect.bottom > SCREEN_HEIGHT:
            self.speed[1] = -self.speed[1]
        self.rect.move_ip((self.speed[0], self.speed[1]))

    def colision(self, objetivo):
        if self.rect.colliderect(objetivo.rect):
            self.speed[0] = -self.speed[0]
            self.sonido_golpe.play()  # Reproducir sonido de rebote


class Paleta(pygame.sprite.Sprite):
    "Define el comportamiento de las paletas de ambos jugadores"

    def __init__(self, x):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image("paleta.png", IMG_DIR, alpha=True)
        self.rect = self.image.get_rect()
        self.rect.centerx = x
        self.rect.centery = SCREEN_HEIGHT / 2

    def humano(self):
        # Controlar que la paleta no salga de la pantalla
        if self.rect.bottom >= SCREEN_HEIGHT:
            self.rect.bottom = SCREEN_HEIGHT
        elif self.rect.top <= 0:
            self.rect.top = 0

    def cpu(self, pelota):
        self.speed = [0, 2.5]
        if pelota.speed[0] >= 0 and pelota.rect.centerx >= SCREEN_WIDTH / 2:
            if self.rect.centery > pelota.rect.centery:
                self.rect.centery -= self.speed[1]
            if self.rect.centery < pelota.rect.centery:
                self.rect.centery += self.speed[1]


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    pygame.mixer.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption("Pong")

    # cargamos los objetos
    fondo = load_image("fondo.jpg", IMG_DIR, alpha=False)
    sonido_golpe = load_sound("tennis.ogg", SONIDO_DIR)
    sonido_punto = load_sound("aplausos.ogg", SONIDO_DIR)

    bola = Pelota(sonido_golpe, sonido_punto)
    jugador1 = Paleta(40)
    jugador2 = Paleta(SCREEN_WIDTH - 40)

    clock = pygame.time.Clock()
    pygame.key.set_repeat(1, 25)  # Activa repeticion de teclas
    pygame.mouse.set_visible(False)

    # el bucle principal del juego
    while True:
        clock.tick(60)
        # Obtenemos la posicion del raton
        pos_mouse = pygame.mouse.get_pos()
        mov_mouse = pygame.mouse.get_rel()

        # Actualizamos los objetos en pantalla
        jugador1.humano()
        jugador2.cpu(bola)
        bola.update()

        # Comprobamos si colisionan los objetos
        bola.colision(jugador1)
        bola.colision(jugador2)

        # Posibles entradas del teclado y raton
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit(0)
            elif event.type == pygame.KEYDOWN:
                if event.key == K_UP:
                    jugador1.rect.centery -= 5
                elif event.key == K_DOWN:
                    jugador1.rect.centery += 5
                elif event.key == K_ESCAPE:
                    sys.exit(0)
            elif event.type == pygame.KEYUP:
                if event.key == K_UP:
                    jugador1.rect.centery += 0
                elif event.key == K_DOWN:
                    jugador1.rect.centery += 0
            # Si el raton no esta quieto, mover la paleta a su posicion
            elif mov_mouse[1] != 0:
                jugador1.rect.centery = pos_mouse[1]

        # actualizamos la pantalla
        screen.blit(fondo, (0, 0))
        todos = pygame.sprite.RenderPlain(bola, jugador1, jugador2)
        todos.draw(screen)
        pygame.display.flip()


if __name__ == "__main__":
    main()

Aquí terminamos el curso, esperamos que os haya sido de utilidad. Os recomendamos que hagáis un repaso de todo lo aprendido y que rehagáis todos los ejemplos, ya que os ayudarán afianzar todos los conocimientos.

Comentaros como siempre, que el curso tiene un índice con todos los capítulos, el cual os podrá ayudar a dirigiros a los temas que queráis repasar en concreto.

Fuente > GitHub dbfuentes

Últimos análisis

Valoración RZ
8
Valoración RZ
8
Valoración RZ
8
Valoración RZ
10
Valoración RZ
8
Valoración RZ
9
Valoración RZ
9
Valoración RZ
10