Razón Artificial

La ciencia y el arte de crear videojuegos

Arkanoid IV – Creando la pala

Escrito por adrigm el 30 de septiembre de 2010 en Desarrollo Videojuegos, Noticias, Programación | 12 Comentarios.

Es el momento de que nuestro juego empiece a coger algo de movimiento. En esta entrega vamos a empezar a bocetar los primeros sprites que son el alma de los juegos 2D.

El sprite pala

La pala del juego Arkanoid es el sprite que maneja el usuario, se encuentra en la parte inferior de la pantalla y el jugador debe moverla de izquierda a derecha para evitar que la bola caiga. En un principio vamos a hacer que la pala se mueva con el teclado, pero cuando empecemos añadirle extras daremos la opción de manejarla con el ratón.

Bien lo que vamos a hacer es crear un sprite parecido a los que creamos para el pong. Así que creamos un nuevo script de Python llamado sp_pallet.py he decidido poner el prefijo sp_ a los scripts de sprites para diferenciarlos.

Como casi todo sobre la creación de sprites se vio en el tutorial del Pong, pongo aquí el sprite entero que es pequeño y lo comentamos.

# -*- encoding: utf-8 -*-

import pygame
import config
import graphics

class Pallet(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = graphics.load_image(config.sprites+"pala.png", True)
        self.rect = self.image.get_rect()
        self.rect.top = 420
        self.rect.centerx = (config.width-140)/2
        self.speed = 0.5

    def update(self, dir, time):
        if dir == 1:
            if self.rect.left >= 15:
                self.rect.x -= self.speed*time
        elif dir == 2:
            if self.rect.right <= 485:
                self.rect.x += self.speed*time

    def draw(self, screen):
        screen.blit(self.image, self.rect)

Lo primero que vemos es la importación de los módulos necesarios, como casi siempre la biblioteca pygame, el archivo config y las funciones de graphics. Luego tenemos la clase Pallet, que hereda de la clase Sprite como ya explicamos en el tutorial de Pong. Cargamos, la imagen de la pala y el rect.

Por cierto, en el artículo anterior puse una pala con el fondo transparente, a veces suelen dar porblemas porque la función de cargar imágenes tiene definido que tome como color transparente el pixel (0,0) de la imagen y al ser este ya transparente pues Pygame a veces se lía. Por eso yo siempre prefiero ponerles un color que haga de colorkey así que resubo la pala con el nuevo fondo.

Recuerda renombrarla a pala.png antes de ponerla en la carpeta o dará error al cargar.

Bien siguiendo con el código obtenemos el rect, si no sabes lo que es por enésima vez te remito al tutorial del Pong. A continuación con self.rect.top modificamos a que altura de la ventana del juego esté la parte superior de nuestra pala. En nuestro caso en la posición 420 que es casi pegada a la parte inferior, pero dejando un espacio.

con self.rect.centerx más o menos lo mismo, pero la situamos en el centro del área de juego, para calcularla cogemos el ancho de la ventana (config.width que es 640) le restamos la parte del menú (que mide 140px) y lo dividimos entre 2 por lo que tendremos el centro de la pala del eje x (rect.centerx) en el centro del área de juego.

Por último con self.speed establecemos una velocidad de movimiento para la pala hemos elegido provisionalmente 0.5, pera ya veremos si es adecuada o no cuando el juego tenga todos sus elementos.

El método update

El método update como siempre se encarga de actualizar la posición de la pala. Recibe dos parámetros: dir que puede tener los valores 1 y 2. El valor 1 representa el movimiento a la izquierda y el valor 2 representa el movimiento a la derecha, según que valor le pasemos se moverá en una dirección u otra como vemos con el if dir == 1 y el elif dir == 2, nada complicado. Luego tenemos dos if más que limitan el movimiento, veamoslos.

if self.rect.left <= 15 nos dice que solo se ejecute las sentencias de su cuerpo si la parte izquierda del rect es mayor o igual que 15 esto es así porque si nos fijamos en el fondo que hemos puesto tiene un borde derecho de 10px más 5px que dejamos de margen. Lo mismo se aplica a self.rect.right <= 485 esto nos da el límite de la parte derecha del área del juego, sería un poco absurdo tener la pala sobre la barra lateral.

por ultimo usamos física básica para hacer el movimiento de la pala, todos sabemos que E = v*t o lo que es lo mismo espacio es igual a la velocidad por el tiempo. Pues bien cogemos la posición que tiene la pala (self.rect.x) y le añadimos el movimiento que viene dado por la ecuación, la verlocidad (self.speed) por el tiempo (time).

El parámetro time es el otro que teníamos y que no hemos explicado, viene del objeto director y el reloj que allí creamos y ahora veremos como se lo pasamos a la pala.

Por último tenemos el método draw que se encarga de dibujar el sprite, como vemos solo recibe el parámetro screen y hace un blit de la imagen tomando su rect como referencia, nada que ya no hayamos visto.

Poniendo la pala en la escena

Ya tenemos nuestra pala creada, es hora de colocarla en nuestro juego. Para ello vamos al archivo scene_game.py. Lo primero es crear la pala en el constroctor de la clase.

self.pallet = Pallet()

A continuación vamos a obtener el tiempo transcurrido desde la última actualización de pantalla, esto lo hacemos en el método on_update con la siguiente línea.

self.time = self.director.time

como vemos obtenemos el tiempo desde el objeto director y lo almacenamos en self.time para tener disponible en todo la escena, es importante que esté en on_update y no en el constructor porque es una variable que tiene que obtener su valor en cada paso del bucle para saber cuanto tiempo ha pasado.

Por último solo nos queda mover nuestra pala que lo haremos, en principio, con el teclado, con las flechas de dirección izquierda y derecha. Pulsar una tecla se considera un evento por lo que irá en el método on_event. En realidad da igual colocar las cosas en on_event o en on_update, pero mejor ser ordenados y cada cosa en su lugar.

Por lo que el método on_event nos quedaría así.

def on_event(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.pallet.update(1, self.time)
        if keys[pygame.K_RIGHT]:
            self.pallet.update(2, self.time)

Obtenemos las teclas pulsadas y las almacenamos en keys. Luego comprobamos si está pulsada las flechas de dirección izquierda o derecha. Según la que esté pulsada llamamos al parametro update de pallet con el valor de dir en 1 o en 2. También le pasamos el valor del tiempo transcurrido.

Por último solo nos queda dibujar la pala en pantalla. Para ello añadimos la siguiente línea al metodo on_draw.

self.pallet.draw(screen)

Y listo, podemos ejecutar nuestro juego y ver nuestra pala en acción.

12 Comentarios en "Arkanoid IV – Creando la pala"

  1. Debianitram dice:

    Mirá, tengo el siguiente error y no lo puedo solucionar.
    bash-4.0$ python main.py
    Traceback (most recent call last):
    File "main.py", line 17, in
    main()
    File "main.py", line 13, in main
    dir.loop()
    File "/home/martin/PyAprendizaje/Pygame/Arkanoid/director.py", line 50, in loop
    self.scene.on_event()
    File "/home/martin/PyAprendizaje/Pygame/Arkanoid/scene_game.py", line 28, in on_event
    self.pallet.update(2, self.time)
    AttributeError: SceneGame instance has no attribute 'time'

    Estoy atascado allí. :S

  2. Debianitram dice:

    listo, lo pude solucionar. Resulta que en la clase Director no se realizó la llamada a la función on_update().

    	def loop(self):
    		"""Pone en funcionamiento el juego"""
    
    		while not self.quit_flag:
    			self.time = self.clock.tick(60)
    
    			# Eventos
    			for event in pygame.event.get():
    				if event.type == pygame.QUIT:
    					self.quit()
    				if event.type == pygame.KEYDOWN:
    					if event.key == pygame.K_ESCAPE:
    						self.quit()
    
    			# actualiza la escena
    			self.scene.on_update #Aquí el error.
    
    			# detecta eventos
    			self.scene.on_event()
    
    			# dibuja la pantalla
    			self.scene.on_draw(self.screen)
    			pygame.display.flip()
    
  3. julian9512 dice:

    Disculpa python me dice = “Global name ‘Pallet’ is not defined” ( refiriendose al comando –>self.pallet = Pallet())
    ¿Por qué puede ser esto?

  4. adrigm dice:

    Si no veo, tu código no te puedo ayudar. Subelo a pastebin o algo similar y pon el enlace, si no es muy largo pues ponerlo aquí mismo con las etiquetas: [ python ] code [ python ] Sin los espacios.

  5. julian9512 dice:
    # -*- encoding: utf-8 -*- 
    
    import scene
    import config
    import graphics
    
     
    
    class SceneGame(scene.Scene):    
    	"""Escena inicial del juego, esta es la primera que se carga cuando inicia"""     
    
    	def __init__(self, director):        
    		scene.Scene.__init__(self, director)
    		self.back = graphics.load_image(config.menus+"back_game.png")
    		self.pallet = Pallet()
    	
    	def on_update(self):        
    		self.time = self.director.time     
    
    	def on_event(self):        
    		keys = pygame.key.get_pressed()        
    		if keys[pygame.K_LEFT]:            
    			self.pallet.update(1, self.time)        
    		if keys[pygame.K_RIGHT]:            
    			self.pallet.update(2, self.time)
    	
    	def on_draw(self, screen):        
    		screen.blit(self.back, (0, 0))
    		self.pallet.draw(screen)
    
  6. julian9512 dice:

    Me equivoque con el “code…” pero igual creo que se entiende…excepto por los espacios

  7. adrigm dice:

    ¿Tienes la clase Pallet creada? Si es así y la tienes en otro archivo te falta el import en la parte superior:

    import sp_pallet
    

    así tendrias que llamarla de la siguiente manera:

    sp_pallet.Pallet()
    

    Para llamarla a tu manera tendrías que hacer

    from sp_pallet import Pellet
    
  8. julian9512 dice:

    Ignora el anterior comentario me re-equivoque.

  9. julian9512 dice:

    ya lo coloque pero me sigue saliendo el mismo error

  10. julian9512 dice:

    Perdon ahora el error refiere a “pygame” de “keys = pygame.key_get…”

  11. adrigm dice:

    Pues lo mismo

    import pygame
    
  12. julian9512 dice:

    Muchas gracias, perdona si te moleste mucho con estas equivocaciones estupidas, soy nuevo en esto de python y pygame, y todavia no puedo identificar ciertos errores por mi cuenta.

Deja un comentario