Tutoriales no image

Publicado el 18-09-2005 | por admin

26

Programación de juegos en Python – Tutorial 3

Tutorial 3 Volvemos con la tercera entrega del tutorial para aprender a programar juegos en python, esta vez veremos como crear un “Space Invaders” sencillo pero con muchos sprites en pantalla y sonido, tambien veremos un control más amplio del teclado y nos meteremos más a fondo con temporizadores y las funciones de numeros aleatorios.

Este script lo conseguí hace más de un año en alguna web en ingles (no recuerdo cual) y simplemente lleva algunas modificaciones para utilizar las funciones que ya creamos en el tutorial 2, lo demás, lo he intentado dejar tal y como su autor, Kevin Harris, lo dejó.

También gracias a dios he utilizado sus gráficos, ya que los mios podrián haber dañado la sensibilidad de algún diseñador …

Esta vez creo que lo mejor es descargar el fuente y despues ir comentando el código nuevo que aparece en él, asi que todo el ejemplo lo podeis descargar de aquí: Tutorial 3

1. ORGANIZACIÓN

Lo primero que vemos al descomprimir el tutorial es que hay una carpeta que se llama datos, ahí es donde estan las imágenes y los sonidos del juego, es mejor tenerlo todo organizado, pues cuando la cantidad de gráficos, sonidos, animaciones, músicas, tilesets, … aumente, más difícil será encontrar lo que se busca.

Al abrir el script vemos que importamos una librería nueva, la os, que nos da información sobre el sistema operativo sobre el que se ejecuta el juego (versión, directorio …), esto nos será util para localizar los datos (graficos y sonidos) del juego, más adelante nos servirá para guardar una partida, las opciones o las máximas puntuaciones, por ejemplo.

En la sección de constantes, además de las que nos indican la resolución del juego, tenemos una nueva que es la fuente de los datos. Esto es así por si cambiamos la carpeta de sitio, no tener que modificar todas las lineas de código donde le hagamos referencia.

Los unicos cambios que se han producido en la función de cargar imagenes es que la primera linea es esta:

fullname = os.path.join(DATOS, name)

Que guarda la ruta completa de la imagen ayundandose de la constante DATOS. A partir de ahora en la función se utiliza la variable fullname para llamar a la imagen.

2. MÚSICA, MAESTRO …

La siguiente función es la que se encarga de cargar los sonidos del juego, a continuación comentaremos “linea a linea” lo que hace esta función:


def load_SoundFile(name):

     class NoneSound:
          def play(self): pass

     if not pygame.mixer or not pygame.mixer.get_init():
          return NoneSound()

     fullname = os.path.join(DATOS, name)

     try:
          sound = pygame.mixer.Sound(fullname)
     except pygame.error, message:
          print "No se pudo cargar el sonido:", fullname
          raise SystemExit, message

     return sound

Veamos, a la función le llega el nombre del archivo de sonido, pero lo primero que hacemos es crear una clase para que si algo falla, el juego siga funcionando y no se nos cuelgue por que no se pudo cargar el sonido de un laser (quizas por que haya 100.000 sonidos a la vez y la máquina donde se ejecuta el juego no tenga tantos canales, o por que no tenga tarjeta de sonido, o que esté mal configurada, por ejemplo). Asi que pasamos de esos sonidos.

Despues comprobamos que se puede ejecutar sonidos, si tiene tarjeta de sonido y está configurada. Si no, usamos la clase de NoneSound y continuamos el juego sin sonido.

Ahora, para organizarnos, pillamos la ruta del sonido y la guardamos en fullname. Esto ya sabemos para que es.

Por último intentamos cargar el sonido, si hubo algún problema es que algo no está en su sitio, y el juego debe pararse. Si todo fue correctamente, devolvemos una variable de sonido.

3. EL MOTOR DEL JUEGO (1ª PARTE)

Nos vamos a la funcion principal (main()), ya veremos las clases de los sprites más adelante, ahora es el momento de inicializar variables y lo primero que se hace es “plantar una semilla”.

La semilla es un concepto un tanto dificil de explicar sin entrar en terrenos quizas demasiado técnicos, asi que solamente diremos que es lo que hace todavia más aleatorio los números aleatorios, seleccionando como partida normalmente la fecha y hora actual. Para más informacion, la wikipedia: Números aleatorios

Lo siguiente que nos llama la atención es que a la hora de definir la pantalla (screen), vamos a usar doble-buffered por hardware, con lo cual hará que nuestro juego pueda ir más fluido gracias a la tarjeta gráfica. (Si os dá error en esta linea, simplemente quitar la opción).

Ahora cargamos todos los sonidos, nos fijamos que el nombre de las variable de sonido las acabamos con FX, esto es así para ayudarnos a diferenciarla, así es más comodo recordarlas.

Vemos que hay por ahí una variable que la hacemos global, esto significa que la variable será la misma en todo el código, y no solo en esta función principal. Nos servirá más adelante cuando tengamos que llamar al sonido del laser.

Ahora veremos otra forma de almacenar sprites, esta es más util cuando hay muchos sprites del mismo tipo. Crearemos un contenedor de sprites del tipo RenderClear que nos permitirá no solo dibujar, sino tambien limpiar los sprites que contenga.
La función que utilizamos en el tutorial 2, RenderPlain, solo nos permitia pintar, lo cual puede ser util si, como era el caso, cada vez que “refrescabamos” la pantalla, borrabamos todo. En este ejemplo, con tantos sprites a la vez, no podemos permitirnos esos lujos, asi que tenemos que ir pintando y borrando los sprites dibujados solamente, y no toda la pantalla.

Asi vemos que creamos contenedores para la nave del jugador, sus laseres, las naves enemigas y sus laseres. De camino hemos insertado ya 3 naves enemigas y hemos hecho global otra variable de los laseres enemigos.

Ahora inicializamos las variables del juego, que son las siguientes:
   running: Nos indica si se está ejecutando el bucle principal.
   addTieFighterCounter: Es la “cuenta atrás” para generar un nuevo enemigo.
   clock: Este ya lo conocemos, es el reloj que lleva los frames por segundo.

4. LOS OBJETOS DEL JUEGO

Vamos a ver cómo hemos creado los objetos del juego, para ello vamos a examinar las clases XWing, TIEFighter, XWingLaser y TIEFighterLaser.

Del objeto XWing cabe destacar que tiene dos variables de velocidad que nos permiten movernos en las 8 direcciones básicas y que el movimiento está predeterminado a la mitad inferior de la pantalla.

Los TIEFighter se mueven como la bola del tutorial 2, pero solo en la mitad superior de la pantalla. Estos sprites se inicializan en una posición (startx) dada al constructor (ya vimos este tema en el tutorial 2).
El sistema de disparo es muy sencillo, pillamos un número aleatorio entre 1 y sesenta, y si es uno, disparamos.
El disparo simplemente crea un nuevo objeto de TIEFighterLaser que veremos a continuación (usando la variable global tiefighterLaserSprites como contenedor) y “tocamos” el sonido del laser enemigo (también es una variable global llamada tiefighterShotFX).

Los dos laseres hacen los mismo, uno hacia arriba (jugador) y otro hacia abajo (enemigo). Cabe destacar que si se salen de la pantalla, se eliminan esos laseres, liberandose así recursos para la máquina.

5. EL CONTROL POR TECLADO

Una vez entramos en el bucle principal y vemos que hemos limitado la acción a 60 frames por segundo vemos todas las acciones del teclado.

Esta forma de “capturar” los eventos es diferente de la utilizada en el tutorial 2, entonces usabamos un “detector de evento” y buscabamos cuando se pulsaba una tecla.
En este caso usaremos un array que contiene todos los eventos actuales y buscaremos las teclas que nos interesan.

Sobre cuál de los dos metodos es mejor depende de la diversidad de eventos que busquemos (si miramos teclado solamente, o si miramos algo más como ratón, gamepad o joystick, o mensajes del sistema).

No creo que haga falta comentar mucho las acciones, cuando se pulsa una dirección se pone la velocidad correspondiente a 4, cuando se suelta la tecla, se pone a cero.
Cuando se pulsa el espacio se crea un laser en la posicion superior central de la nave y se “toca” el sonido del laser del jugador.

6. EL MOTOR DEL JUEGO (2ª PARTE)

Para agregar otro enemigo hemos utilizado un temporizador “casero”, contamos las veces que se ejecuta el bucle, y cada 200 veces creamos un nuevo enemigo (200 veces a 60 por segundo viene a ser a un enemigo cada 3 y pico segundos).
Es el temporizador más sencillo que hay, en futuros capitulos veremos como usar temporizadores más completos, asincronos, ect …

Para finalizar actualizamos todos los sprites (esto aún no pintará nada en pantalla) mediante la función update que tienen todos los objetos.
Limpiamos los últimos sprites pintados en base al fondo.
Pintamos la nueva situación de todos los sprites.

Por último mostramos todo en pantalla gracias al doble buffer.

Cuando se pulsa escape o se cierra la ventana se sale del bucle principal y salimos del juego automáticamente.

ULTIMAS NOTAS
En este capitulo hemos aprendido a poner sonidos, manejar muchos sprites al mismo tiempo, controlar el juego mediante el teclado y algunas cosillas como aprovechar el hardware para el doble-buffer, los números aleatorios y el ámbito de variables con las variables globales.

En el siguiente tutorial daremos un nuevo paso aprendiendo a crear menus de inicio, incluir animaciones, guardar máximas puntuaciones, leer los primeros tilesets, controlar puntuaciones, vidas …

ESTE JUEGO NO ESTÁ TERMINADO …
Este juego funciona, pero tiene bugs, por ejemplo, los enemigos no pueden alcanzarte …
¿Podrías solucionar esto?
Lo siguiente no es un bug, pero en el código, el autor hizo definiciones de variables globales en medio del código, a pesar de que esto no impide el funcionamiento del juego, queda más feo que pegarle a un padre y haría que cualquier profesor de metodologia de te tirara al cuello.
La solución para no tener que utilizar variables globales es sencilla, pero no trivial …
¿Podrias encontrar la forma de no utilizar variables globales en medio del código?


Sobre el autor



26 respuestas a Programación de juegos en Python – Tutorial 3

  1. etd says:

    el código original y pequeños mini HOWTOs en http://www.codesampler.com/python.htm

  2. OT says:

    Perdón por el off-topic pero como sigo con interes tu tutorial pensé que te gustaria echarle un vistazo a esto “Game Scripting With Python” http://slashdot.org/article.pl?sid=05/09/17/182207

  3. cut0ff says:

    Este tuto cada vez se pone más interesante. Gracias compa por el buén trabajo realizado, sigue así.

  4. ceritium says:

    Bueno, estoy ahora con este 3er manual, he hehco algunos cambios, ahora los malos desaparecen por debajo, y aparecen por encima de la pantalla,

    Ahora quiero añadir un marcador, el tema de los puntos es facil

    for hit in pygame.sprite.groupcollide( tiefighterSprites, xwingLaserSprites, 1, 1):
    explode1FX.play()
    puntos+=1

    pero ahora no consigo imprimir texto en pantalla, en el tutorial 2 lo hice con esto

    fonte = pygame.font.Font(None, 80)
    texto = fonte.render(str(puntos), 1,(255,255,255,0))
    screen.blit(texto1, (100,30))

    pero el 3 trabaja distinto el tema de los sprites, pero no lo consigo descifrar… alguien me puede ayudar?

  5. cut0ff says:

    ceritium, un apunte solo. En el foro hay una sección dedicada a la programación de juegos. Puedes formular tus preguntas ahí, incluso sin necesidad de registrarte. Gracias.

  6. dvl says:

    Bueno, gracias aetd por recordarme la página, OT, no he tenido mucho tiempo de leer pero creo que los tiros de ese “libro” van por otro lado.

    ceritium, el problema es que esta vez no recargamos el fondo cada vez, asi que se pintarán los números uno encima de otro … como muy bién dice cutOff, la respuesta en el foro (ya esta disponible para que la leas, y si quieres, la comentamos en el canal de jabberes).

  7. ceritium says:

    joder es verdad el lbog tiene foro XD, es la cosa de leer solo las feeds xD y cuando entro en la web es solo para postear xD gracias a todos por responder, voy a leer el foro.

  8. Done says:

    hola a todos compatriotas del buen mundo, si es dvl quien esta haciendo este tercer tutorial quisiera pedirle un favor, es que me he perdido el uno y quisiera saber donde lo puedo encontrar. eso si serìa genial si empastaìs en pdf y anexas las imagenes para que quede fenomeno. si alguno de vosotros tiene lo que necesito me lo podeìs mandar a mi correo, soy novato y quisiera entrar en este fabuloso mundo. escribidme a donaldoquintana@yahoo.es

  9. Pingback: Sukiweb.net » Programando en Python

  10. Done says:

    alguno de ustedes sabe donde puedo descargar PyQt, sip y las dependencias de eric estoy al rojo buscando las dependencias y aun no he podido instalar el eric en mi suse linux 9.2
    donaldoquintana@yahoo.es

  11. javi says:

    Un ejemplo de lo que se puede hacer con pygame y pyopengl lo he dejado en mi blog

    http://blep.blogspot.com/2005/09/makefight.html

  12. dvl says:

    Done, pincha en la sección tutoriales, ahí están todos, con respecto a las pyQT para nuestro linux tiene que venir con cualquier distro si no, busca en el repositorio de alguna, seguro que viene (rediris, por ejemplo).

    Muchisimas gracias Javi, si, se puede hacer todo eso y más, ya lo veremos en la siguiente serie de tutoriales para juegos en 3D … si dios quiere 😀

  13. javi says:

    @dvl: No tengo que decir que si quieres ayuda en el tema python + (Opengl or ODE or Image) no tienes más que escribirme un mail. Tengo bastante código interesante del jueguecillo del que he dejado las imágenes.

    un saludo

  14. Done says:

    amigos quisiera saber cual es la mejor distro para juegos que aproveche la tarjeta de video, se pueda configurar facilmente y pos supuesto sacarle el jugo.
    cual es entonces la distro mejor optimizada para jugones? y programadores de juegos.

  15. ominae says:

    hace tiempo que no sacais otro capitulo del tutorial…¿se ha terminado? como en uno de los anteriores comentavais que se usaria el juego en red y aun no lo habeis utilizado pensaba quedavan mas capitulos. Bueno, enorabuena por el tutorial esta muy bien. Quiza un capitulo lo podriais dedicar a juegos 3D con el modulo que anunciais en la pagina principal.

    Un saludo.
    ominae

  16. Leon says:

    Estos no iban a ser seis tutoriales? hace un montón que estoy esperando por los tres últimos.

  17. Dividio says:

    Los tutoriales los escribe DVL, por el foro comentó un día que no andaba muy bien de tiempo para poder continuar los tutoriales.

  18. alex pinto says:

    sigo sin poder hacer nada no puedo ni siquiera descomprimir el tutorial no habre naa

  19. San Dalia says:

    La verdad que el tut es de rechupete, lo unico que no me queda claro que es el SDL, supongo un conj de libs pero, ¿para que?.

  20. Giancarlo velasquez valmori says:

    creo k python es muy BURIDOM Y ADEMAS LO K COPIO DE AKI NO FUNCIONA.JEJE

  21. dvd says:

    Felicitaciones dvl por tu trabajo, este tutorial me esta siendo de gran ayuda. La información que hay en castellano por lo que he visto es muy escasa, es una lastima que se haya quedado abandonado (por lo que veo). Estaría bien que si tu por problemas de tiempo no puedes continuar alguien lo hiciese.

  22. Tamara navas says:

    eres un tonto dvd no sabes ni escribir ainhoa t quiere.feo estos chat no comentarios

  23. Tamara navas says:

    hola me llamo tamara mi messenger es tamara-loca@hotmail.com

  24. Demian says:

    …..Y que paso con los otros tres tutoriales restantes, creí que habia leido al principio que eran 6, es una lastima que alguien no haya seguido el hilo ya que se estaba poniendo cada vez mas interesante, Saludos

  25. Croasan says:

    Enhorabuena, los tutoriales son excelentes, espero que pronto puedas encontrar el tiempo suficiente para publicar el resto.

    Me preguntaba si has pensado en hacer algo en vista isometrica, me gustaria hacer algo asi con python.

    Lo dicho, enhorabuena por los tutoriales y gracias, excelente trabajo.

  26. julian says:

    quisiera saber urgente como hacer un contador de puntos 1 a 1 en phyton? y que salga en la pantalla

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Back to Top ↑