Diferencia entre revisiones de «Curso Python DGA 2011/pygame/contenidos»
(→Colocar la imagen en la pantalla) |
(→Textos) |
||
(9 revisiones intermedias por el mismo usuario no mostrado) | |||
Línea 2: | Línea 2: | ||
{{MiTitulo | Contenidos}} | {{MiTitulo | Contenidos}} | ||
+ | |||
{{TOC|right}} | {{TOC|right}} | ||
Línea 127: | Línea 128: | ||
=== Manejar los rectángulos === | === Manejar los rectángulos === | ||
− | Atributos | + | Atributos para manipular un rectángulo: |
top, left, bottom, right | top, left, bottom, right | ||
topleft, bottomleft, topright, bottomright | topleft, bottomleft, topright, bottomright | ||
Línea 135: | Línea 136: | ||
w,h | w,h | ||
− | + | A una superficie le podemos pedir su rectángulo: | |
− | + | imagen.get_rect() | |
+ | |||
+ | == Un sprite de ejemplo == | ||
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | ||
− | class Banana(Sprite): | + | class Banana(Sprite): # Heredan de la clase Sprite |
− | def __init__(self, scr=None): | + | def __init__(self, scr=None): # Le pasamos la pantalla donde se dibujará |
Sprite.__init__(self) | Sprite.__init__(self) | ||
− | self.image = cargar_imagen('banana.png') | + | self.image = cargar_imagen('banana.png') # Usamos la función citada antes |
− | self.rect = self.image.get_rect() | + | self.rect = self.image.get_rect() # Guardamos el rectángulo para manipular la imagen |
− | self.scr = scr | + | self.scr = scr # Usaremos esta superficie para dibujar el sprite |
− | self.velocidad = 1 | + | self.velocidad = 1 # Velocidad a la que se moverá nuestro objeto |
def update(self): | def update(self): | ||
− | self.rect.top += self.velocidad | + | self.rect.top += self.velocidad # Movimiento descendente: aumenta el valor de y |
def draw(self): | def draw(self): | ||
− | if self.scr: self.scr.blit(self.image, self.rect) | + | if self.scr: self.scr.blit(self.image, self.rect) # Para dibujar en la pantalla |
</source> | </source> | ||
+ | |||
+ | == Movimiento == | ||
+ | El bucle principal del juego se ejecuta muchas veces por segundo. Si cambiamos la posición en que se dibuja un objeto (su rectángulo), generamos una sensación de movimento. | ||
+ | |||
El movimiento puede ser automático, generado por un evento (teclado, joystick, webcam, wiimote, ...) o por interacción con otros objetos. | El movimiento puede ser automático, generado por un evento (teclado, joystick, webcam, wiimote, ...) o por interacción con otros objetos. | ||
Línea 234: | Línea 241: | ||
== Sonidos == | == Sonidos == | ||
+ | === Sonidos del juego === | ||
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | ||
sonido = pygame.mixer.Sound(<ruta>) # soporta .wav, .mp3, .ogg | sonido = pygame.mixer.Sound(<ruta>) # soporta .wav, .mp3, .ogg | ||
Línea 240: | Línea 248: | ||
</source> | </source> | ||
+ | ===Música de fondo=== | ||
+ | pygame.mixer.music.load(ruta) | ||
+ | pygame.mixer.music.play(1) # el 1 indica repetición | ||
== Textos == | == Textos == | ||
+ | Podemos usar la fuente por defecto del sistema (None), una que tengamos instalada o un archivo con una fuente. | ||
+ | Los pasos son: | ||
+ | * Creación del objeto fuente: Prepara la definición de la fuente para el tamaño que queremos usar | ||
+ | * Render del texto, que crea una superficie | ||
+ | * Colocación de la superficie en la pantalla del juego | ||
+ | El primer paso es más costoso y lo haremos fuera del bucle principal del juego. | ||
<source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | <source lang="python" line="GESHI_NORMAL_LINE_NUMBERS"> | ||
font = pygame.font.Font(None, 28) # fuente por defecto | font = pygame.font.Font(None, 28) # fuente por defecto | ||
Línea 249: | Línea 266: | ||
screen.blit(texto, (10, 10)) | screen.blit(texto, (10, 10)) | ||
</source> | </source> | ||
+ | |||
+ | === Más utilidades para fuentes === | ||
+ | pygame.font.get_fonts -> Devuelve todas las fuentes disponibles | ||
+ | pygame.font.SysFont -> Crea un objeto fuente a partir de las fuentes del sistema. | ||
+ | |||
http://www.losersjuegos.com.ar/traducciones/pygame/font | http://www.losersjuegos.com.ar/traducciones/pygame/font | ||
Línea 275: | Línea 297: | ||
</source> | </source> | ||
− | ==Gravedad=== | + | ===Gravedad=== |
Es una aceleración hacia abajo. | Es una aceleración hacia abajo. | ||
La gravedad de la tierra es de 9.81 metros por segundo. En un juego, la gravedad constante depende del '''frame rate'''. Lo utilizamos cuando un personaje salta, en los proyectiles, etc. | La gravedad de la tierra es de 9.81 metros por segundo. En un juego, la gravedad constante depende del '''frame rate'''. Lo utilizamos cuando un personaje salta, en los proyectiles, etc. |
Última revisión de 04:30 20 dic 2011
Contenido
- 1 Pygame
- 2 Instalación
- 3 Inicializar Pygame
- 4 Crear la ventana de juego
- 5 Bucle principal del juego
- 6 Color de fondo en mi ventana
- 7 Imágenes
- 8 Un sprite de ejemplo
- 9 Movimiento
- 10 Velocidad del movimiento
- 11 Control de los límites de la pantalla
- 12 Teclado
- 13 Movimiento con el ratón
- 14 FPS: Frames por segundo
- 15 Colisiones
- 16 Rebotes
- 17 Sonidos
- 18 Textos
- 19 Animaciones
- 20 Posición y velocidad
Pygame
Pygame es una librería multiplataforma diseñada para facilitar la creación de software multimedia, sobre todo juegos. Funciona como interfaz a las bibliotecas SDL Pygame se encarga de gestionar:
- imágenes en distintos formatos (PNG, BMP, PCX, TGA, ...)
- sistemas de sonido (MOD, OGG, MP3, ...)
- operaciones relacionadas con el gestor de ventana.
- eventos de aplicación y dispositivos de entrada (mouse, teclado, joystick)
- temporizadores.
- colisiones entre objetos
Instalación
- Descarga el paquete apropiado al sistema operativo y versión de python de http://www.pygame.org/download.shtml.
- Aquí tienes más versiones compiladas para windows:
Si todo ha ido bien puedes probar los juegos de ejemplos:
python -m pygame.examples.aliens
Inicializar Pygame
import pygame
from pygame.locals import *
pygame.init()
Crear la ventana de juego
import pygame
from pygame.locals import *
ANCHO, ALTO = 640, 480
pygame.display.set_mode((ANCHO, ALTO))
pygame.display.set_caption("Mi primer juego con pygame")
Bucle principal del juego
Como en toda aplicación multimedia, en un juego pygame el bucle principal tiene que:
- comprobar los controles
- evaluar los eventos
- actualizar objetos en el juego
- refrescar la pantalla
while True:
# comprobar controles
# evaluar eventos
for eventos in pygame.event.get():
if eventos.type == QUIT:
sys.exit(0)
# actualizar los objetos (sprites)
# dibujar / refrescar la pantalla
Color de fondo en mi ventana
Cuando creamos la ventana principal, set_mode devuelve un objeto (surface) que podemos usar para colorear el fondo:
BG_COLOR = 150, 150, 80
pantalla = pygame.display.set_mode((ANCHO, ALTO))
pygame.display.set_caption("Mi primer juego con pygame")
while True:
for eventos in pygame.event.get():
if eventos.type == QUIT:
sys.exit(0)
pantalla.fill(BG_COLOR)
pygame.display.flip() # Ver referencia de flip más adelante
flip actualiza la pantalla. Pygame maneja la pantalla con Double Buffer. Primero dibuja la pantalla en segundo plano y después la hace visible.
Imágenes
Cargar imágenes
Podemos cargar un fondo así:
fondo = pygame.image.load('imagenes/escenario.jpg')
Transparencias
En Pygame se usan dos tipos de transparencias, la transparencia alpha y la de colorkey:
- Transparencia alfa (alpha)
- Se aplica a toda la imagen, es un valor que va desde 0 a 255 donde 0 es opaco y 255 es transparente, se puede hacer una imagen borrosa dandole valores intermedios
- Tranparencia colorkey
- Se aplica solo a un color de la imagen y hace ese color invisible
Una función interesante para cargar imágenes con transparencia alfa:
def cargar_imagen(nombre, optimizar=False):
ruta = os.path.join('imagenes', nombre)
imagen = pygame.image.load(ruta)
if optimizar:
return imagen.convert()
else:
return imagen.convert_alpha()
Sistemas de coordenadas
Pygame no usa el sistema de coordenadas cartesianas, con el (0,0) en el centro de la pantalla.
En pygame la esquina superior izquierda tiene la coordenada 0,0. La esquina inferior derecha tiene max_ancho-1, max_alto-1 .
Colocar la imagen en la pantalla
screen.blit(imagen, (posx, posy))
Si hay una imagen de fondo, se suele colocar:
screen.blit(fondo, (0, 0))
Sprites
Los distintos elementos de un juego tienen mucha información: imagen, posición, tipo y dirección de movimento, vidas, etc. Crearemos una clase, que hereda de Sprite para representar estos objetos. Un sprite en pygame tiene:
- self.image
- self.rect
- update(self)
Manejar los rectángulos
Atributos para manipular un rectángulo:
top, left, bottom, right topleft, bottomleft, topright, bottomright midtop, midleft, midbottom, midright center, centerx, centery size, width, height w,h
A una superficie le podemos pedir su rectángulo:
imagen.get_rect()
Un sprite de ejemplo
class Banana(Sprite): # Heredan de la clase Sprite
def __init__(self, scr=None): # Le pasamos la pantalla donde se dibujará
Sprite.__init__(self)
self.image = cargar_imagen('banana.png') # Usamos la función citada antes
self.rect = self.image.get_rect() # Guardamos el rectángulo para manipular la imagen
self.scr = scr # Usaremos esta superficie para dibujar el sprite
self.velocidad = 1 # Velocidad a la que se moverá nuestro objeto
def update(self):
self.rect.top += self.velocidad # Movimiento descendente: aumenta el valor de y
def draw(self):
if self.scr: self.scr.blit(self.image, self.rect) # Para dibujar en la pantalla
Movimiento
El bucle principal del juego se ejecuta muchas veces por segundo. Si cambiamos la posición en que se dibuja un objeto (su rectángulo), generamos una sensación de movimento.
El movimiento puede ser automático, generado por un evento (teclado, joystick, webcam, wiimote, ...) o por interacción con otros objetos.
Velocidad del movimiento
Es importante controlar la velocidad a la que se refresca la pantalla:
# creación de reloj
clock = pygame.time.Clock()
# dentro del bucle del juego
while True:
# ...
tiempo = clock.tick(60)
El juego intentará hacer 60 fps (frames por segundo)
http://www.losersjuegos.com.ar/traducciones/pygame/time/clock
Control de los límites de la pantalla
Normalmente no dejaremos que los sprites se muevan fuera de la pantalla: desaparecen, rebotan, hacemos un scroll ... En cada ciclo del juego tendremos que comprobar que los objetos no se salgan de la pantalla. Recuerda que el límite superior e izquierdo es el 0, el límite derecho es la anchura definida al crear la pantalla y el límite inferior, la altura de la pantalla.
Teclado
¿Qué teclas se han pulsado?
keys = pygame.key.get_pressed()
# comprueba si se ha pulsado la tecla de flecha arriba
if keys[K_UP]:
self.rect.centery -= self.velocidad
Podemos detectar un evento de pulsar una tecla:
if event.type == pygame.KEYDOWN:
print event.key
Aquí tienes todo el catálogo de las teclas (keycodes): http://www.pygame.org/docs/ref/key.html
Movimiento con el ratón
if event.type == pygame.MOUSEBUTTONDOWN: # o MOUSEBUTTONUP o MOUSEMOTION
(mouseX, mouseY) = pygame.mouse.get_pos()
# ...
http://www.pygame.org/docs/ref/mouse.html
FPS: Frames por segundo
Un frame es un paso completo el bloque actualizar/mostrar/espera La velocidad de ejecución debería ser la misma en todas las plataformas, pero a veces va demasiado despacio y otras demasiado deprisa. Regla de oro: como mínimo debe de haber 30 actualizaciones por segundo. Pygame cuenta el tiempo en milisegundos.
clock = pygame.time.Clock()
clock.tick(30) # 30 veces por segundo
Clock devuelve el tiempo pasado desde el frame anterior.
milliseconds = clock.tick(FPS)
playtime += milliseconds / 1000.0
Colisiones
Para comprobar si dos objetos se tocan (sus rectángulos):
pygame.sprite.collide_rect(objeto1, objeto2) pygame.sprite.collide_circle(objeto1, objeto2)
Devuelven verdadero o falso.
Si se utilizan grupos de sprites (balas, naves, enemigos, ...):
pygame.sprite.spritecollideany(objeto, grupo) pygame.sprite.groupcollide(grupo1, grupo2)
http://www.losersjuegos.com.ar/traducciones/pygame/sprite
Rebotes
Cuando un objeto rebota, el ángulo de reflexión es el mismo que el ángulo de incidencia:
Sonidos
Sonidos del juego
sonido = pygame.mixer.Sound(<ruta>) # soporta .wav, .mp3, .ogg
# ...
sonido.play()
Música de fondo
pygame.mixer.music.load(ruta) pygame.mixer.music.play(1) # el 1 indica repetición
Textos
Podemos usar la fuente por defecto del sistema (None), una que tengamos instalada o un archivo con una fuente. Los pasos son:
- Creación del objeto fuente: Prepara la definición de la fuente para el tamaño que queremos usar
- Render del texto, que crea una superficie
- Colocación de la superficie en la pantalla del juego
El primer paso es más costoso y lo haremos fuera del bucle principal del juego.
font = pygame.font.Font(None, 28) # fuente por defecto
# ...
texto = font.render("Puntos: 1000", 1, (0, 0, 0)) # Texto, antialiasing, color en RGB
# ...
screen.blit(texto, (10, 10))
Más utilidades para fuentes
pygame.font.get_fonts -> Devuelve todas las fuentes disponibles pygame.font.SysFont -> Crea un objeto fuente a partir de las fuentes del sistema.
http://www.losersjuegos.com.ar/traducciones/pygame/font
Animaciones
Las animaciones se simulan. Se va cambiando la imagen. Hay que dejar unos ciclos (milisegundos) cada imagen para que se vea en pantalla.
Posición y velocidad
- ¿Dónde está un objeto en el instante x?
- La velocidad es la proporción entre la distancia recorrida y el tiempo. En el desplazamiento tenemos que tener en cuenta también la dirección del objeto.
- Dadas las variables: posición posición original (x, y), velocidad y ángulo:
desplazamiento_x = (velocidad * cos(angulo))
desplazamiento_y = (velocidad * sin(angulo))
posicion_x += desplazamiento_x
posicion_y += desplazamiento_y
Aceleración
Cuando movemos un objeto a una velocidad, se le puede añadir una aceleración continua a la velocidad
velocidad += aceleracion
desplazamiento_x = (velocidad * cos(angulo))
desplazamiento_y = (velocidad * sin(angulo))
posicion_x += desplazamiento_x
posicion_y += desplazamiento_y
Gravedad
Es una aceleración hacia abajo. La gravedad de la tierra es de 9.81 metros por segundo. En un juego, la gravedad constante depende del frame rate. Lo utilizamos cuando un personaje salta, en los proyectiles, etc.