<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Python Mania</title>
	<atom:link href="http://pythonmania.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://pythonmania.wordpress.com</link>
	<description>Un Blog donde dejo mis apuntes de python</description>
	<lastBuildDate>Sat, 07 Jan 2012 07:56:27 +0000</lastBuildDate>
	<language>es</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='pythonmania.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Python Mania</title>
		<link>http://pythonmania.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://pythonmania.wordpress.com/osd.xml" title="Python Mania" />
	<atom:link rel='hub' href='http://pythonmania.wordpress.com/?pushpress=hub'/>
		<item>
		<title>consolas web de python</title>
		<link>http://pythonmania.wordpress.com/2010/08/08/consolas-web-de-python/</link>
		<comments>http://pythonmania.wordpress.com/2010/08/08/consolas-web-de-python/#comments</comments>
		<pubDate>Sun, 08 Aug 2010 21:58:04 +0000</pubDate>
		<dc:creator>Daniel Fuentes B.</dc:creator>
				<category><![CDATA[herramientas]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://pythonmania.wordpress.com/?p=612</guid>
		<description><![CDATA[Me encontré con estos sitios que te permiten usar una consola python via web y ver la salida que produce, puede ser útil para algunas pruebas rápidas. Estos dos te muestran el interprete y la salida que produce de forma interactiva: http://shell.appspot.com/ http://try-python.mired.org/ Mientras que estos otros dos nos permiten escribir un script y luego [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=612&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Me encontré con estos sitios que te permiten usar una consola python via web y ver la salida que produce, puede ser útil para algunas pruebas rápidas.</p>
<p>Estos dos te muestran el interprete y la salida que produce de forma interactiva:</p>
<ul>
<li><a href="http://shell.appspot.com/">http://shell.appspot.com/</a></li>
<li><a href="http://try-python.mired.org/">http://try-python.mired.org/</a></li>
</ul>
<p>Mientras que estos otros dos nos permiten escribir un script y luego probar como funciona:</p>
<ul>
<li><a href="http://pythonwebconsole.thomnichols.org/">http://pythonwebconsole.thomnichols.org/</a></li>
<li><a href="http://codepad.org/">http://codepad.org/</a> (este también funciona como pastebin y soporta varios lenguajes)</li>
</ul>
<p>Obviamente por motivos de seguridad tienen algunos modulos algo capados, pero pueden resultar útiles <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/pythonmania.wordpress.com/612/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pythonmania.wordpress.com/612/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/pythonmania.wordpress.com/612/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pythonmania.wordpress.com/612/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/pythonmania.wordpress.com/612/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/pythonmania.wordpress.com/612/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/pythonmania.wordpress.com/612/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/pythonmania.wordpress.com/612/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/pythonmania.wordpress.com/612/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pythonmania.wordpress.com/612/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/pythonmania.wordpress.com/612/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pythonmania.wordpress.com/612/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/pythonmania.wordpress.com/612/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pythonmania.wordpress.com/612/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=612&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://pythonmania.wordpress.com/2010/08/08/consolas-web-de-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<georss:point>-33.425360 -70.566466</georss:point>
		<geo:lat>-33.425360</geo:lat>
		<geo:long>-70.566466</geo:long>
		<media:content url="" medium="image">
			<media:title type="html">Daniel F.</media:title>
		</media:content>
	</item>
		<item>
		<title>Tutorial Pygame 4: manejo de figuras y texto (simular el lanzamiento de un proyectil)</title>
		<link>http://pythonmania.wordpress.com/2010/07/14/tutorial-pygame-4-figuras-y-texto/</link>
		<comments>http://pythonmania.wordpress.com/2010/07/14/tutorial-pygame-4-figuras-y-texto/#comments</comments>
		<pubDate>Wed, 14 Jul 2010 17:37:30 +0000</pubDate>
		<dc:creator>Daniel Fuentes B.</dc:creator>
				<category><![CDATA[pygame]]></category>
		<category><![CDATA[tutoriales]]></category>

		<guid isPermaLink="false">http://pythonmania.wordpress.com/?p=520</guid>
		<description><![CDATA[En esta parte del tutorial se va a simular el lanzamiento de un proyectil (una esfera), para mostrar las siguientes temas: Rellenar el fondo con un color especifico Dibujar lineas en la pantalla Dibujar un circulo Sincronizar el movimiento usando tiempo A continuación la explicación (aunque es recomendable que hayan leído la parte anterior antes [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=520&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>En esta <a href="http://pythonmania.wordpress.com/2010/03/23/tutorial-pygame-introduccion/">parte del tutorial</a> se va a simular el lanzamiento de un proyectil (una esfera), para mostrar las siguientes temas:</p>
<ul>
<li>Rellenar el fondo con un color especifico</li>
<li>Dibujar lineas en la pantalla</li>
<li>Dibujar un circulo</li>
<li>Sincronizar el movimiento usando tiempo</li>
</ul>
<p>A continuación la explicación (aunque es recomendable que hayan leído <a href="http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/">la parte anterior</a> antes de seguir):</p>
<p><span id="more-520"></span><br />
<strong>Paso 1: Creando lo básico (rellenar el fondo y dibujar lineas)</strong></p>
<p>Lo primero es crear la ventana, que tendrá un fondo azul y en donde dibujaremos una linea blanca que servirá de separador (en la parte de arriba se mostrara la información más adelante).</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/07/14/tutorial-pygame-4-figuras-y-texto

# ---------------------------
# Importación de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import sys

# -----------
# Constantes
# -----------

WIDTH = 640
HEIGHT = 480

# ------------------------------
# Clases y Funciones utilizadas
# ------------------------------


# ------------------------------
# Función principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption(&quot;tutorial pygame parte 4&quot;)

    # el bucle principal del juego
    while True:
        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == K_ESCAPE:
                    sys.exit()

        # Re dibujar los elementos en pantalla
        screen.fill((30, 145, 255))
        pygame.draw.line(screen, (255, 255, 255), (0, 25), (640, 25), 2)
        # actualizamos la pantalla
        pygame.display.flip()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>La mayor parte de este código la explicamos en <a href="http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/">la segunda parte</a> del tutorial. Lo nuevo es que en vez de usar una imagen de fondo, utilizamos un color para rellenar la pantalla al hacer <em>screen.fill((30, 145, 255))</em> que en términos simples llena la pantalla con un color celeste, el color se ingresa usando <a href="http://es.wikipedia.org/wiki/Modelo_de_color_RGB">el valor RGB del color</a>, que en este caso es (30, 145, 255)</p>
<blockquote><p>El RGB (Red, Green, Blue) es un modelo de color en donde cualquier color se puede formar mediante los colores primarios (rojo, verde, azul).</p>
<p>Los colores primarios se representan de la siguiente manera: el rojo es el (255,0,0), el verde con (0,255,0) y el azul con (0,0,255). La ausencia de color (o sea el negro) es el (0,0,0) y el blanco (255,255,255)</p>
<p>Cualquier otro color se obtiene con la mezcla de estos, como por ejemplo el amarillo se obtiene al combinar el rojo con el verde, o sea (255,255,0) y lo mismo para el resto de los colores.</p></blockquote>
<p>Lo otro fue dibujar una linea blanca en la ventana, para dibujar lineas se usa <a href="http://www.losersjuegos.com.ar/traducciones/pygame/draw#line">line del modulo draw</a> de la siguiente forma:</p>
<p><pre class="brush: python;">
pygame.draw.line(Superficie, Color, Inicio, Fin, Grosor)
</pre></p>
<p>Que en este caso con <em>pygame.draw.line(screen, (255, 255, 255), (0, 25), (640, 25), 2)</em> Ocurre lo siguiente: la superficie sobre la cual se dibuja es la pantalla (que llamamos screen), el color de la linea es blanco (255, 255, 255) y dibuja os una linea paralela a 25 pixeles del borde, por lo que comienza en (0, 25) y termina en (640, 25) y esta linea es de 2 pixeles de ancho (grosor)</p>
<blockquote><p>Existe también el pygame.draw.aaline() que dibuja lineas aplicando anti-alias (suavizar el borde de linea para que la linea no se vea pixelada o escalonada) y su uso es el siguiente<br />
<pre class="brush: python;">
pygame.draw.aaline(Superficie, Color, Inicio, Fin, blend=1)
</pre><br />
Si blend está en valor True (1), las figuras se mezclarán con la tonalidad de los pixeles existentes en lugar de sobre-escribirlos.</p></blockquote>
<p><strong>Paso 2: Crear el proyectil (dibujar un circulo) y mostrar texto</strong></p>
<p>Ahora dibujaremos un circulo (que sera nuestro proyectil) en la esquina inferior izquierda y crearemos un sprite que contenga la información del proyectil.</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/07/14/tutorial-pygame-4-figuras-y-texto

# ---------------------------
# Importación de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import sys

# -----------
# Constantes
# -----------

WIDTH = 640
HEIGHT = 480

# ------------------------------
# Clases y Funciones utilizadas
# ------------------------------


class Proyectil(pygame.sprite.Sprite):
    &quot;Clase que representa el proyectil lanzado&quot;

    def __init__(self, x, y):
        self.angulo = 45
        self.veloc = 50
        self.tiempo = 0
        self.x = x
        self.y = y
        self.xreal = x
        self.yreal = HEIGHT - self.y


# ------------------------------
# Función principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption(&quot;tutorial pygame parte 4&quot;)

    # se define la letra por defecto
    fuente = pygame.font.Font(None, 20)

    # se crea un proyectil a lanzar
    bala = Proyectil(0, HEIGHT)

    # el bucle principal del juego
    while True:
        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == K_ESCAPE:
                    sys.exit()

        text = &quot;Velocidad: %3d (m/s)   Angulo: %d   x=%d m   y=%d m&quot; % (
            bala.veloc, bala.angulo, bala.xreal, bala.yreal)
        mensaje = fuente.render(text, 1, (255, 255, 255))

        # Re dibujar los elementos en pantalla
        screen.fill((30, 145, 255))
        screen.blit(mensaje, (15, 5))
        pygame.draw.line(screen, (255, 255, 255), (0, 25), (640, 25), 2)
        pygame.draw.circle(screen, (0, 0, 0), (int(bala.x), int(bala.y)), 10)
        # actualizamos la pantalla
        pygame.display.flip()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Creamos una clase (sprite) que representa nuestro proyectil y le ingresamos algunos valores por defecto como son el angulo y velocidad de disparo, o sea esta parte:</p>
<p><pre class="brush: python;">
class Proyectil(pygame.sprite.Sprite):
    &quot;Clase que representa el proyectil lanzado&quot;

    def __init__(self, x, y):
        self.angulo = 45
        self.veloc = 50
        self.tiempo = 0
        self.x = x
        self.y = y
        self.xreal = x
        self.yreal = HEIGHT - self.y
</pre></p>
<p>Si se fijan el tiempo lo dejamos en 0 (ya que comenzara a contar a partir del disparo del proyectil) y definimos dos valores self.x, self.y que representan la posición del proyectil en la pantalla y otro par de valores self.xreal, self.yreal que después tomaran la posición que se calcule que tendrá el proyectil, estos valores serán diferentes en el eje y, ya que pygame considera el (0,0) en la equina superior izquierda y las formulas físicas que describen el movimiento (ver mas adelante) consideran el (0,0) en la esquina inferior izquierda. Mas adelante (en el while True) iniciamos esta clase (bajo el nombre de &#8220;bala&#8221;) con la posición inicial de esta (en este caso la esquina inferior izquierda).</p>
<p>Ahora vamos a mostrar en pantalla un texto (que aparecerá en la parte superior de la ventana) indicando la información básica del proyectil: angulo y velocidad de disparo (al momento de disparar) y su posición. Para mostrar el texto primero definimos la fuente a utilizar y su tamaño haciendo: <em>fuente = pygame.font.Font(None, 20)</em></p>
<blockquote><p>En pygame.font.Font el primer valor es la ubicación y nombre de la fuente utilizada.  Si se ingresa None se utiliza la fuente por defecto. </p>
<p>El segundo valor es la altura de la fuente (en pixeles).</p></blockquote>
<p>Luego almacenamos el mensaje como una cadena de texto en la variable &#8220;text&#8221; (usando la información obtenida desde la clase &#8220;bala&#8221;) y este texto se tiene que dibujar en alguna superficie (pygame no puede dibujar el texto directamente, sino hay que crear una &#8220;imagen&#8221; de de ese texto), para lo cual usamos <em>mensaje =  fuente.render(text, 1, (255, 255, 255))</em> con lo cual almacenamos esa &#8220;imagen&#8221; en el objeto mensaje (tal como si fuera un sprite) y después de manera análoga a un sprite esa &#8220;imagen&#8221; se muestra en la pantalla usando <em>screen.blit(mensaje, (15, 5))</em> donde (15, 5) es la posición en que se muestra (arriba a la izquierda)</p>
<blockquote><p>El <a href="http://www.losersjuegos.com.ar/traducciones/pygame/font/font#render">Font.render</a> toma como primer valor la cadena de texto a mostrar, el segundo valor es si usa antialias (=1) o no y el tercero es el color del texto. Se puede agregar un cuarto valor para crear un borde en el texto</p></blockquote>
<p>Por ultimo hacemos: <em>pygame.draw.circle(screen, (0, 0, 0), (int(bala.x), int(bala.y)), 10)</em> En este caso dibujamos un circulo en la la pantalla/ventana (que llamamos screen) este es de un color negro, que esta en la posición (bala.x, bala.y) o sea en la esquina inferior izquierda (aunque después al disparar el proyectil estos valores se modifican, moviendo el circulo), los int son para transformar los valores a números enteros, ya que los valores originales pueden ser decimales y el ultimo valor le indica que el circulo tiene un radio de 10 px.</p>
<p><strong>Paso 3: preparando el proyectil </strong></p>
<p>Ahora vamos a modificar un poco nuestro juego, de tal manera que podamos aumentar o disminuir tanto el angulo como la velocidad de disparo. </p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/07/14/tutorial-pygame-4-figuras-y-texto

# ---------------------------
# Importación de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import sys

# -----------
# Constantes
# -----------

WIDTH = 640
HEIGHT = 480

# ------------------------------
# Clases y Funciones utilizadas
# ------------------------------


class Proyectil(pygame.sprite.Sprite):
    &quot;Clase que representa el proyectil lanzado&quot;

    def __init__(self, x, y):
        self.angulo = 45
        self.veloc = 50
        self.tiempo = 0
        self.x = x
        self.y = y
        self.disparar = False
        self.xreal = x
        self.yreal = HEIGHT - self.y

    def update(self):
        &quot;actualizar la posición del proyectil&quot;

        if self.disparar == True:
            # esta en movimiento, hay que actualizar la posición
            pass
        else:
            # se mantiene sin disparar, por lo cual no se hace nada
            pass

        # si sale de la pantalla reiniciar la posición (a inferior izq.)
        if (self.y &gt; HEIGHT) or (self.x &gt; WIDTH):
            self.x = 0
            self.y = HEIGHT
            self.disparar = False

# ------------------------------
# Función principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption(&quot;tutorial pygame parte 4&quot;)

    # se define la letra por defecto
    fuente = pygame.font.Font(None, 20)

    # se crea un proyectil a lanzar
    bala = Proyectil(0, HEIGHT)

    pygame.key.set_repeat(1, 80)  # Activa repetición de teclas

    # el bucle principal del juego
    while True:
        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == K_UP:
                    if bala.angulo &lt; 90:
                        bala.angulo = bala.angulo + 1
                elif event.key == K_DOWN:
                    if bala.angulo &gt; 0:
                        bala.angulo = bala.angulo - 1
                elif event.key == K_RIGHT:
                    if bala.veloc &lt; 100:
                        bala.veloc = bala.veloc + 1
                elif event.key == K_LEFT:
                    if bala.veloc &gt; 10:
                        bala.veloc = bala.veloc - 1
                elif event.key == K_SPACE:
                    bala.disparar = True
                elif event.key == K_ESCAPE:
                    sys.exit()

        # Actualizar la posición e información
        bala.update()
        text = &quot;Velocidad: %3d (m/s)   Angulo: %d   x=%d m   y=%d m&quot; % (
            bala.veloc, bala.angulo, bala.xreal, bala.yreal)
        mensaje = fuente.render(text, 1, (255, 255, 255))

        # Re dibujar los elementos en pantalla
        screen.fill((30, 145, 255))
        screen.blit(mensaje, (15, 5))
        pygame.draw.line(screen, (255, 255, 255), (0, 25), (640, 25), 2)
        pygame.draw.circle(screen, (0, 0, 0), (int(bala.x), int(bala.y)), 10)
        # actualizamos la pantalla
        pygame.display.flip()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>El código es bastante sencillo, en la parte en donde se detecta que teclas se han pulsado se limita la velocidad y angulo de disparo de la siguiente manera: Al pulsar la flecha hacia arriba que se aumente el angulo (hasta un máximo de 90 <a href="http://es.wikipedia.org/wiki/Grado_sexagesimal">grados (sexagesimales)</a>, o sea un angulo recto) y la flecha hacia abajo lo disminuye hasta un angulo de 0 grados. Mientes que a la derecha se aumenta la velocidad (hasta un máximo de 100) y a la izquierda se disminuye la velocidad (hasta un mínimo de 10).</p>
<p>Dentro de la clase proyectil (o sea la bala) se ha definido un metodo update (que después es utilizado en el while True) y que va actualizando la posición del proyectil en la pantalla. En este método se agrega una comprobación de tal manera que si el proyectil sale de la pantalla los valores se reinicien</p>
<p>Si se fijan el valor por defecto para self.disparar es False. De esta manera al pulsar a barra espaciadora se dispara el proyectil (cambiando el valor de disparar a True), por lo que al llamar el bala.update() se va calculando la nueva posición de la bala (a continuación se explicara como obtener la nueva posición)</p>
<p><strong>Un poco de física</strong></p>
<p>Antes de continuar hay que entender la base del lanzamiento de proyectiles, la cual voy a intentar explicarla de una manera sencilla a continuación.</p>
<p>Voy a considerar el punto (0,0) &#8220;el origen&#8221; como la esquina inferior izquierda, para que se mantengan las ecuaciones de la misma forma en que se encontrarían en un libro (después se va a ajustar el valor para que corresponda con el de pygame)</p>
<p>Como se trata de un <a href="http://es.wikipedia.org/wiki/Trayectoria_bal%C3%ADstica">lanzamiento de proyectiles</a>, podemos aplicar algunos supuestos para simplificar el problema: </p>
<ul>
<li><strike>la vaca es esférica y sin rozamiento</strike></li>
<li>No tendremos en cuenta el efecto de rotación de la Tierra (que desvía el proyectil)</li>
<li>La velocidad del proyectil es suficientemente pequeña como para despreciar la resistencia que presenta el aire en oposición a su movimiento (roce)</li>
<li>La aceleración de gravedad <strong><em>g</em></strong> es constante (no varia su valor con la altura ni con curvatura de la superficie terrestre)</li>
</ul>
<p>Entonces tenemos (de forma simplificada) las siguientes ecuaciones para determinar la posición (en cualquier momento) de un objeto en el eje x e y:</p>
<p><img src='http://s0.wp.com/latex.php?latex=x%3D+x_%7B0%7D%2Bv_%7Bx%7Dt+%2B%7B%5Cfrac%7B1%7D%7B2%7D%7Dat%5E2+&amp;bg=ffffff&amp;fg=666666&amp;s=1' alt='x= x_{0}+v_{x}t +{&#92;frac{1}{2}}at^2 ' title='x= x_{0}+v_{x}t +{&#92;frac{1}{2}}at^2 ' class='latex' /><br />
<img src='http://s0.wp.com/latex.php?latex=y%3D+y_%7B0%7D%2Bv_%7By%7Dt+%2B%7B%5Cfrac%7B1%7D%7B2%7D%7Dat%5E2+&amp;bg=ffffff&amp;fg=666666&amp;s=1' alt='y= y_{0}+v_{y}t +{&#92;frac{1}{2}}at^2 ' title='y= y_{0}+v_{y}t +{&#92;frac{1}{2}}at^2 ' class='latex' /></p>
<p>Como en nuestro caso, el objeto a lanzar (la esfera o proyectil) esta inicialmente en el origen (0,0) por lo cual:<br />
<img src='http://s0.wp.com/latex.php?latex=x_%7B0%7D%3D0&amp;bg=ffffff&amp;fg=666666&amp;s=0' alt='x_{0}=0' title='x_{0}=0' class='latex' />  e  <img src='http://s0.wp.com/latex.php?latex=y_%7B0%7D%3D0&amp;bg=ffffff&amp;fg=666666&amp;s=0' alt='y_{0}=0' title='y_{0}=0' class='latex' /></p>
<p>Además la única aceleración que afecta el proyectil es la gravedad (y que solo influye de manera vertical), por lo tanto en este caso queda:</p>
<p><img src='http://s0.wp.com/latex.php?latex=x%3D+0+%2B+v_%7Bx%7Dt&amp;bg=ffffff&amp;fg=666666&amp;s=0' alt='x= 0 + v_{x}t' title='x= 0 + v_{x}t' class='latex' /><br />
<img src='http://s0.wp.com/latex.php?latex=y%3D+0+%2B+v_%7By%7Dt+%2B+%7B%5Cfrac%7B1%7D%7B2%7D%7Dgt%5E2&amp;bg=ffffff&amp;fg=666666&amp;s=0' alt='y= 0 + v_{y}t + {&#92;frac{1}{2}}gt^2' title='y= 0 + v_{y}t + {&#92;frac{1}{2}}gt^2' class='latex' /></p>
<p>Esto es una parábola. Si consideraremos a la <a href="http://es.wikipedia.org/wiki/Intensidad_de_la_gravedad">aceleración de gravedad</a> con un valor de g = -9,8 (el signo menos es porque actúa hacia abajo) y la velocidad con la que se lanza el proyectil <a href="http://es.wikipedia.org/wiki/Vector_%28f%C3%ADsica%29">es un vector </a>(que depende del ángulo y su valor), por lo que hay que descomponerla en sus componentes horizontal (<img src='http://s0.wp.com/latex.php?latex=v_%7Bx%7D&amp;bg=ffffff&amp;fg=666666&amp;s=0' alt='v_{x}' title='v_{x}' class='latex' />) y vertical (<img src='http://s0.wp.com/latex.php?latex=v_%7By%7D&amp;bg=ffffff&amp;fg=666666&amp;s=0' alt='v_{y}' title='v_{y}' class='latex' />): </p>
<p>Ya que es un vector <a href="http://es.wikipedia.org/wiki/Vector_%28f%C3%ADsica%29#Componentes_de_un_vector">la suma de sus componentes</a> (horizontal y vertical) da el valor del modulo del vector. Además el modulo del vector con las componentes de este en el eje x e y forman un triangulo, por lo que aplicando <a href="http://es.wikipedia.org/wiki/Trigonometr%C3%ADa#Razones_trigonom.C3.A9tricas">trigonometría</a> se puede determinar los valores de los componentes horizontal y vertical:</p>
<p><a href="http://pythonmania.files.wordpress.com/2010/07/pygame_vector_velocidad.png"><img src="http://pythonmania.files.wordpress.com/2010/07/pygame_vector_velocidad.png?w=300&#038;h=231" alt="vector velocidad" title="pygame_vector_velocidad" width="300" height="231" class="aligncenter size-medium wp-image-587" /></a></p>
<p>En la imagen se aprecia el triangulo que se forma, así tenemos las siguientes razones trigonometricas:</p>
<p><img src='http://s0.wp.com/latex.php?latex=cos%7B%5Calpha%7D+%3D+%7B%5Cfrac%7Bv_%7Bx%7D%7D%7Bv%7D%7D+&amp;bg=ffffff&amp;fg=666666&amp;s=1' alt='cos{&#92;alpha} = {&#92;frac{v_{x}}{v}} ' title='cos{&#92;alpha} = {&#92;frac{v_{x}}{v}} ' class='latex' /><br />
<img src='http://s0.wp.com/latex.php?latex=sen%7B%5Calpha%7D+%3D+%7B%5Cfrac%7Bv_%7By%7D%7D%7Bv%7D%7D+&amp;bg=ffffff&amp;fg=666666&amp;s=1' alt='sen{&#92;alpha} = {&#92;frac{v_{y}}{v}} ' title='sen{&#92;alpha} = {&#92;frac{v_{y}}{v}} ' class='latex' /></p>
<p>Despejando tenemos:</p>
<p><img src='http://s0.wp.com/latex.php?latex=v_%7Bx%7D+%3D+%7Bv%7D+%7Bcos%7B%5Calpha%7D%7D+&amp;bg=ffffff&amp;fg=666666&amp;s=0' alt='v_{x} = {v} {cos{&#92;alpha}} ' title='v_{x} = {v} {cos{&#92;alpha}} ' class='latex' /><br />
<img src='http://s0.wp.com/latex.php?latex=v_%7By%7D+%3D+%7Bv%7D+%7Bsen%7B%5Calpha%7D%7D+&amp;bg=ffffff&amp;fg=666666&amp;s=0' alt='v_{y} = {v} {sen{&#92;alpha}} ' title='v_{y} = {v} {sen{&#92;alpha}} ' class='latex' /></p>
<p>Con lo cual se puede obtener la componente en ambos ejes de la velocidad.</p>
<p>Así en resumen, el proyectil tendrá el siguiente comportamiento:</p>
<ul>
<li>De forma horizontal solo depende de la velocidad (que es constante), por lo que se moverá en este caso hacia la derecha</li>
<li>De forma vertical tenemos a la velocidad que lo impulsa hacia arriba y la gravedad que se opone (hacia abajo). Por lo cual el proyectil en un inicio comenzara a subir, pero luego por la aceleración de gravedad comenzara a caer (el tiempo esta al cuadrado en el segundo termino, por lo cual al aumentar t (el tiempo), la aceleración por el tiempo al cuadrado terminara superando a la velocidad por el tiempo y en ese instante empezara a caer)</li>
</ul>
<p><strong>Paso 4: Movimiento del proyectil</strong></p>
<p>Ahora aplicamos lo anterior en nuestro programa, por lo que modificamos el método update para que a medida que trascurre el tiempo calcule la posición del proyectil, por lo la versión final de nuestro juego / simulador queda de la siguiente manera:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/07/14/tutorial-pygame-4-figuras-y-texto

# ---------------------------
# Importación de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import sys
import math

# -----------
# Constantes
# -----------

WIDTH = 640
HEIGHT = 480

# ------------------------------
# Clases y Funciones utilizadas
# ------------------------------


class Proyectil(pygame.sprite.Sprite):
    &quot;Clase que representa el proyectil lanzado&quot;

    def __init__(self, x, y):
        self.angulo = 45
        self.veloc = 50
        self.tiempo = 0
        self.x = x
        self.y = y
        self.disparar = False
        self.xreal = x
        self.yreal = HEIGHT - self.y

    def update(self):
        &quot;actualizar la posición del proyectil&quot;
        self.velocx = self.veloc * math.cos(math.radians(self.angulo))
        self.velocy = self.veloc * math.sin(math.radians(self.angulo))

        if self.disparar == True:
            # esta en movimiento, hay que actualizar la posición
            self.xreal = (0 + self.velocx * self.tiempo)
            self.yreal = (0 + self.velocy * self.tiempo +
                (-9.8 * (self.tiempo ** 2)) / 2)
            # Corregir la posición en el eje vertical
            self.x = self.xreal
            self.y = HEIGHT - self.yreal
        else:
            # se mantiene sin disparar, por lo cual no se hace nada
            pass

        # si sale de la pantalla reiniciar la posición (a inferior izq.)
        if (self.y &gt; HEIGHT) or (self.x &gt; WIDTH):
            self.x = 0
            self.y = HEIGHT
            self.tiempo = 0
            self.disparar = False

# ------------------------------
# Función principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption(&quot;tutorial pygame parte 4&quot;)

    # se define la letra por defecto
    fuente = pygame.font.Font(None, 20)

    # se crea un proyectil a lanzar
    bala = Proyectil(0, HEIGHT)

    pygame.key.set_repeat(1, 80)  # Activa repetición de teclas
    clock = pygame.time.Clock()

    # el bucle principal del juego
    while True:
        # registramos cuanto ha pasado desde el ultimo ciclo
        tick = clock.tick(60)
        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == K_UP:
                    if bala.angulo &lt; 90 and bala.disparar == False:
                        bala.angulo = bala.angulo + 1
                elif event.key == K_DOWN:
                    if bala.angulo &gt; 0 and bala.disparar == False:
                        bala.angulo = bala.angulo - 1
                elif event.key == K_RIGHT:
                    if bala.veloc &lt; 100 and bala.disparar == False:
                        bala.veloc = bala.veloc + 1
                elif event.key == K_LEFT:
                    if bala.veloc &gt; 10 and bala.disparar == False:
                        bala.veloc = bala.veloc - 1
                elif event.key == K_SPACE:
                    bala.disparar = True
                elif event.key == K_ESCAPE:
                    sys.exit()

        if bala.disparar == True:
            # al tiempo anterior le sumamos lo transcurrido
            bala.tiempo = bala.tiempo + (tick / 1000.0)

        # Actualizar la posición e información
        bala.update()
        text = &quot;Velocidad: %3d (m/s)   Angulo: %d   x=%d m   y=%d m&quot; % (
            bala.veloc, bala.angulo, bala.xreal, bala.yreal)
        mensaje = fuente.render(text, 1, (255, 255, 255))

        # Re dibujar los elementos en pantalla
        screen.fill((30, 145, 255))
        screen.blit(mensaje, (15, 5))
        pygame.draw.line(screen, (255, 255, 255), (0, 25), (640, 25), 2)
        pygame.draw.circle(screen, (0, 0, 0), (int(bala.x), int(bala.y)), 10)
        # actualizamos la pantalla
        pygame.display.flip()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Si se fijan ahora iniciamos un reloj (modulo time) <em>clock =  pygame.time.Clock()</em> y luego al comienzo del <em>while True</em> registramos cuanto tiempo (en milisegundos) han pasado desde la llamada anterior del clock.tick (en la parte anterior del tutorial explique que tick devuelve el tiempo que ha pasado entre llamadas), por ello hacemos: <em>tick = clock.tick(60)</em></p>
<blockquote><p>Observación: Use <strong><em>tick = clock.tick(60)</em></strong> pero es igual de valido (y funciona de la misma manera) si se usa <strong><em>tick = clock.tick()</em></strong> ya que ambas devuelven el tiempo trascurrido y en este caso la sincronización del movimiento de los objetos en el juego depende del tiempo (y no del framerate)</p>
<p>El principal motivo para haber usado <em>clock.tick(60)</em> es que de esta manera se controla el framerate (a la vez que se obtiene cuantos milisegundos han pasado), así si tienen un equipo muy potente, podemos limitar como corre el juego y que no ocupe todo los recursos del equipo al ejecutarse (cosa que se agradece). Para que se hagan una idea al usar clock.tick() el juego estaba usando los dos nucleos de mi CPU al 100% y alcanzaba unos frames bestiales (y que no eran necesarios), en cambio clock.tick(60) el movimiento era igual de fluido y el procesador estaba al funcionando al mínimo.</p></blockquote>
<p>Volviendo al tema, ya que en el tick esta almacenado el tiempo que ha pasado entre llamadas, ahora simplemente se comprueba si se ha disparado la bala y si es así hay que sumar el tiempo trascurrido al que se tenia registrado (que inicialmente era 0 y que en cada ciclo del juego va aumentando), o sea esto:</p>
<p><pre class="brush: python;">
if bala.disparar == True:
    bala.tiempo = bala.tiempo + (tick / 1000.0)
</pre></p>
<p>Nota: Se divide por 1000.0 para transformar el tiempo del tick desde milisegundos a segundos (ya que la velocidad esta dada en m/seg). Se usa 1000.0 en vez de 1000 para que los resultados sean decimales (punto flotante).</p>
<p>Ahora en la clase del proyectil, se modifica el método update para que calcule la posición del proyectil, de la siguiente manera:</p>
<p><pre class="brush: python;">
    def update(self):
        &quot;actualizar la posición del proyectil&quot;
        self.velocx = self.veloc * math.cos(math.radians(self.angulo))
        self.velocy = self.veloc * math.sin(math.radians(self.angulo))

        if self.disparar == True:
            # esta en movimiento, hay que actualizar la posición
            self.xreal = (0 + self.velocx * self.tiempo)
            self.yreal = (0 + self.velocy * self.tiempo +
                (-9.8 * (self.tiempo ** 2)) / 2)
            # Corregir la posición en el eje vertical
            self.x = self.xreal
            self.y = HEIGHT - self.yreal
</pre></p>
<p>Primero se calcula la componente de la velocidad en el eje x (<em>self.velocx</em>) e eje y (<em>self.velocy</em>), para ello se multiplica la velocidad (<em>self.veloc</em>) por el coseno (<em>math.cos</em>) y seno (<em>math.sin</em>) de angulo respectivamente. Eso si el angulo inicial lo tenemos en <a href="http://es.wikipedia.org/wiki/Grado_sexagesimal">grados (sexagesimal)</a> y las funciones math.sin y math.cos trabajan en <a href="http://es.wikipedia.org/wiki/Radianes">radianes</a>, por lo que usamos la función <a href="http://docs.python.org/library/math.html#math.radians"><em>math.radians</em></a> para pasar de grados a radianes (aunque también podríamos haber trabajado desde un comienzo en radianes, pero eso le hubiera quitado la gracia al ejemplo).</p>
<p>Luego para calcular la posición teórica de la bala usamos las ecuaciones que se mencionaron en la explicación física, o sea:<br />
<img src='http://s0.wp.com/latex.php?latex=x%3D+0+%2B+v_%7Bx%7Dt&amp;bg=ffffff&amp;fg=666666&amp;s=0' alt='x= 0 + v_{x}t' title='x= 0 + v_{x}t' class='latex' /><br />
<img src='http://s0.wp.com/latex.php?latex=y%3D+0+%2B+v_%7By%7Dt+%2B+%7B%5Cfrac%7B1%7D%7B2%7D%7Dgt%5E2&amp;bg=ffffff&amp;fg=666666&amp;s=0' alt='y= 0 + v_{y}t + {&#92;frac{1}{2}}gt^2' title='y= 0 + v_{y}t + {&#92;frac{1}{2}}gt^2' class='latex' /></p>
<p>Que  aplicadas en nuestro código quedan:<br />
<pre class="brush: python;">
self.xreal = (0 + self.velocx * self.tiempo)
self.yreal = (0 + self.velocy * self.tiempo + (-9.8 * (self.tiempo ** 2)) / 2)
</pre></p>
<p>y posteriormente corregimos la posición para que se ajuste al sentido de los ejes que usa  pygame; la posición en el eje x se deja igual <em>self.x = self.xreal</em> y la posición en el eje y se invierte <em>self.y = HEIGHT &#8211; self.yreal</em></p>
<p>Por ultimo en la entrada del teclado se pone una comprobación extra para que no se puedan modificar los datos mientras el proyectil esta en movimiento.</p>
<blockquote><p>Bueno eso es todo por ahora, pueden descargar<a href="http://sites.google.com/site/dbfuentes/archivos/tutorial-pygame-4.zip?attredirects=0&amp;d=1"> todos estos ejemplos desde aquí</a> (o buscarlo en el repositorio de <a href="http://github.com/dbfuentes/tutorial-pygame">github</a>)</p></blockquote>
<p>En la siguiente parte vamos a crear el clásico juego (<a href="http://es.wikipedia.org/wiki/Matamarcianos">estilo Shoot &#8216;em up</a>) de la nave que va disparando y eliminando a los enemigos que aparecen en pantalla </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/pythonmania.wordpress.com/520/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pythonmania.wordpress.com/520/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/pythonmania.wordpress.com/520/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pythonmania.wordpress.com/520/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/pythonmania.wordpress.com/520/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/pythonmania.wordpress.com/520/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/pythonmania.wordpress.com/520/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/pythonmania.wordpress.com/520/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/pythonmania.wordpress.com/520/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pythonmania.wordpress.com/520/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/pythonmania.wordpress.com/520/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pythonmania.wordpress.com/520/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/pythonmania.wordpress.com/520/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pythonmania.wordpress.com/520/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=520&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://pythonmania.wordpress.com/2010/07/14/tutorial-pygame-4-figuras-y-texto/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<georss:point>-33.425360 -70.566466</georss:point>
		<geo:lat>-33.425360</geo:lat>
		<geo:long>-70.566466</geo:long>
		<media:content url="" medium="image">
			<media:title type="html">Daniel F.</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2010/07/pygame_vector_velocidad.png?w=300" medium="image">
			<media:title type="html">pygame_vector_velocidad</media:title>
		</media:content>
	</item>
		<item>
		<title>Cambiando el user-agent de urllib</title>
		<link>http://pythonmania.wordpress.com/2010/04/13/cambiando-el-user-agent-de-urllib/</link>
		<comments>http://pythonmania.wordpress.com/2010/04/13/cambiando-el-user-agent-de-urllib/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 18:39:38 +0000</pubDate>
		<dc:creator>Daniel Fuentes B.</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://pythonmania.wordpress.com/?p=498</guid>
		<description><![CDATA[Hace algunos días necesitaba cambiar el user agent de urllib (o sea como se identifica urllib al abrir una pagina web) para usarlo en mi script para bajar archivos desde goear. El problema es que normalmente a algunos sitios como google o la wikipedia no les gusta que uno use otras cosas que nos sean [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=498&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Hace algunos días necesitaba cambiar el <a href="http://es.wikipedia.org/wiki/Agente_de_usuario">user agent</a> de urllib (o sea como se identifica urllib al abrir una pagina web) para usarlo en <a href="http://logicerror.wordpress.com/2007/08/12/script-en-python-para-descargar-los-archivos-de-goear/">mi script</a><a href="http://bitbucket.org/dbfuentes/goear-dl/"> para bajar archivos desde goear</a>. El problema es que normalmente a algunos sitios como google o la wikipedia no les gusta que uno use otras cosas que nos <a href="http://es.wikipedia.org/wiki/Navegador_web">sean navegadores validos</a> para ver sus paginas.</p>
<p>Por ejemplo al hacer una búsqueda en google:<br />
<pre class="brush: python;">
from urllib import urlopen
pag = urlopen(&quot;http://www.google.com/search?q=python&quot;)
print pag.read()
</pre><br />
Nos responde mucho texto (en realidad es el html de una pagina de error), que nos dice :<br />
<pre class="brush: php;">
[...]&lt;H1&gt;Forbidden&lt;/H1&gt;Your client does not have permission to get URL &lt;code&gt;/search?q=python&lt;/code&gt; from this server.[...]
</pre></p>
<p>Ahora si abrimos el interprete en modo interactivo y hacemos:<br />
<pre class="brush: python;">
&gt;&gt;&gt; from urllib import URLopener
&gt;&gt;&gt; URLopener.version
'Python-urllib/1.17'
</pre><br />
Vemos que por defecto urllib se identifica al abrir alguna pagina (o sea su user-agent) es <em>&#8220;Python-urllib/1.17&#8243;</em>.</p>
<p>Para cambiarlo por otro valor, consultamos la <a href="http://docs.python.org/library/urllib.html#urllib._urlopener">documentacion de python</a> que nos dice:</p>
<blockquote><p>To override this functionality, programmers can create a subclass of URLopener or FancyURLopener, then assign an instance of that class to the urllib._urlopener variable before calling the desired function.</p></blockquote>
<p>Con esto en mente hacemos una pequeña clase que hace el cambio, en donde le señalamos un nuevo user agent (en el ejemplo voy a usar el de IE7, aunque si quieren otros <a href="http://www.useragentstring.com/pages/useragentstring.php">pueden buscar por aquí</a>), quedando el ejemplo de esta manera:<br />
<pre class="brush: python;">
from urllib import FancyURLopener

class MyOpener(FancyURLopener):
    version = 'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)'

myopener = MyOpener()
pag = myopener.open(&quot;http://www.google.com/search?q=python&quot;)
print pag.read()
</pre><br />
Y ahora si nos responde (nos muestra el html de la pagina) con un lindo:<br />
<pre class="brush: php;">
[...]Results &lt;b&gt;1&lt;/b&gt; - &lt;b&gt;10&lt;/b&gt; of about &lt;b&gt;36,400,000&lt;/b&gt; for &lt;b&gt;python&lt;/b&gt; [...]
</pre></p>
<p>Claro que se puede usar con cualquier otro metodo de urllib, como por ejemplo con retrieve (para descargar la pagina con los resultados de la búsqueda, en vez de ver el html):<br />
<pre class="brush: python;">
from urllib import FancyURLopener

class MyOpener(FancyURLopener):
    version = 'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)'

myopener = MyOpener()
myopener.retrieve(&quot;http://www.google.com/search?q=python&quot;, &quot;resultados.html&quot;)
</pre></p>
<p>Divertido, ¿o no?</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/pythonmania.wordpress.com/498/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pythonmania.wordpress.com/498/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/pythonmania.wordpress.com/498/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pythonmania.wordpress.com/498/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/pythonmania.wordpress.com/498/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/pythonmania.wordpress.com/498/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/pythonmania.wordpress.com/498/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/pythonmania.wordpress.com/498/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/pythonmania.wordpress.com/498/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pythonmania.wordpress.com/498/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/pythonmania.wordpress.com/498/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pythonmania.wordpress.com/498/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/pythonmania.wordpress.com/498/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pythonmania.wordpress.com/498/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=498&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://pythonmania.wordpress.com/2010/04/13/cambiando-el-user-agent-de-urllib/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<georss:point>-33.425360 -70.566466</georss:point>
		<geo:lat>-33.425360</geo:lat>
		<geo:long>-70.566466</geo:long>
		<media:content url="" medium="image">
			<media:title type="html">Daniel F.</media:title>
		</media:content>
	</item>
		<item>
		<title>Tutorial Pygame 3: creando un videojuego (el clasico pong)</title>
		<link>http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/</link>
		<comments>http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 19:48:08 +0000</pubDate>
		<dc:creator>Daniel Fuentes B.</dc:creator>
				<category><![CDATA[pygame]]></category>
		<category><![CDATA[tutoriales]]></category>
		<category><![CDATA[juegos]]></category>

		<guid isPermaLink="false">http://pythonmania.wordpress.com/?p=434</guid>
		<description><![CDATA[Ok, es tiempo de continuar con esta serie de tutoriales de pygame. Si recuerdan en el tutorial anterior cargamos unas imágenes y las mostramos en pantalla, haciendo que se movieran. Ahora vamos a avanza un poco, programando uno de los juegos mas sencillos que pueden existir, el clásico pong. En esta parte trataremos los siguientes [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=434&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Ok, es tiempo de continuar con <a href="http://pythonmania.wordpress.com/2010/03/23/tutorial-pygame-introduccion/">esta serie de tutoriales de pygame</a>. Si recuerdan en el <a href="http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/">tutorial anterior</a> cargamos unas imágenes y las mostramos en pantalla, haciendo que se movieran. Ahora vamos a avanza un poco, programando uno de los juegos mas sencillos que pueden existir, el <a href="http://es.wikipedia.org/wiki/Pong">clásico pong</a>.</p>
<p>En esta parte trataremos los siguientes puntos:</p>
<ul>
<li>Crear una función para cargar imágenes</li>
<li>Como crear sprites (los sprites son personajes, objetos, etc. dentro del juego)</li>
<li>Sincronización de elementos en los videojuegos (¿que son frames por segundo?)</li>
<li>Controlar un sprite con el teclado</li>
<li>Controlar un sprite con el mouse</li>
<li>Colisiones entre elementos (sprites)</li>
<li>Inteligencia artificial (o la falta de esta)</li>
<li>reproducción de sonidos (al cumplirse alguna condición)</li>
</ul>
<p><span id="more-434"></span><br />
Para este tutorial me voy a basar en el primer juego que escribí en pygame <a href="http://logicerror.wordpress.com/2008/03/01/pygame/">hace mucho tiempo</a> (que por cierto tenia algunos errores), el cual a su vez se basaba en un ejemplo de <a href="http://www.linuxjuegos.com/programacion-de-juegos-en-python-tutorial-2/">linuxjuegos </a>(aun más antiguo). En resumen voy reescribir el juego, simplificándolo y de paso voy a explicar como funciona:</p>
<p><strong>Paso 1: Creando lo básico (y una función para cargar imágenes)</strong></p>
<p>Lo primero es crear la ventana y una función para cargar las imágenes.</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import os
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
IMG_DIR = &quot;imagenes&quot;

# ------------------------------
# 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 &quot;Error, no se puede cargar la imagen: &quot;, ruta
        sys.exit(1)
    # Comprobar si la imagen tiene &quot;canal alpha&quot; (como los png)
    if alpha == True:
        image = image.convert_alpha()
    else:
        image = image.convert()
    return image


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;Ejemplo de un Pong Simple&quot;)

    # cargamos el fondo
    fondo = load_image(&quot;fondo.jpg&quot;, IMG_DIR, alpha=False)

    # el bucle principal del juego
    while True:
        #actualizamos la pantalla
        screen.blit(fondo, (0, 0))
        pygame.display.flip()

        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Creamos una función para cargar imágenes por comodidad, así se facilita cargar distintos tipos de imágenes a la vez que realiza los convert() según corresponda. La función trabaja de la siguiente manera: toma tres parámetros el nombre, el directorio donde se encuentra la imagen y si tiene o no un canal alpha (el color transparente del los png). Luego con esa información (directorio + nombre imagen) crea la ruta de la imagen y intenta abrirla con un <em>try</em> que es como &#8220;espera, voy a probar abrir la imagen… y si algo falla (<em>except</em>), avisa y termina el programa&#8221;. Después de eso revisa si la imagen tiene un cana alpha (<em>if alpha == True</em>), en ese caso realiza el <em>.convert_alpha()</em>, en caso contrario realiza un simple <em>.convert() </em>. Finalmente devuelve la superficie (&#8220;surface&#8221;) que se crea al cargar la imagen.</p>
<p>Luego en la función principal del juego se carga la imagen del fondo y se muestra en pantalla. Si se fijan hay una variable llamada IMG_DIR, esta indica el nombre del directorio donde se encuentran las imágenes.</p>
<p>Nota: usaremos estas imágenes en el tutorial:</p>
<div id="attachment_491" class="wp-caption aligncenter" style="width: 33px"><a href="http://pythonmania.files.wordpress.com/2010/04/bola.png"><img src="http://pythonmania.files.wordpress.com/2010/04/bola.png?w=480" alt="" title="bola"   class="size-full wp-image-491" /></a><p class="wp-caption-text">bola.png</p></div>
<div id="attachment_494" class="wp-caption aligncenter" style="width: 26px"><a href="http://pythonmania.files.wordpress.com/2010/04/paleta.png"><img src="http://pythonmania.files.wordpress.com/2010/04/paleta.png?w=480" alt="" title="paleta"   class="size-full wp-image-494" /></a><p class="wp-caption-text">paleta.png</p></div>
<div id="attachment_495" class="wp-caption aligncenter" style="width: 310px"><a href="http://pythonmania.files.wordpress.com/2010/04/fondo_tutorial3.jpg"><img src="http://pythonmania.files.wordpress.com/2010/04/fondo_tutorial3.jpg?w=300&#038;h=225" alt="" title="fondo_tutorial3" width="300" height="225" class="size-medium wp-image-495" /></a><p class="wp-caption-text">fondo.jpg (hacer click para agrandar)</p></div>
<p><strong>Paso 2: Creando sprites</strong></p>
<p>En el tutorial anterior ya hable algo de los sprites y les recomende <a href="http://www.losersjuegos.com.ar/referencia/articulos/conceptos_basicos">leer esto (que explica los conceptos básicos de los videojuegos)</a>. Ahora vamos a profundizar en los sprites.</p>
<p>Un sprite es básicamente cualquier cosa que aparezca en nuestro juego (personajes, objetos, etc.) la cual tiene asociada informacion (como su posición, tamaño, etc.). En pygame es costumbre hacer una clase para cada sprite, de tal manera que la clase contenga la información relevante de ese sprite.</p>
<p>En este caso vamos a crear la clase Pelota, que va a contener todos los datos de la pelota usada en el juego. Esta primera versión de la pelota, solo rebotará indistintamente en las cuatro murallas de nuestra pantalla. Veamos el código:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import os
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
IMG_DIR = &quot;imagenes&quot;

# ------------------------------
# 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 &quot;Error, no se puede cargar la imagen: &quot;, ruta
        sys.exit(1)
    # Comprobar si la imagen tiene &quot;canal alpha&quot; (como los png)
    if alpha == True:
        image = image.convert_alpha()
    else:
        image = image.convert()
    return image


# -----------------------------------------------
# Creamos los sprites (clases) de los objetos del juego:


class Pelota(pygame.sprite.Sprite):
    &quot;La bola y su comportamiento en la pantalla&quot;

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;bola.png&quot;, 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]


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;Ejemplo de un Pong Simple&quot;)

    # cargamos los objetos
    fondo = load_image(&quot;fondo.jpg&quot;, IMG_DIR, alpha=False)
    bola = Pelota()

    # el bucle principal del juego
    while True:
        #actualizamos la pantalla
        screen.blit(fondo, (0, 0))
        screen.blit(bola.image, bola.rect)
        pygame.display.flip()

        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Ahora dentro de la clase <em>Pelota()</em> vemos que hereda los metodos de la clase padre <em>pygame.sprite.Sprite</em>, luego en el <em>def __init__(self):</em> se define que se hará cuando se llama al instanciar la clase. (<a href="http://mundogeek.net/archivos/2008/03/05/python-orientacion-a-objetos/">una explicación mas completa por aquí</a>). En nuestro caso se le dice primero que inicie <em>pygame.sprite.Sprite</em> (algo un poco raro pero obligatorio), luego en <em>self.image</em> cargamos la imagen (algo conocido,  ya que lo hemos hecho antes).</p>
<blockquote><p>Nota: <em>self</em> se usa para referirse la clase actual en la que se está, en otras palabras para una clase es como referirse a si misma (algo común en las clases)</p></blockquote>
<p>Con <em>self.image.get_rect()</em> se obtiene un objeto rectangulo (<em>rect</em>) con las dimensiones y posición de la imagen (en este caso se usa sobre self.image, o sea la imagen de la bola) y este rectángulo se lo asignamos a self.rect. Esto resulta bastante útil, ya que nos permite dejar de preocuparnos por las dimensiones de la imagen por si luego decidimos cambiarlas, además de obtener algunos extras que se señalan a continuación:</p>
<blockquote><p>
Ahora el <a href="http://www.losersjuegos.com.ar/traducciones/pygame/rect">rectangulo creado con get_rect()</a> nos permite usar varios varios atributos virtuales que se pueden usar para mover o alinear el rectángulo (y que usaremos a continuación). Entre ellos:</p>
<ul>
<li>top, left, bottom, right</li>
<li>topleft, bottomleft, topright, bottomright</li>
<li>midtop, midleft, midbottom, midright</li>
<li>center, centerx, centery</li>
<li>size, width, height</li>
<li>w,h</li>
</ul>
</blockquote>
<p>Ahora con <em>self.rect.centerx</em> y <em>self.rect.centery</em> le indicamos a pygame que el centro de nuestra imagen (centerx, centery) quede exactamente en la mitad de la pantalla (o sea centramos la imagen)</p>
<p>Por ultimo en <em>self.speed</em> se establece la velocidad con que se mueva la pelota en el eje x y en el eje y (en la siguiente parte se vera para que lo vamos a usar)</p>
<p><strong>Intermedio: un poco de teoría, sincronización en los videojuegos</strong></p>
<p>Antes de continuar, hay que mencionar algo sobre la forma de sincronizar los videojuegos, lo cual es necesario, ya que si llegamos y ejecutamos nuestro videojuego en un computador antiguo, por ejemplo en un Pentium II, es posible que el videojuego se vea muy lento, en cambio si lo ejecutamos en un computador más potente (de ultima generación), el juego se verá tan rápido que será imposible jugar.</p>
<p>Hay dos formas de sincronización:</p>
<p><strong><em>Sincronización por Framerate o Frames per Second (FPS):</em></strong> En este caso se refiere a la frecuencia con que se ejecuta el ciclo principal de un videojuego en un segundo (mientras más alto, más fluidez).</p>
<p>Básicamente se va obteniendo el tiempo que ha trascurrido desde el inicio del ciclo, se hacen las acciones del juego y cuando pasen los FPS especificados, se actualiza/refresca la pantalla. Así se logra una fluidez constante sin importar en que equipo se ejecute</p>
<blockquote><p>Este es uno de los metodos mas extendidos (especialmente en juegos en 2D). Claro que este método tiene sus ventajas y desventajas:</p>
<ul>
<li>A favor: ya que limitamos la cantidad máxima de FPS que puede lograr el juego, este debería verse de la misma forma en cualquier computador en donde se corra, ya que si el equipo es muy potente solo funcionara a los FPS especificados (pese a que puede ir mas rápido)</li>
<li>En contra: al usar este método en computadores más rápidos (que el pc donde se desarrollo) el juego se verá fluido, pero si lo ejecutamos en una máquina con un procesador mucho más antiguo del que usamos para desarrollarlo, lo más probable es que se vea bastante lento (por algo hay requerimientos mínimos)</li>
</ul>
</blockquote>
<p><strong><em>Sincronización por Tiempo:</em></strong> En este caso se sincroniza en base al tiempo (por lo que no importan los FPS) moviéndose de igual manera los objetos sin importar en que equipo se ejecute el juego (ya que el movimiento depende del tiempo transcurrido).Ya que lo que se hace es calcular la posición de un objeto en función del tiempo transcurrido.</p>
<blockquote><p>Este método se usa bastante en videojuegos 3D, ya que el framerate varía mucho en cada ciclo</p>
<ul>
<li>A favor: Los objetos/sprites se mueven siempre a la misma velocidad, sin importar cuantos FPS se alcancen (ya que su movimiento es en función del tiempo), por lo cual no hay que preocuparse de controlar el framerate</li>
<li>En contra: Pese a que los objetos se mueven siempre a la misma velocidad, en un computador más lento el desplazamiento no se verá fluidamente,  por ejemplo en caso (extremo) de que se demore el juego 1 segundo en cada ciclo, cada vez que se deba mover un objeto este se desplazara grandes distancias (ya que el tiempo entre actualizaciones/ciclos en donde se refrezca la pantalla es grande), produciéndose un salto muy notorio</li>
</ul>
</blockquote>
<p>Si en el primer método (FPS) queríamos mover un objeto 8 pixeles, haríamos lo siguiente: </p>
<p><pre class="brush: python;">
x = x + 8
</pre></p>
<p>En cambio si lo hacemos en base al tiempo tendríamos:</p>
<p><pre class="brush: python;">
x = x + (velocidad)*(tiempo)
</pre></p>
<p>O sea física básica, en donde por ejemplo si se desplaza el objeto a una velocidad de 0.008, y el ciclo demora 1 segundo en ejecutarse (1000ms), el nuevo incremento será de: </p>
<p><pre class="brush: python;">
x = x + 0.008*1000
x = x + 8
</pre></p>
<p>Ok, volvamos con nuestro juego.</p>
<p><strong>Parte 3: Moviendo la pelota (y creando un reloj)</strong></p>
<p>Volviendo al juego (el cual va a usar el método de los FPS), vamos a crear dentro de la clase Pelota una función update, que se encargará de hacer avanzar la bola y que seta rebote cuando haya llegado a los límites de la pantalla. </p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import os
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
IMG_DIR = &quot;imagenes&quot;

# ------------------------------
# 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 &quot;Error, no se puede cargar la imagen: &quot;, ruta
        sys.exit(1)
    # Comprobar si la imagen tiene &quot;canal alpha&quot; (como los png)
    if alpha == True:
        image = image.convert_alpha()
    else:
        image = image.convert()
    return image


# -----------------------------------------------
# Creamos los sprites (clases) de los objetos del juego:


class Pelota(pygame.sprite.Sprite):
    &quot;La bola y su comportamiento en la pantalla&quot;

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;bola.png&quot;, 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]

    def update(self):
        if self.rect.left &lt; 0 or self.rect.right &gt; SCREEN_WIDTH:
            self.speed[0] = -self.speed[0]
        if self.rect.top &lt; 0 or self.rect.bottom &gt; SCREEN_HEIGHT:
            self.speed[1] = -self.speed[1]
        self.rect.move_ip((self.speed[0], self.speed[1]))

# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;Ejemplo de un Pong Simple&quot;)

    # cargamos los objetos
    fondo = load_image(&quot;fondo.jpg&quot;, IMG_DIR, alpha=False)
    bola = Pelota()

    clock = pygame.time.Clock()

    # el bucle principal del juego
    while True:
        clock.tick(60)
        bola.update()

        #actualizamos la pantalla
        screen.blit(fondo, (0, 0))
        screen.blit(bola.image, bola.rect)
        pygame.display.flip()

        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Los dos <em>if</em> sirven para comprobar si la pelota alcanzo los bordes de la pantalla, si esto ocurre que comience a moverse en sentido contrario (por ejemplo si llego a topar el borde derecho, la pelota comenzara a moverse a la izquierda, lo mismo para los otros bordes)</p>
<p>La función move_ip(x,y) mueve de forma relativa el sprite por pantalla, esto es, subirá o bajará x pixel y avanzará retrocederá y pixel. (en este caso utilizara la velocidad que definimos anteriormente para la bola, moviendola 3pixeles hacia la derecha y abajo)</p>
<p>Ahora en la función principal del juego tenemos una linea que inicia la clase<em> bola = Pelota()</em> y luego de esto una linea que crea un reloj que controle el tiempo del juego <em>clock = pygame.time.Clock()</em>, el cual se ejecuta justo antes de iniciar el bucle principal del juego.</p>
<p>Luego se esto en la función principal hacemos <em>clock.tick(60)</em>, lo cual sirve para poner el reloj a un paso de 60 FPS, esto se hace para que nunca se pase de 60 frames por segundo, así no importará si estamos ejecutando esto en un pentium II o en una supercomputadora, la velocidad siempre será como máximo de 60 frames por segundo.</p>
<p>Finalmente con <em>bola.update()</em> se actualiza la posición de la pelota y luego se redibuja la pantalla</p>
<blockquote><p>Clock.tick es bastante curioso, si se usa sin argumentos (o sea  <em>clock.tick()</em>) devuelve el tiempo que ha pasado (en milisegundos) desde la ultima vez que se llamo (o sea funciona como un reloj), pero si se usa con un argumento, que es el framerate (por ejemplo <em>clock.tick(60)</em>), la función esperará el tiempo necesario para mantener al juego corriendo a la velocidad solicitada, o sea en el ejemplo el juego nunca correrá a más de 60 frames/cuadros por segundo (sirve para controlar el framerate).</p>
<p>Eso si este método no es muy exacto, pero casi no usa CPU, si se quiere algo mas exacto hay que usar Clock.tick_busy_loop <a href="http://www.losersjuegos.com.ar/traducciones/pygame/time/clock">(más información en la documentación de pygame)</a></p></blockquote>
<p><strong>Parte 4: Creando la paleta (control con teclado)</strong></p>
<p>No hay grandes cambios, lo primero que se hace es crear una clase que contenga la paleta y en la función principal hay que revisar si se ha pulsado alguna de las teclas indicadas (y actuar de acuerdo a ella). El código queda:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import os
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
IMG_DIR = &quot;imagenes&quot;

# ------------------------------
# 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 &quot;Error, no se puede cargar la imagen: &quot;, ruta
        sys.exit(1)
    # Comprobar si la imagen tiene &quot;canal alpha&quot; (como los png)
    if alpha == True:
        image = image.convert_alpha()
    else:
        image = image.convert()
    return image


# -----------------------------------------------
# Creamos los sprites (clases) de los objetos del juego:


class Pelota(pygame.sprite.Sprite):
    &quot;La bola y su comportamiento en la pantalla&quot;

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;bola.png&quot;, 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]

    def update(self):
        if self.rect.left &lt; 0 or self.rect.right &gt; SCREEN_WIDTH:
            self.speed[0] = -self.speed[0]
        if self.rect.top &lt; 0 or self.rect.bottom &gt; SCREEN_HEIGHT:
            self.speed[1] = -self.speed[1]
        self.rect.move_ip((self.speed[0], self.speed[1]))


class Paleta(pygame.sprite.Sprite):
    &quot;Define el comportamiento de las paletas de ambos jugadores&quot;

    def __init__(self, x):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;paleta.png&quot;, 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 &gt;= SCREEN_HEIGHT:
            self.rect.bottom = SCREEN_HEIGHT
        elif self.rect.top &lt;= 0:
            self.rect.top = 0


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;Ejemplo de un Pong Simple&quot;)

    # cargamos los objetos
    fondo = load_image(&quot;fondo.jpg&quot;, IMG_DIR, alpha=False)
    bola = Pelota()
    jugador1 = Paleta(40)

    clock = pygame.time.Clock()

    # el bucle principal del juego
    while True:
        clock.tick(60)

        # Actualizamos los obejos en pantalla
        jugador1.humano()
        bola.update()

        # Posibles entradas del teclado y mouse
        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

        #actualizamos la pantalla
        screen.blit(fondo, (0, 0))
        screen.blit(bola.image, bola.rect)
        screen.blit(jugador1.image, jugador1.rect)
        pygame.display.flip()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Se define la clase paleta de manera analoga a la clase pelota, la única diferencia es que el  def __init__(self, x) recibe como argumento adicional la coordenada x de la paleta (así con la misma clase se puede cargar una paleta a la izquierda y otra a la derecha), en cuanto a la coordenada y (en eje vertical), esta clase deja centrada la paleta (verticalmente)</p>
<p>Después dentro de la clase se define un: <em>def humano(self)</em>, que simplemente es lo que hace la paleta cuando es controlada por un jugador (humano), en este caso lo único que hace es que si alcanza el borde superior o inferior en el eje y (eje vertical), deje de moverse, para que no se salga de pantalla (algo no muy grato)</p>
<p>En la función principal del juego, se inicia la clase <em>jugador1 = Paleta(25)</em> para crear la paleta controlada por el jugador (el 25 es para que la paleta quede a 25 píxeles del borde izquierdo) y un poco más adelante se le indica que esa paleta se controlada por una persona (humana) <em>jugador1.humano()</em>, el resto es actualizar la pantalla.</p>
<p>Dentro del bucle se comprueba los eventos (en la parte de<em> for event in pygame.event.get():</em>), así cada vez que se pulsa una tecla (del teclado) se obtiene un evento pygame.KEYDOWN y cada vez que se suelta una tecla se produce un evento pygame.KEYUP. Esos eventos devuelven el valor de la tecla pulsada (<a href="http://www.losersjuegos.com.ar/traducciones/pygame/key">se puede revisar los posibles valores en la documentación</a>)</p>
<p>Así que simplemente se revisa dentro del evento pygame.KEYDOWN que tecla se pulso, si se trata de la tecla flecha hacia arriba (K_UP) la paleta se desplaza 5 píxeles hacia arriba y si se trata de la tecla flecha hacia abajo (K_DOWN)  se desplaza 5 píxeles hacia abajo. En el caso de que puse la tecla K_ESCAPE simplemente se termina el programa</p>
<p>Una revisión similar se hace cuando se sueltan las teclas (pygame.KEYUP) en donde se deja de mover la paleta. En este juego no tiene mucho sentido hacer esto (ya que por defecto la paleta esta quieta) pero en otros juegos puede servir, por eso lo puse (pese a no ser necesario).</p>
<blockquote><p>Dentro de <a href="pygame.key"><em>pygame.key</em></a> existe el método <em><a href="http://www.losersjuegos.com.ar/traducciones/pygame/key#get_pressed">get_pressed()</a></em> que devuelve una lista con todas las teclas pulsadas, usar esto puede ser mas simple que ir comprobando una por una las teclas pero tiene como inconveniente que:</p>
<ul>
<li>no hay forma de conocer el orden de las teclas pulsadas</li>
<li>las pulsaciones muy rápidas de teclas pueden pasar desapercibidas</li>
</ul>
</blockquote>
<p><strong>Parte 5: mejorando el control con el teclado (y el mouse)</strong></p>
<p>Si se fijaron el código anterior tiene un problema, al mantener pulsada una tecla (flecha hacia arriba o abajo) el programa solo mueve la paleta una vez (solo registra una vez el evento), en vez de mantenerse moviendo la paleta hasta que se suelte la tecla. Además falta poder controlar la paleta con el mouse.</p>
<p>Para lo primero, hay que indicarle a pygame que active la repetición de teclas, lo cual se hace con la función <a href="http://www.losersjuegos.com.ar/traducciones/pygame/key#set_repeat"><em>pygame.key.set_repeat()</em></a>, esta toma dos argumentos: el primero establece el tiempo de retraso (el número de milisegundos) que tienen que pasar para detectar/enviar el primer evento y el segundo argumento (el intervalo) es el numero de milisegundos que pasan entre cada envío del evento.</p>
<p>Para conocer el estado del mouse, hay que usar <a href="http://www.losersjuegos.com.ar/traducciones/pygame/mouse">pygame.mouse</a>, para ello lo primero que haremos es que el cursor del mouse no se vea dentro de la pantalla (o sea que solo aparezca fuera de ella) seo lo hacemos con <em>pygame.mouse.set_visible(False)</em></p>
<p>Luego dentro de nuestro bucle, registramos la posición del mouse con <em>pos_mouse = pygame.mouse.get_pos()</em>, que nos devuelve una tupla con <a href="http://www.losersjuegos.com.ar/traducciones/pygame/mouse#get_pos">las coordenadas (x, y) en donde esta el puntero del mouse</a>, las que quedan almacenadas en pos_mouse. Luego usamos <em>mov_mouse = pygame.mouse.get_rel()</em> para obtener cuanto se ha movido el mouse desde la ultima consulta que realizo get_rel() (<a href="http://www.losersjuegos.com.ar/traducciones/pygame/mouse#get_rel">esto tambien es una tupla, del tipo (x,y) que devueve la distancia que se ha movido</a>),en caso de que el puntero del mouse no se haya movido devlvera un (0,0). </p>
<p><pre class="brush: python;">
elif mov_mouse[1] != 0:
   jugador1.rect.centery = pos_mouse[1]
</pre></p>
<p>Avanzamos un poco y en la parte en donde comprobamos los eventos, usamos un <em>if mov_mouse[1] != 0:</em>, con esto el deciomos que si la coordenada y de la tupla que devuelve get_rel() es distinta de 0, mueva la paleta a la posición en donde esta el mouse (<em>jugador1.rect.centery = pos_mouse[1]</em>)</p>
<p>Entonces nuestro codigo queda como:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import os
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
IMG_DIR = &quot;imagenes&quot;

# ------------------------------
# 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 &quot;Error, no se puede cargar la imagen: &quot;, ruta
        sys.exit(1)
    # Comprobar si la imagen tiene &quot;canal alpha&quot; (como los png)
    if alpha == True:
        image = image.convert_alpha()
    else:
        image = image.convert()
    return image


# -----------------------------------------------
# Creamos los sprites (clases) de los objetos del juego:


class Pelota(pygame.sprite.Sprite):
    &quot;La bola y su comportamiento en la pantalla&quot;

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;bola.png&quot;, 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]

    def update(self):
        if self.rect.left &lt; 0 or self.rect.right &gt; SCREEN_WIDTH:
            self.speed[0] = -self.speed[0]
        if self.rect.top &lt; 0 or self.rect.bottom &gt; SCREEN_HEIGHT:
            self.speed[1] = -self.speed[1]
        self.rect.move_ip((self.speed[0], self.speed[1]))


class Paleta(pygame.sprite.Sprite):
    &quot;Define el comportamiento de las paletas de ambos jugadores&quot;

    def __init__(self, x):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;paleta.png&quot;, 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 &gt;= SCREEN_HEIGHT:
            self.rect.bottom = SCREEN_HEIGHT
        elif self.rect.top &lt;= 0:
            self.rect.top = 0


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;Ejemplo de un Pong Simple&quot;)

    # cargamos los objetos
    fondo = load_image(&quot;fondo.jpg&quot;, IMG_DIR, alpha=False)
    bola = Pelota()
    jugador1 = Paleta(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 posicon del mouse
        pos_mouse = pygame.mouse.get_pos()
        mov_mouse = pygame.mouse.get_rel()

        # Actualizamos los obejos en pantalla
        jugador1.humano()
        bola.update()

        # Posibles entradas del teclado y mouse
        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 mouse 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))
        screen.blit(bola.image, bola.rect)
        screen.blit(jugador1.image, jugador1.rect)
        pygame.display.flip()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p><strong>Parte 6: Colisiones</strong></p>
<p>Hasta ahora al encontrarse la pelota con la paleta, simplemente esta pasa por detras sin rebotar en la paleta, eso occure porque no hemos especificado que tiene que pasar cuando se producen colisiones, o sea cuando dos sprites chocan.</p>
<p>Para esto dentro de la clase de uno de los sprites hay que crear un método que compruebe si este sprite ha chocado con otros, por conveniencia lo vamos a colocar en la clase Pelota (ya que esta es la que rebota en las otras cosas). </p>
<p>En la clase Pelota definimos <em>def colision(self, objetivo):</em> el cual comprueba si la pelota ha chocado con algo (el segundo argumento es el objeto con el cual esperamos que choque). </p>
<p>Para saber si dos sprites/objetos han chocado usamos <em>pygame.sprite.colliderect(objeto1, objeto2)</em> este comprueba si el rectángulo del objeto1 entra en contacto con el rectángulo del objeto2, retornando True en caso de que entren en contacto. Luego simplemente cambiamos la dirección de la pelota</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import os
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
IMG_DIR = &quot;imagenes&quot;

# ------------------------------
# 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 &quot;Error, no se puede cargar la imagen: &quot;, ruta
        sys.exit(1)
    # Comprobar si la imagen tiene &quot;canal alpha&quot; (como los png)
    if alpha == True:
        image = image.convert_alpha()
    else:
        image = image.convert()
    return image


# -----------------------------------------------
# Creamos los sprites (clases) de los objetos del juego:


class Pelota(pygame.sprite.Sprite):
    &quot;La bola y su comportamiento en la pantalla&quot;

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;bola.png&quot;, 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]

    def update(self):
        if self.rect.left &lt; 0 or self.rect.right &gt; SCREEN_WIDTH:
            self.speed[0] = -self.speed[0]
        if self.rect.top &lt; 0 or self.rect.bottom &gt; 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]


class Paleta(pygame.sprite.Sprite):
    &quot;Define el comportamiento de las paletas de ambos jugadores&quot;

    def __init__(self, x):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;paleta.png&quot;, 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 &gt;= SCREEN_HEIGHT:
            self.rect.bottom = SCREEN_HEIGHT
        elif self.rect.top &lt;= 0:
            self.rect.top = 0


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;Ejemplo de un Pong Simple&quot;)

    # cargamos los objetos
    fondo = load_image(&quot;fondo.jpg&quot;, IMG_DIR, alpha=False)
    bola = Pelota()
    jugador1 = Paleta(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 posicon del mouse
        pos_mouse = pygame.mouse.get_pos()
        mov_mouse = pygame.mouse.get_rel()

        # Actualizamos los obejos en pantalla
        jugador1.humano()
        bola.update()

        # Comprobamos si colisionan los objetos
        bola.colision(jugador1)

        # Posibles entradas del teclado y mouse
        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 mouse 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))
        screen.blit(bola.image, bola.rect)
        screen.blit(jugador1.image, jugador1.rect)
        pygame.display.flip()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p><strong>Parte 7: Comportamiento del oponente (crear al enemigo)</strong></p>
<p>Ahora vamos a crear al enemigo, para esto vamos a modificar la clase Paleta, agregando el método cpu (que sera el segundo jugador controlado por el computador)</p>
<p><pre class="brush: python;">
def cpu(self, objetivo):
    self.rect.centery = objetivo.rect.centery
    if self.rect.bottom &gt;= SCREEN_HEIGHT:
        self.rect.bottom = SCREEN_HEIGHT
    elif self.rect.top &lt;= 0:
        self.rect.top = 0
</pre></p>
<p>Básicamente definimos dentro de la clase Paleta un <em>def cpu(self, objetivo):</em> en donde se le dice a la paleta que siga la posición de la pelota (o sea que se mueva junto con ella) haciendo un <em>self.rect.centery = objetivo.rect.centery</em> (o sea la posición vertical de la paleta es igual a la posición vertical de la pelota), además comprobamos que la paleta no se salga de la pantalla</p>
<p>El resto es crear y mostrar la paleta del jugador 2 (que es controlado por el computador), que es análogo a lo hecho anteriormente, quedando:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import os
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
IMG_DIR = &quot;imagenes&quot;

# ------------------------------
# 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 &quot;Error, no se puede cargar la imagen: &quot;, ruta
        sys.exit(1)
    # Comprobar si la imagen tiene &quot;canal alpha&quot; (como los png)
    if alpha == True:
        image = image.convert_alpha()
    else:
        image = image.convert()
    return image


# -----------------------------------------------
# Creamos los sprites (clases) de los objetos del juego:


class Pelota(pygame.sprite.Sprite):
    &quot;La bola y su comportamiento en la pantalla&quot;

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;bola.png&quot;, 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]

    def update(self):
        if self.rect.left &lt; 0 or self.rect.right &gt; SCREEN_WIDTH:
            self.speed[0] = -self.speed[0]
        if self.rect.top &lt; 0 or self.rect.bottom &gt; 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]


class Paleta(pygame.sprite.Sprite):
    &quot;Define el comportamiento de las paletas de ambos jugadores&quot;

    def __init__(self, x):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;paleta.png&quot;, 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 &gt;= SCREEN_HEIGHT:
            self.rect.bottom = SCREEN_HEIGHT
        elif self.rect.top &lt;= 0:
            self.rect.top = 0

    def cpu(self, objetivo):
        self.rect.centery = objetivo.rect.centery
        if self.rect.bottom &gt;= SCREEN_HEIGHT:
            self.rect.bottom = SCREEN_HEIGHT
        elif self.rect.top &lt;= 0:
            self.rect.top = 0

# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;Ejemplo de un Pong Simple&quot;)

    # cargamos los objetos
    fondo = load_image(&quot;fondo.jpg&quot;, IMG_DIR, alpha=False)
    bola = Pelota()
    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 posicon del mouse
        pos_mouse = pygame.mouse.get_pos()
        mov_mouse = pygame.mouse.get_rel()

        # Actualizamos los obejos 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 mouse
        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 mouse 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))
        screen.blit(bola.image, bola.rect)
        screen.blit(jugador1.image, jugador1.rect)
        screen.blit(jugador2.image, jugador2.rect)
        pygame.display.flip()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Muy lindo el juego, pero esto tiene un problema; de la manera en que el jugador 2 esta programado es invencible, ya que el oponente siempre llega a la pelota (ya que se mueve junto a ella)</p>
<p><strong>Parte 8: Sonidos básicos</strong></p>
<p>Ahora vamos por los sonidos, quedando el código de esta manera:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import os
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
IMG_DIR = &quot;imagenes&quot;
SONIDO_DIR = &quot;sonidos&quot;

# ------------------------------
# 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 &quot;Error, no se puede cargar la imagen: &quot;, ruta
        sys.exit(1)
    # Comprobar si la imagen tiene &quot;canal alpha&quot; (como los png)
    if alpha == 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, message:
        print &quot;No se pudo cargar el sonido:&quot;, ruta
        sonido = None
    return sonido

# -----------------------------------------------
# Creamos los sprites (clases) de los objetos del juego:


class Pelota(pygame.sprite.Sprite):
    &quot;La bola y su comportamiento en la pantalla&quot;

    def __init__(self, sonido_golpe, sonido_punto):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;bola.png&quot;, 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 &lt; 0 or self.rect.right &gt; SCREEN_WIDTH:
            self.speed[0] = -self.speed[0]
            self.sonido_punto.play()  # Reproducir sonido de punto
        if self.rect.top &lt; 0 or self.rect.bottom &gt; 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):
    &quot;Define el comportamiento de las paletas de ambos jugadores&quot;

    def __init__(self, x):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;paleta.png&quot;, 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 &gt;= SCREEN_HEIGHT:
            self.rect.bottom = SCREEN_HEIGHT
        elif self.rect.top &lt;= 0:
            self.rect.top = 0

    def cpu(self, objetivo):
        self.rect.centery = objetivo.rect.centery
        if self.rect.bottom &gt;= SCREEN_HEIGHT:
            self.rect.bottom = SCREEN_HEIGHT
        elif self.rect.top &lt;= 0:
            self.rect.top = 0

# ------------------------------
# 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(&quot;Ejemplo de un Pong Simple&quot;)

    # cargamos los objetos
    fondo = load_image(&quot;fondo.jpg&quot;, IMG_DIR, alpha=False)
    sonido_golpe = load_sound(&quot;tennis.ogg&quot;, SONIDO_DIR)
    sonido_punto = load_sound(&quot;aplausos.ogg&quot;, 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 posicon del mouse
        pos_mouse = pygame.mouse.get_pos()
        mov_mouse = pygame.mouse.get_rel()

        # Actualizamos los obejos 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 mouse
        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 mouse 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))
        screen.blit(bola.image, bola.rect)
        screen.blit(jugador1.image, jugador1.rect)
        screen.blit(jugador2.image, jugador2.rect)
        pygame.display.flip()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Lo primero que se se hace es crear una función que cargue los sonidos <em>load_sound</em>, es análoga a la función para cargar imágenes. Para abrir el archivo usamos el modulo <a href="http://www.losersjuegos.com.ar/traducciones/pygame/mixer/sound">pygame.mixer.Sound</a> abriendo el sonido de la forma <em>sonido = pygame.mixer.Sound(ruta)</em></p>
<p>Luego en el bucle principal del juego hay que iniciar el modulo mixer (que se encarga de los sonidos), haciendo <em>pygame.mixer.init()</em>. Luego simplemente se cargan los sonidos usando la función que se definio anterioremente, o sea:</p>
<p><pre class="brush: python;">
sonido_golpe = load_sound(&quot;tennis.ogg&quot;, SONIDO_DIR)
sonido_punto = load_sound(&quot;aplausos.ogg&quot;, SONIDO_DIR)
</pre></p>
<p>Los cuales se le pasan luego a la clase pelota haciendo <em>bola = Pelota(sonido_golpe, sonido_punto)</em>. Dentro de la clase pelota estos sonidos se almacenan en <em>self.sonido_golpe</em> y<em> self.sonido_punto</em></p>
<p>Luego en la clase de la pelota usando <a href="http://www.losersjuegos.com.ar/traducciones/pygame/mixer/sound#play">Sound.play()</a> se reproducen los sonidos. Así en el método <em>colision()</em> se le indica que si la pelota colisiona con una paleta reproduzca el archivo &#8220;tennis.ogg&#8221; (que se guardo en self.sonido_golpe) haciendo <em>self.sonido_golpe.play()</em> y en el método <em>update()</em> al llegar a los bordes izquierdo y derecho de la pantalla se reproduce unos aplausos haciendo <em>self.sonido_punto.play()</em></p>
<p><strong>Parte 9: Mejorando el juego (y modificar al oponente)</strong></p>
<p>Nuestro juego tiene los siguientes problemas:</p>
<ol>
<li>Al actualizar la pantalla, tenemos que cargar uno por uno los sprites (lo que no es muy ordenado), así que es mejor agruparlos</li>
<li>El oponente es invencible&#8230;</li>
<li>al marcar un punto, la bola debería volver al centro</li>
</ol>
<p>Para lo primero es bastante fácil, simplemente juntamos los sprites de la forma <em>todos = pygame.sprite.RenderPlain(bola, jugador1, jugador2)</em> y luego los mostramos todos de una vez haciendo <em>todos.draw(screen)</em></p>
<blockquote><p>RenderPlain y RenderClear son alias para <a href="http://www.losersjuegos.com.ar/traducciones/pygame/sprite/group">Group</a> (se mantienen por compatibilidad), por lo tanto se manipulan igual que <a href="http://www.losersjuegos.com.ar/traducciones/pygame/sprite/group">Group</a></p></blockquote>
<p>Ok, ahora mejoramos al oponente (o más bien hay que modificarlo para que no sea invencible) quedando así:</p>
<p><pre class="brush: python;">
def cpu(self, pelota):
    self.speed = [0, 2.5]
    if pelota.speed[0] &gt;= 0 and pelota.rect.centerx &gt;= SCREEN_WIDTH / 2:
        if self.rect.centery &gt; pelota.rect.centery:
            self.rect.centery -= self.speed[1]
        if self.rect.centery &lt; pelota.rect.centery:
            self.rect.centery += self.speed[1]
</pre></p>
<p>No es muy diferente de la versión anterior, pero en este caso se define una velocidad (que en el eje y es de 2.5, lo cual es menor a lo 3 de la pelota) y luego se comprueba que la pelota se mueva a la derecha (hacia la paleta) con <em>pelota.speed[0] &gt;= 0</em> y que la pelota haya pasado la mitad de la pantalla <em>pelota.rect.centerx &gt;= SCREEN_WIDTH / 2</em>, si ambas condiciones se cumplen se comienza a mover la paleta (en caso contrario se queda quieta)</p>
<p>Ahora si se cumplen las condiciones para que se mueva la paleta, se compara la posición de la paleta con la pelota: si la pelota esta mas arriba que la paleta, esta ultima se mueve hacia arriba, por otro lado si la pelota esta abajo de la paleta, esta se mueve hacia abajo.</p>
<p>Con esto el oponente ya no es invencible, debido a que:</p>
<ol>
<li>solo se mueve si la pelota se acerca a el y a pasado la mitad de la pantalla, por lo que el resto del tiempo esta quieto (y por lo tanto la posición de la paleta y la pelota no coinciden siempre)</li>
<li>la paleta se mueve mas lento que la pelota, por lo cual en tramos largos no es capaz de alcanzar a la pelota</li>
</ol>
<p>Combinando ambas, el computador puede perder (pese a que la superficie de la paleta es mayor a la pelota)</p>
<blockquote><p>Nota: esto no es <a href="http://es.wikipedia.org/wiki/Inteligencia_artificial">Inteligencia artificial</a> como tal, sino que es más cercano a un <a href="http://es.wikipedia.org/wiki/Comportamiento">comportamiento predeterminado</a></p></blockquote>
<p>Para el ultimo problema, simplemente en la parte en donde le actualiza la bola, luego de reproducir el sonido, reiniciamos la posición de la bola.</p>
<p>La versión final del juego queda de la siguiente manera:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import os
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
IMG_DIR = &quot;imagenes&quot;
SONIDO_DIR = &quot;sonidos&quot;

# ------------------------------
# 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 &quot;Error, no se puede cargar la imagen: &quot;, ruta
        sys.exit(1)
    # Comprobar si la imagen tiene &quot;canal alpha&quot; (como los png)
    if alpha == 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, message:
        print &quot;No se pudo cargar el sonido:&quot;, ruta
        sonido = None
    return sonido

# -----------------------------------------------
# Creamos los sprites (clases) de los objetos del juego:


class Pelota(pygame.sprite.Sprite):
    &quot;La bola y su comportamiento en la pantalla&quot;

    def __init__(self, sonido_golpe, sonido_punto):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;bola.png&quot;, 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 &lt; 0 or self.rect.right &gt; 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 &lt; 0 or self.rect.bottom &gt; 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):
    &quot;Define el comportamiento de las paletas de ambos jugadores&quot;

    def __init__(self, x):
        pygame.sprite.Sprite.__init__(self)
        self.image = load_image(&quot;paleta.png&quot;, 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 &gt;= SCREEN_HEIGHT:
            self.rect.bottom = SCREEN_HEIGHT
        elif self.rect.top &lt;= 0:
            self.rect.top = 0

    def cpu(self, pelota):
        self.speed = [0, 2.5]
        if pelota.speed[0] &gt;= 0 and pelota.rect.centerx &gt;= SCREEN_WIDTH / 2:
            if self.rect.centery &gt; pelota.rect.centery:
                self.rect.centery -= self.speed[1]
            if self.rect.centery &lt; 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(&quot;Ejemplo de un Pong Simple&quot;)

    # cargamos los objetos
    fondo = load_image(&quot;fondo.jpg&quot;, IMG_DIR, alpha=False)
    sonido_golpe = load_sound(&quot;tennis.ogg&quot;, SONIDO_DIR)
    sonido_punto = load_sound(&quot;aplausos.ogg&quot;, 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 posicon del mouse
        pos_mouse = pygame.mouse.get_pos()
        mov_mouse = pygame.mouse.get_rel()

        # Actualizamos los obejos 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 mouse
        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 mouse 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__ == &quot;__main__&quot;:
    main()
</pre></p>
<blockquote><p>Bueno eso es todo por ahora, pueden descargar<a href="http://sites.google.com/site/dbfuentes/archivos/tutorial-pygame-3.zip?attredirects=0&amp;d=1"> todos estos ejemplos desde aquí</a> (o buscarlo en el repositorio de <a href="http://github.com/dbfuentes/tutorial-pygame">github</a>)</p></blockquote>
<p>Lo unico que le faltaria al juego es un sistema de puntuaciones, pero para eso primero hay que aprender como mostrar texto con pygame, lo cual es uno de los temas a tratar en la siguiente parte de este tutorial (la parte 4).</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/pythonmania.wordpress.com/434/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pythonmania.wordpress.com/434/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/pythonmania.wordpress.com/434/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pythonmania.wordpress.com/434/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/pythonmania.wordpress.com/434/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/pythonmania.wordpress.com/434/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/pythonmania.wordpress.com/434/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/pythonmania.wordpress.com/434/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/pythonmania.wordpress.com/434/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pythonmania.wordpress.com/434/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/pythonmania.wordpress.com/434/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pythonmania.wordpress.com/434/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/pythonmania.wordpress.com/434/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pythonmania.wordpress.com/434/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=434&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		<georss:point>-33.425360 -70.566466</georss:point>
		<geo:lat>-33.425360</geo:lat>
		<geo:long>-70.566466</geo:long>
		<media:content url="" medium="image">
			<media:title type="html">Daniel F.</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2010/04/bola.png" medium="image">
			<media:title type="html">bola</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2010/04/paleta.png" medium="image">
			<media:title type="html">paleta</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2010/04/fondo_tutorial3.jpg?w=300" medium="image">
			<media:title type="html">fondo_tutorial3</media:title>
		</media:content>
	</item>
		<item>
		<title>Tutorial Pygame 2: creando una ventana, cargar imagenes y moverlas</title>
		<link>http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/</link>
		<comments>http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/#comments</comments>
		<pubDate>Thu, 25 Mar 2010 13:54:28 +0000</pubDate>
		<dc:creator>Daniel Fuentes B.</dc:creator>
				<category><![CDATA[pygame]]></category>
		<category><![CDATA[tutoriales]]></category>
		<category><![CDATA[juegos]]></category>

		<guid isPermaLink="false">http://pythonmania.wordpress.com/?p=379</guid>
		<description><![CDATA[En esta segunda parte del tutorial veremos los siguientes temas: Como crear una ventana El bucle principal de un videojuego (o como saber cuando hay que terminar el juego) Usar una imagen como fondo Mostrar una imagen y mover la imagen en la pantalla A continuación la explicación completa Paso 1: Creando una ventana Primero [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=379&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>En esta segunda parte <a href="http://pythonmania.wordpress.com/2010/03/23/tutorial-pygame-introduccion/">del tutorial</a> veremos los siguientes temas:</p>
<ul>
<li>Como crear una ventana</li>
<li>El bucle principal de un videojuego (o como saber cuando hay que terminar el juego)</li>
<li>Usar una imagen como fondo</li>
<li>Mostrar una imagen y mover la imagen en la pantalla</li>
</ul>
<p>A continuación la explicación completa<br />
<span id="more-379"></span><br />
<strong>Paso 1: Creando una ventana</strong></p>
<p>Primero Importamos los módulos y definimos dos variables globales (por metodología se suelen poner en mayúsculas) que son resolución de la pantalla del juego. </p>
<p>Luego hay que crear la ventana, para ello dentro de la función main() usamos <em>pygame.display.set_mode</em> y<em> pygame.display.set_caption</em>, que establecen el tamaño de la ventana y el titulo de esta respectivamente:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

# ------------------------------
# Clases y Funciones utilizadas
# ------------------------------


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;tutorial pygame parte 2&quot;)


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Ahora lo ejecutamos y sorpresa&#8230; se crea la ventana pero inmediatamente se cierra, eso ocurre porque no hemos definido el bucle o loop principal del juego</p>
<p><strong>Paso 2: el bucle principal del juego</strong></p>
<p>Los juegos generalmente ejecutan un bucle infinito (su bucle principal), lo cual permite que el juego continúe corriendo hasta la que se se cumpla una condición que lo termine (como por ejemplo que el jugador pierda todas sus vidas o se rinda), mas o menos lo que muestra este diagrama:</p>
<p><a href="http://pythonmania.files.wordpress.com/2010/03/pygame_bucle_principal.png"><img src="http://pythonmania.files.wordpress.com/2010/03/pygame_bucle_principal.png?w=480" alt="" title="pygame_bucle_principal"   class="aligncenter size-full wp-image-397" /></a></p>
<p>En nuestro caso el bucle principal se continuara ejecutando hasta que el jugador cierre el ventana (o sea que se quede esperando hasta que se haga click en le botón para cerrar la ventana). Entonces el código del paso anterior queda de la siguiente manera:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

# ------------------------------
# Clases y Funciones utilizadas
# ------------------------------


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;tutorial pygame parte 2&quot;)

    # el bucle principal del juego
    while True:
        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Lo que hace es simple, una vez dentro del bucle, recorre la lista que devuelve <em>pygame.event.get()</em> (es una lista con todos los eventos que registra pygame, como por ejemplo cuando uno presiona una tecla), si dentro de esa lista esta el evento pygame.QUIT (o sea cerrar la ventana) el programa ejecuta la orden <em>sys.exit()</em> (que termina la ejecución del programa y es parte del modulo sys, por eso lo importamos), en caso contrario (que aun no se produzca ese evento) seguirá esperando.</p>
<blockquote><p>En <a href="http://www.losersjuegos.com.ar/traducciones/pygame">loserjuegos</a> esta la documentación de referencia de pygame traducida, entre ella l<a href="http://www.losersjuegos.com.ar/traducciones/pygame/event">a lista de los eventos</a></p></blockquote>
<p><strong>Paso 3: Cargando el fondo y una imagen</strong></p>
<p>Primero para cargar las imágenes usamos <em>pygame.image.load()</em>, con ello se crea un objeto que contiene la <a href="http://www.losersjuegos.com.ar/traducciones/pygame/image">superficie de la imagen</a> (aun no la muestra). Luego de esto hay que indicar las posiciones de esta imagen, para lo cual se usa <em>blit(imagen, (coordenada_x, coordenada_y))</em></p>
<p>Puedes pensar en la ventana de pygame <a href="http://es.wikipedia.org/wiki/Geometr%C3%ADa_anal%C3%ADtica#Localizaci.C3.B3n_de_un_punto_en_el_plano_cartesiano">como un plano en 2 ejes</a>, con una pequeña  diferencia: el origen (coordenadas 0,0) se encuentra en la esquina superior izquierda de la ventana. Por lo tanto en valor de las coordenadas en el eje x (horizontal) va aumentando (y es positivo) mientras se avanza a la derecha, mientras que en el eje y (vertical) el valor va aumentando (y es positivo) a medida que se avanza hacia abajo (o sea lo contrario de lo que se acostumbra, para el eje y)</p>
<p>Para que quede más claro, un esquema en que muestra en que posición cargaremos las imágenes (Nota: pygame siempre usa como referencia la esquina superior izquierda de las imágenes)</p>
<p><a href="http://pythonmania.files.wordpress.com/2010/03/pygame_coordenadas.png"><img src="http://pythonmania.files.wordpress.com/2010/03/pygame_coordenadas.png?w=480&#038;h=365" alt="" title="pygame_coordenadas" width="480" height="365" class="aligncenter size-full wp-image-406" /></a></p>
<p>Ahora que ya sabemos sobre coordenadas, vamos a insertar un fondo y una imagen en nuestra ventana, usaremos las siguientes:</p>
<div id="attachment_410" class="wp-caption aligncenter" style="width: 160px"><a href="http://pythonmania.files.wordpress.com/2010/03/fondo.jpg"><img src="http://pythonmania.files.wordpress.com/2010/03/fondo.jpg?w=150&#038;h=112" alt="" title="fondo" width="150" height="112" class="size-thumbnail wp-image-410" /></a><p class="wp-caption-text">fondo.jpg (hacer clic para agrandar)</p></div>
<div id="attachment_414" class="wp-caption aligncenter" style="width: 100px"><a href="http://pythonmania.files.wordpress.com/2010/03/tux.png"><img src="http://pythonmania.files.wordpress.com/2010/03/tux.png?w=480" alt="" title="tux"   class="size-full wp-image-414" /></a><p class="wp-caption-text">tux.png (hacer clic para agrandar)</p></div>
<p>Vamos con el código:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

# ------------------------------
# Clases y Funciones utilizadas
# ------------------------------


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;tutorial pygame parte 2&quot;)

    # cargamos el fondo y una imagen (se crea objetos &quot;Surface&quot;)
    fondo = pygame.image.load(&quot;fondo.jpg&quot;).convert()
    tux = pygame.image.load(&quot;tux.png&quot;).convert_alpha()

    # Indicamos la posicion de las &quot;Surface&quot; sobre la ventana
    screen.blit(fondo, (0, 0))
    screen.blit(tux, (550, 200))
    # se muestran lo cambios en pantalla
    pygame.display.flip()

    # el bucle principal del juego
    while True:
        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Si se fijan al cargar el fondo se uso <em>fondo = pygame.image.load(&#8220;fondo.jpg&#8221;).convert()</em> mientras que para la imagen de tux se uso <em>tux = pygame.image.load(&#8220;tux.png&#8221;).convert_alpha()</em>. Esto se debe a que el fondo no necesita tener un color trasparente (un canal alpha) ya que es la imagen que esta bajo todas las demás, en cambio el sprite de nuestro pingüino si necesita tener un color trasparente (que convenientemente ya esta definido en el png <img src='http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ,  lo hice a propósito cuando lo cree) o de lo contrario al cargar la imagen del pingüino se vería un feo rectángulo a su alrededor</p>
<blockquote><p>Si quieren saber más sobre sprites, resoluciones y similares les recomiendo que lean <a href="http://www.losersjuegos.com.ar/referencia/articulos/conceptos_basicos">este articulo sobre los conceptos básicos para programar un videojuego</a> (pongan ojo en la parte de los sprites)</p></blockquote>
<p>Luego se hizo <em>screen.blit(fondo, (0, 0))</em> y <em>screen.blit(tux, (550, 200))</em>, con esto se le indica que cargue la imagen del fondo justo en la coordenada (0,0) para que cubra toda la pantalla (cualquier otro valor hubiera dejado el fondo desplazado) y en el caso de tux se le indica que lo cargue a la derecha</p>
<p><strong>Paso 4: Moviendo la imagen</strong></p>
<p>Ahora vamos a hacer que tux se mueva a la izquierda, para ello, simplemente a su posición en el eje x le vamos a restar -1 en cada ciclo del bucle principal. Para ello modificamos el código para que quede de la siguiente manera:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

# ------------------------------
# Clases y Funciones utilizadas
# ------------------------------


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;tutorial pygame parte 2&quot;)

    # cargamos el fondo y una imagen (se crea objetos &quot;Surface&quot;)
    fondo = pygame.image.load(&quot;fondo.jpg&quot;).convert()
    tux = pygame.image.load(&quot;tux.png&quot;).convert_alpha()

    tux_pos_x = 550
    tux_pos_y = 200

    # Indicamos la posicion de las &quot;Surface&quot; sobre la ventana
    screen.blit(tux, (tux_pos_x, tux_pos_y))
    screen.blit(fondo, (0, 0))
    # se muestran lo cambios en pantalla
    pygame.display.flip()

    # el bucle principal del juego
    while True:
        # le restamos 1 a la coordenada x de tux
        # asi se mueve un poquito a la izquierda
        tux_pos_x = tux_pos_x - 1
        screen.blit(tux, (tux_pos_x, tux_pos_y))
        # se muestran lo cambios en pantalla
        pygame.display.flip()

        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>y el resultado fue un fallo gigantesco:<br />
<a href="http://pythonmania.files.wordpress.com/2010/03/tutorial_pygame_2_fail.jpg"><img src="http://pythonmania.files.wordpress.com/2010/03/tutorial_pygame_2_fail.jpg?w=480" alt="" title="tutorial_pygame_2_fail"   class="aligncenter size-full wp-image-421" /></a></p>
<p>Explicación: lo que paso es que se nos olvido borrar al pingüino de la pantalla antes de moverlo a su nueva posición, por lo que veremos en realidad un &#8220;rastro&#8221; del movimiento mientras dibujamos continuamente al pingüino en nuevas posiciones. Además nunca le pusimos limite al movimiento del pingüino, por lo que una vez que alcanzo el borde de la pantalla, siguió moviéndose hacia la izquierda hacia el infinito y mas allá&#8230;</p>
<p><strong>Paso 5 (final): Refrescando/borrando la pantalla</strong></p>
<p>La solución mas fácil para borrar el &#8220;rastro&#8221; que se deja al moverse, es simplemente redibujar toda la pantalla (fondo incluido) en cada ciclo del juego, por lo tanto dentro del while, después de actualizar la posición del pingüino, se redibuja tota la pantalla usando <em>blit()</em> y  <em>pygame.display.flip()</em></p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: X11/MIT license http://www.opensource.org/licenses/mit-license.php
# http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/

# ---------------------------
# Importacion de los módulos
# ---------------------------

import pygame
from pygame.locals import *
import sys

# -----------
# Constantes
# -----------

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

# ------------------------------
# Clases y Funciones utilizadas
# ------------------------------


# ------------------------------
# Funcion principal del juego
# ------------------------------


def main():
    pygame.init()
    # creamos la ventana y le indicamos un titulo:
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption(&quot;tutorial pygame parte 2&quot;)

    # cargamos el fondo y una imagen (se crea objetos &quot;Surface&quot;)
    fondo = pygame.image.load(&quot;fondo.jpg&quot;).convert()
    tux = pygame.image.load(&quot;tux.png&quot;).convert_alpha()

    tux_pos_x = 550
    tux_pos_y = 200

    # Indicamos la posicion de las &quot;Surface&quot; sobre la ventana
    screen.blit(tux, (tux_pos_x, tux_pos_y))
    screen.blit(fondo, (0, 0))
    # se muestran lo cambios en pantalla
    pygame.display.flip()

    # el bucle principal del juego
    while True:
        # le restamos 1 a la coordenada x de tux y comprobamos
        # que no alcance el borde de la pantalla
        tux_pos_x = tux_pos_x - 1
        if tux_pos_x &lt; 1:
            tux_pos_x = 550

        # Redibujamos todos los elementos de la pantalla
        screen.blit(fondo, (0, 0))
        screen.blit(tux, (tux_pos_x, tux_pos_y))
        # se muestran lo cambios en pantalla
        pygame.display.flip()

        # Posibles entradas del teclado y mouse
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()


if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Además después de actualizar la tux_pos_x  se coloco un if, de tal manera de que si esa posición es 0 o negativa (o sea esta fuera de la pantalla), la tux_pos_x tome un valor de 550 (550 + 90px que mide de ancho la imagen de tux = 640 px, o sea que la imagen se muestre al borde derecho de la pantalla)</p>
<blockquote><p>Bueno eso es todo por ahora, pueden descargar todos estos ejemplos <a href="http://sites.google.com/site/dbfuentes/archivos/tutorial-pygame-2.zip?attredirects=0&amp;d=1">desde aquí</a> (o buscarlo en el repositorio de <a href="http://github.com/dbfuentes/tutorial-pygame">github</a>).</p></blockquote>
<p>En el próximo tutorial explicaremos como controlar el movimiento de una imagen (con el teclado), colisiones y reproducir algunos sonidos. <a href="http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/">Pueden encontrar esta segunda parte aquí</a></p>
<p>Saludos.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/pythonmania.wordpress.com/379/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pythonmania.wordpress.com/379/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/pythonmania.wordpress.com/379/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pythonmania.wordpress.com/379/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/pythonmania.wordpress.com/379/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/pythonmania.wordpress.com/379/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/pythonmania.wordpress.com/379/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/pythonmania.wordpress.com/379/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/pythonmania.wordpress.com/379/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pythonmania.wordpress.com/379/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/pythonmania.wordpress.com/379/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pythonmania.wordpress.com/379/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/pythonmania.wordpress.com/379/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pythonmania.wordpress.com/379/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=379&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		<georss:point>-33.425360 -70.566466</georss:point>
		<geo:lat>-33.425360</geo:lat>
		<geo:long>-70.566466</geo:long>
		<media:content url="" medium="image">
			<media:title type="html">Daniel F.</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2010/03/pygame_bucle_principal.png" medium="image">
			<media:title type="html">pygame_bucle_principal</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2010/03/pygame_coordenadas.png" medium="image">
			<media:title type="html">pygame_coordenadas</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2010/03/fondo.jpg?w=150" medium="image">
			<media:title type="html">fondo</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2010/03/tux.png" medium="image">
			<media:title type="html">tux</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2010/03/tutorial_pygame_2_fail.jpg" medium="image">
			<media:title type="html">tutorial_pygame_2_fail</media:title>
		</media:content>
	</item>
		<item>
		<title>Tutorial pygame 1: introducción a la programacion de videojuegos</title>
		<link>http://pythonmania.wordpress.com/2010/03/23/tutorial-pygame-introduccion/</link>
		<comments>http://pythonmania.wordpress.com/2010/03/23/tutorial-pygame-introduccion/#comments</comments>
		<pubDate>Wed, 24 Mar 2010 01:47:37 +0000</pubDate>
		<dc:creator>Daniel Fuentes B.</dc:creator>
				<category><![CDATA[pygame]]></category>
		<category><![CDATA[tutoriales]]></category>
		<category><![CDATA[juegos]]></category>

		<guid isPermaLink="false">http://pythonmania.wordpress.com/?p=364</guid>
		<description><![CDATA[Hace tiempo que quería escribir una entrada sobre el uso de pygame para programar juegos. Así que ahora voy a hacerlo en una serie de entradas sobre este tema (aun no estoy seguro de cuantas serán), por lo que esta servirá de introducción e índice (o sea la Parte 1 de este tutorial). Primero, ¿que [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=364&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Hace tiempo que quería escribir una entrada sobre el uso de pygame para programar juegos. Así que ahora voy a hacerlo en una serie de entradas sobre este tema (aun no estoy seguro de cuantas serán), por lo que esta servirá de introducción e índice (o sea la Parte 1 de este tutorial).<br />
<span id="more-364"></span></p>
<p><strong>Primero, ¿que es pygame?</strong></p>
<p>Lo primero que hay que<a href="http://www.pygame.org/"> pygame</a> es una biblioteca multimedia (que trabaja sobre las librerías SDL) que permiten la creación de videojuegos en dos dimensiones de una manera sencilla.</p>
<blockquote><p>Las SDL (Simple DirectMedia Layer) son un conjunto de bibliotecas que proporcionan funciones básicas para realizar operaciones de dibujado 2D, gestión de efectos de sonido, música, carga y gestión de imágenes (y son importantes ya que pygame trabaja sobre ellas). Básicamente es una librería similar a OpenGL o DirectX (solo en la parte 2D), diseñada para ser más fácil de usar que estas otras (además OpenGL solo se encarga de la parte gráfica, en cambio SDL incluye otras cosas como son los sonidos <img src='http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> )</p></blockquote>
<p>Tal como les dije anteriormente usando pygame vamos a programar algunos videojuegos. No esperen programar un juego inmenso en 3D con gráficas espectaculares y que necesite equipos potentes para ser usado. Mas bien lo que vamos a obtener son juegos en 2D similares a los de consolas como supernintendo, portátiles como el GBA, nintendoDS (sin la parte táctil), etc. Para que se hagan una idea de como son los juegos programados con pygame, algunos juegos como <a href="http://fretsonfire.sourceforge.net/">frets on fire</a>, <a href="http://megadriver.wordpress.com/2010/01/18/lo-mejor-de-pygame-solarwolf/">SolarWolf</a> o <a href="http://icculus.org/pyddr/">pydance</a> usan pygame para su desarrollo. Pueden encontrar mas ejemplos en <a href="http://pygame.org/tags/">el sitio de pygame</a></p>
<p>Volviendo al tema Pygame se encarga de manejar la parte más complicada dentro de la programación de un videojuego, o se se encarga de cargar y mostrar las imágenes (en formatos como PNG, BMP, PCX, TGA,&#8230;), sonido (formatos OGG, MP3, MIDI,&#8230;), vídeos, las ventanas del juego y monitoriza los dispositivos de entrada (como mouse, teclado y joystick) de una manera bastante sencilla. Por lo que básicamente uno se tiene que preocupar por la programación del juego en si</p>
<p><strong>Requisitos previos (recomendados)</strong></p>
<ul>
<li>Tener instalado python y pygame (obvio). Ambas están disponibles para varios sistemas (como Windows, GNU/Linux, Mac, etc.) así que los juegos creados pueden ser multiplataforma</li>
<li>Conocimiento básico de python, por lo menos como se definen funciones y <a href="http://mundogeek.net/archivos/2008/03/05/python-orientacion-a-objetos/">clases</a></li>
<li>Conocimientos básicos de matemáticas y física, lo que resulta útil al programar juegos en general (con lo que aprendiste de niño es mas que suficiente). Básicamente es algo de física clásica como los conceptos de velocidad, aceleración, etc. y de matemáticas como los conceptos de puntos, coordenadas en el espacio, etc.</li>
</ul>
<p><strong>Primeros pasos</strong></p>
<p>Lo primero hay que hay que hacer es importar el modulo de pygame, lo cual se hace simplemente como:</p>
<p><pre class="brush: python;">
import pygame
from pygame.locals import *
</pre></p>
<p>La  segunda linea es opcional (pero muy recomendada), ya se utiliza para importar una serie de constantes que tiene pygame (como las teclas del teclado)</p>
<p>Ahora en general nuestro código en pygame tendrá una estructura como esta:<br />
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Importacion de los módulos
import pygame
from pygame.locals import *
# y cualquier otro modulo usado

# ----------------------------------------------
# Constantes, como anchos y largo de pantalla, etc.
# ----------------------------------------------

# ----------------------------------------------
# Clases y Funciones utilizadas (lo explicare en la siguiente parte)
# ----------------------------------------------

def main():
    pygame.init()
    # La clase o función principal que crea o ejecuta el juego
    # Contiene principalmente loop del juego (el alma de este)

if __name__ == &quot;__main__&quot;:
    main()
</pre></p>
<p>Si te fijas en la linea 18 se hace un <em>pygame.init()</em>, esto es para que se inicie pygame y es necesario ejecutarlo antes de empezar a usar pygame (por eso fue incluido al inicio de la función principal del juego). Si no te gusta incluir el <em>pygame.init()</em> en la función del juego, otro buen lugar es incluirlo inmediatamente después del <em>if __name__ == &#8220;__main__&#8221;:</em> (antes de llamar a la función <em>main()</em>)</p>
<p><strong>¿Y ahora que?</strong></p>
<p>Continua leyendo las siguientes entradas sobre el tema, en donde se explica como crear ventanas, personajes, insertar sonidos, etc. Que son las siguientes:</p>
<p><a href="http://pythonmania.wordpress.com/2010/03/25/tutorial-pygame-2-ventana-e-imagenes/"><strong>Parte 2: Creando una ventana, cargando imágenes y moviéndolas al interior de la ventana</strong></a>: En esta segunda parte veremos:</p>
<ul>
<li>Como crear una ventana</li>
<li>el bucle principal de un videojuego (o como saber cuando hay que terminar el juego)</li>
<li>Usar una imagen como fondo</li>
<li>mostrar una imagen y moverla en la pantalla</li>
</ul>
<p><a href="http://pythonmania.wordpress.com/2010/04/07/tutorial-pygame-3-un-videojuego/"><strong>Parte 3: Creando un videojuego (el clasico pong)</strong></a>: En esta parte veremos:</p>
<ul>
<li>Crear una función para cargar imágenes</li>
<li>Como crear sprites (los sprites son personajes, objetos, etc. dentro del juego)</li>
<li>sincronización en los videojuegos (¿que son frames por segundo?)</li>
<li>controlar un sprite con el teclado</li>
<li>controlar un sprite con el mouse</li>
<li>colisiones entre elementos (sprites)</li>
<li>Inteligencia artificial (o la falta de esta)</li>
<li>reproducción de sonidos (al cumplirse alguna condición)</li>
</ul>
<p><strong>Parte 4: manejando texto</strong>: El nombre lo dice todo, una explicación de como mostrar texto en pantalla.</p>
<blockquote><p>Referencias:</p>
<p>Principalmente la documentación de pygame, que <a href="http://www.losersjuegos.com.ar/traducciones/pygame">esta traducida en loserjuegos</a> o si quieren <a href='http://pythonmania.files.wordpress.com/2010/03/pygame_esp_20090205.pdf'>una copia de esta traducción en un pdf (para consultar off-line)</a></p></blockquote>
<blockquote><p>Si alguien quiere el código de los ejemplos, este esta en github:  <a href="http://github.com/dbfuentes/tutorial-pygame">http://github.com/dbfuentes/tutorial-pygame</a></p></blockquote>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/pythonmania.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pythonmania.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/pythonmania.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pythonmania.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/pythonmania.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/pythonmania.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/pythonmania.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/pythonmania.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/pythonmania.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pythonmania.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/pythonmania.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pythonmania.wordpress.com/364/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/pythonmania.wordpress.com/364/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pythonmania.wordpress.com/364/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=364&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://pythonmania.wordpress.com/2010/03/23/tutorial-pygame-introduccion/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<georss:point>-33.425360 -70.566466</georss:point>
		<geo:lat>-33.425360</geo:lat>
		<geo:long>-70.566466</geo:long>
		<media:content url="" medium="image">
			<media:title type="html">Daniel F.</media:title>
		</media:content>
	</item>
		<item>
		<title>actualizar paquetes debian</title>
		<link>http://pythonmania.wordpress.com/2010/03/04/actualizar-paquetes-debian/</link>
		<comments>http://pythonmania.wordpress.com/2010/03/04/actualizar-paquetes-debian/#comments</comments>
		<pubDate>Fri, 05 Mar 2010 01:47:09 +0000</pubDate>
		<dc:creator>Daniel Fuentes B.</dc:creator>
				<category><![CDATA[tutoriales]]></category>
		<category><![CDATA[debian]]></category>

		<guid isPermaLink="false">http://pythonmania.wordpress.com/?p=342</guid>
		<description><![CDATA[En un post anterior explicaba como crear un paquete .deb para un script de python, ahora voy a explicar como actualizar un paquete cualquiera. Tenemos dos casos: Hay que realizar algún cambio pequeño, por ejemplo corregir algún bug que tenga el paquete (nueva revisión del paquete) o aplicar algún parche. Este cambio lo realizas tú, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=342&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>En un post anterior explicaba como <a href="http://pythonmania.wordpress.com/2009/04/25/empaquetar-un-script-python-para-debian/">crear un paquete .deb para un script de python</a>, ahora voy a explicar como actualizar un paquete cualquiera.</p>
<p>Tenemos dos casos: </p>
<ol>
<li>Hay que realizar algún cambio pequeño, por ejemplo corregir algún bug que tenga el paquete (nueva revisión del paquete) o aplicar algún parche. Este cambio lo realizas tú, no el desarrollador del programa (o sea no es una nueva versión del programa, sino que son cambios específicos del paquete)</li>
<li>El desarrollador ha lanzado una nueva versión del programa, por lo que tenemos nuevas fuentes (y necesitamos crear un paquete nuevo para esta versión)</li>
</ol>
<p><span id="more-342"></span><br />
<strong>Primer caso: nueva revisión del paquete</strong></p>
<p>En este caso no ha cambiado el programa fuente, sino que se crea una nueva revisión en donde se corrigen bugs o se agrega algún parche al paquete.</p>
<p>Supongamos que teníamos ya creado el paquete para foo-0.7.2 (foo_0.7.2-1_all.deb y el directorio en donde creamos el paquete es: ~/sandbox/foo-0.7.2) y ahora se encontró un bug por lo que tenemos que crear una nueva revisión del paquete (foo_0.7.2-2_all.deb)</p>
<p>Los pasos son:</p>
<ul>
<li>entrar al directorio en donde creamos el paquete deb (por ejemplo si el directorio debianizado estaba en ~/sandbox/foo-0.7.2, por lo que hay que entrar en el)</li>
<li>En el terminal escribe:</li>
</ul>
<p><code>export DEBFULLNAME="tu nombre"</code><br />
<code>export DEBEMAIL="tu@email.com"</code></p>
<ul>
<li>Añadir una nueva revisión en el fichero de cambios (debian/changelog), la manera mas fácil de hacerlo es con:</li>
</ul>
<p><code>dch -i</code></p>
<ul>
<li>Abrir el debian/changelog y en la nueva entrada (que creamos con dch) hay que incluir una breve descripción del error y su solución en la entrada. </li>
</ul>
<blockquote><p>Si agregas un <em>Closes: #12345</em> al final de los cambios y estas subiendo el paquete a un repositorio oficial (como el de debian o ubuntu) el informe del error numero 12345 será automágicamente cerrado en el sistema de seguimiento de bugs de la distribución</p></blockquote>
<ul>
<li>Modifica el código fuente o los archivos que sean necesarios para corregir el bug (y si se necesario aplica algún parche)</li>
<li>Revisa el resto de los archivos, básicamente tienes que revisar (y hacer en caso de que sea necesario) <a href="http://pythonmania.wordpress.com/2009/04/25/empaquetar-un-script-python-para-debian/">los pasos desde el numero 3 al 6 del tutorial anterior</a> para que se pueda crear correctamente el paquete. </li>
<li>Una vez que ya se hayan hechos los cambios necesario, hay que crear el paquete haciendo:</li>
</ul>
<p><code>dpkg-buildpackage -rfakeroot</code></p>
<ul>
<li>Ahora hay que verificar el paquete, hay que comprobar que:</li>
</ul>
<ol>
<li>Que tiene los ficheros necesarios y ninguno más (lesspipe Nombre_paquete.deb)</li>
<li>Que cumple la policy de Debian, con lintian(lintian Nombre_paquete.deb)</li>
<li>Que instala correctamente (con dpkg -i o gdebi)</li>
</ol>
<ul>
<li>Limpiamos los directorios borrando todos los archivos innecesarios, haciendo:</li>
</ul>
<p><code>fakeroot debian/rules clean</code></p>
<p>Listo ya tienes tu nuevo paquete foo_0.7.2-2_all.deb</p>
<blockquote><p>Nota: es importante limpiar, ya que mas adelante podríamos volver a modificar el paquete (o crear uno nuevo) y para ello el directorio tiene que quedar limpio</p></blockquote>
<p></p>
<p><strong>Segundo caso: nueva versión del programa</strong></p>
<p>Supongamos que teníamos ya creado el paquete para foo-0.8.5, y ahora ha salido la versión foo-0.9.1, tenemos que hacer lo siguiente:</p>
<ul>
<li>Ingresar al directorio padre en donde teníamos el paquete de la versión anterior (por ejemplo si el directorio debianizado estaba en ~/sandbox/foo-0.8.5 hay que ingresar a ~/sandbox/)</li>
<li>Descarga las nuevas fuentes (en el ejemplo foo-0.9.1.tar.gz) y verifica los cambios en el código fuente para saber que es lo nuevo, o sea lee changelog, NEWS, README y cualquier otra documentación. Además ve las diferencias con la versión anterior (busca cualquier cosa que pudiera parecer sospechosa o cambios puedan generar algún problema)</li>
<li>Ahora a las nuevas fuentes hay renombrarlas al formato adecuado para las fuentes, o sea nombre_version.orig.tar.gz (por ejemplo si el archivo fuente es foo-0.9.1.tar.gz, tiene que quedar como foo_0.9.1.orig.tar.gz) y pon el archivo ese archivo un directorio por encima del antiguo árbol de fuentes (por ejemplo tiene que quedar en ~/sandbox/foo_0.9.1.orig.tar.gz)</li>
<li>En el terminal escribe:</li>
</ul>
<p><code>export DEBFULLNAME="tu nombre"</code><br />
<code>export DEBEMAIL="tu@email.com"</code></p>
<ul>
<li>Entra en el antiguo directorio (en este caso ~/sandbox/foo-0.8.5) y ejecuta:</li>
</ul>
<p><code>uupdate -u ../foo_0.9.1.orig.tar.gz</code></p>
<ul>
<li>Ahora tendrás un nuevo directorio (~/sandbox/foo-0.9.1) en donde estarán las nuevas fuentes, a las cuales automagicamente se le agregaron los archivos del directorio debian (que fueron creados a partir de la versión anterior).</li>
<li>Entra en ~/sandbox/foo-0.9.1 y modifica el <em>debian/changelog</em> para completar los cambios (<em>uupdate</em> ya creo una entrada en el <em>debian/changelog</em> sólo tienes que completar la información en caso que falte algo)</li>
<li>Revisa el resto de los archivos, básicamente tienes que revisar (y hacer en caso de que sea necesario) <a href="http://pythonmania.wordpress.com/2009/04/25/empaquetar-un-script-python-para-debian/">los pasos desde el numero 3 al 6 del tutorial anterior</a> para que se pueda crear correctamente el paquete. Probablemente los archivos ya estén creados y solo tienes que revisar si necesitan algún cambio o si se necesita algún extra</li>
<li>Una vez que ya se hayan hechos los cambios necesario, hay que crear el paquete haciendo:</li>
</ul>
<p><code>dpkg-buildpackage -rfakeroot</code></p>
<ul>
<li>Ahora hay que verificar el paquete, hay que comprobar que:</li>
</ul>
<ol>
<li>Que tiene los ficheros necesarios y ninguno más (lesspipe Nombre_paquete.deb)</li>
<li>Que cumple la policy de Debian, con lintian(lintian Nombre_paquete.deb)</li>
<li>Que instala correctamente (con dpkg -i o gdebi)</li>
</ol>
<ul>
<li>Limpiamos los directorios borrando todos los archivos innecesarios, haciendo:</li>
</ul>
<p><code>fakeroot debian/rules clean</code></p>
<blockquote><p>es importante limpiar, ya que mas adelante podríamos volver a modificar el paquete (o crear uno nuevo), así que es bueno dejar los directorios en buenas condiciones</p></blockquote>
<ul>
<li>Listo ya tienes tu nuevo paquete</li>
</ul>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/pythonmania.wordpress.com/342/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pythonmania.wordpress.com/342/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/pythonmania.wordpress.com/342/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pythonmania.wordpress.com/342/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/pythonmania.wordpress.com/342/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/pythonmania.wordpress.com/342/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/pythonmania.wordpress.com/342/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/pythonmania.wordpress.com/342/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/pythonmania.wordpress.com/342/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pythonmania.wordpress.com/342/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/pythonmania.wordpress.com/342/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pythonmania.wordpress.com/342/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/pythonmania.wordpress.com/342/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pythonmania.wordpress.com/342/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=342&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://pythonmania.wordpress.com/2010/03/04/actualizar-paquetes-debian/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<georss:point>-33.425360 -70.566466</georss:point>
		<geo:lat>-33.425360</geo:lat>
		<geo:long>-70.566466</geo:long>
		<media:content url="" medium="image">
			<media:title type="html">Daniel F.</media:title>
		</media:content>
	</item>
		<item>
		<title>pywebkit, navegador web en python</title>
		<link>http://pythonmania.wordpress.com/2010/02/18/pywebkit-navegador-web-en-python/</link>
		<comments>http://pythonmania.wordpress.com/2010/02/18/pywebkit-navegador-web-en-python/#comments</comments>
		<pubDate>Fri, 19 Feb 2010 02:25:41 +0000</pubDate>
		<dc:creator>Daniel Fuentes B.</dc:creator>
				<category><![CDATA[pyGtk]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://pythonmania.wordpress.com/?p=319</guid>
		<description><![CDATA[Mientras actualizaba debian me encontré con un paquete bastante curioso python-webkit (en donde me di cuenta que su nombre en realidad es pywebkitgtk) y para quien se pregunte que demonios es webkit, simplemente es el motor de renderizado de de algunos navegadores como safari o la pokébola de google Chrome, en otras palabras es el [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=319&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Mientras actualizaba debian me encontré con un paquete bastante curioso <a href="http://packages.debian.org/sid/python-webkit">python-webkit</a> (en donde me di cuenta que su nombre en realidad es <a href="http://code.google.com/p/pywebkitgtk/">pywebkitgtk</a>) y para quien se pregunte que demonios es webkit, simplemente es el motor de renderizado de de algunos navegadores como <a href="http://es.wikipedia.org/wiki/Safari_%28navegador%29">safari</a> o la <strike>pokébola de google</strike> <a href="http://es.wikipedia.org/wiki/Google_Chrome">Chrome</a>, en otras palabras es el encargado de &#8220;mostrar&#8221; o &#8220;dibujar&#8221; las páginas web dentro de un navegador. Claro que hay otras alternativas como <a href="http://www.pygtk.org/pygtkmozembed/">pygtkmozembed</a> (que usa el motor de firefox) pero no dejan mucho margen para manipularlo</p>
<p>Volviendo al tema principal, en resumen vamos a hacer un intento de navegador web, en donde tendremos una barra de direcciones (un entry de gtk) y abajo va a mostrar la pagina que le indiquemos.</p>
<p>Primero instalamos pywebkit, de debian basta con hacer un:</p>
<p><code># apt-get install python-webkit libwebkit-dev</code> </p>
<p>O sino lo bajan <a href="http://code.google.com/p/pywebkitgtk">desde su sitio</a></p>
<p>Luego creamos un navegador muy simple:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Escrito por Daniel Fuentes B.
# Licencia: BSD &lt;http://www.opensource.org/licenses/bsd-license.php&gt;

import pygtk
pygtk.require(&quot;2.0&quot;)
import gtk
import webkit

class Browser:
    # Ventana del programa
    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_position(gtk.WIN_POS_CENTER)
        self.window.set_default_size(800, 600)
        self.window.connect(&quot;destroy&quot;, self.on_quit)

        # Un vBox, en la parte de arriba hay una caja para ingresar
        # la direccion web, y abago se muestra la pagina
        vbox = gtk.VBox()

        # La parte de la entrada de la url
        self.url_text = gtk.Entry()
        self.url_text.connect('activate', self.url_text_activate)

        # La parte en donde se muestra la pagina que se visita (con scroll incluido)
        self.scroll_window = gtk.ScrolledWindow()
        self.webview = webkit.WebView()
        self.scroll_window.add(self.webview)

        # Unimos todo en el vBox
        vbox.pack_start(self.url_text, fill=True, expand=False)
        # El expand=False al empaquetarlo es para que el entry no ocupe media pantalla
        vbox.pack_start(self.scroll_window, True, True)
        self.window.add(vbox)
        self.window.show_all()

    # Definimos las señales y demas cosas de la ventana:
    def url_text_activate(self, entry):
    # al activar el entry (por ejemplo al hacer enter), se obtiene el
    # texto de la entry (la url) y se activa la funcion que abre la url
        self.open_url(entry.get_text())

    def on_quit(self, widget):
        gtk.main_quit()

    # La funcion magica que abre la url que se le pasa 
    def open_url(self, url):
        &quot;Funcion que carga la pagina elegida&quot;
        # cambia el titulo de la ventana
        self.window.set_title(&quot;Ejemplo pywebkitgtk - %s&quot; % url)
        # mostramos la direccion de la pagina abierta en el entry
        self.url_text.set_text(url)
        # abre la pagina
        self.webview.open(url)

if __name__ == &quot;__main__&quot;:
    browser = Browser()
    # abrimos la pagina de inicio (opcional)
    browser.open_url(&quot;http://code.google.com/p/pywebkitgtk/&quot;) 
    gtk.main()

</pre></p>
<p>El codigo se entiende por si mismo. Si se dan cuenta casi todo el código se para crear la ventana con pygtk (<a href="http://pythonmania.wordpress.com/2009/02/05/introduccion-a-pygtk-y-glade/">tal como fue explicado hace mucho tiempo en la introducción a pygtk que escribí</a>), siendo la unica parte que involucra a webkit la parte en donde se define open_url (más o menos a partir de la linea 50)</p>
<p>Y les dejo una captura del ejemplo funcionando:<br />
<a href="http://pythonmania.files.wordpress.com/2010/02/pywebkit-gtk.png"><img src="http://pythonmania.files.wordpress.com/2010/02/pywebkit-gtk.png?w=300&#038;h=233" alt="pywebkit-gtk" title="pywebkit-gtk" width="300" height="233" class="aligncenter size-medium wp-image-336" /></a></p>
<p>Si alguien se interesa en la <a href="http://code.google.com/p/pywebkitgtk/source/browse/#svn/trunk/demos">web del proyecto hay un navegador mucho más funcional</a> o puede revisar <a href="http://damncorner.blogspot.com/2009/10/cairo-pywebkit-y-pygtk-semana-de.html">este blog</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/pythonmania.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pythonmania.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/pythonmania.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pythonmania.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/pythonmania.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/pythonmania.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/pythonmania.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/pythonmania.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/pythonmania.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pythonmania.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/pythonmania.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pythonmania.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/pythonmania.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pythonmania.wordpress.com/319/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=319&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://pythonmania.wordpress.com/2010/02/18/pywebkit-navegador-web-en-python/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<georss:point>-33.425360 -70.566466</georss:point>
		<geo:lat>-33.425360</geo:lat>
		<geo:long>-70.566466</geo:long>
		<media:content url="" medium="image">
			<media:title type="html">Daniel F.</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2010/02/pywebkit-gtk.png?w=300" medium="image">
			<media:title type="html">pywebkit-gtk</media:title>
		</media:content>
	</item>
		<item>
		<title>Threads en pygtk</title>
		<link>http://pythonmania.wordpress.com/2009/05/21/threads-en-pygtk/</link>
		<comments>http://pythonmania.wordpress.com/2009/05/21/threads-en-pygtk/#comments</comments>
		<pubDate>Thu, 21 May 2009 16:46:12 +0000</pubDate>
		<dc:creator>Daniel Fuentes B.</dc:creator>
				<category><![CDATA[pyGtk]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://pythonmania.wordpress.com/?p=297</guid>
		<description><![CDATA[Uno de los problemas que se producen al crear aplicaciones en pygtk es que si se ejecuta algún comando externo o dentro del mismo código algo que se demore su tiempo en ser ejecutado, mientras se lleva a cabo esta tarea la ventana literalmente se congela/bloquea hasta que se termina de realizar esta tarea, además [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=297&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Uno de los problemas que se producen al crear aplicaciones en pygtk es que si se ejecuta algún comando externo o dentro del mismo código algo que se demore su tiempo en ser ejecutado, mientras se lleva a cabo esta tarea la ventana literalmente se congela/bloquea hasta que se termina de realizar esta tarea, además que no muestra el resultado hasta que termina (y en muchos casos uno quiere mostrar el progreso mientras se ejecuta la tarea)</p>
<p>Una de las soluciones a esto es usar threads (hilos), pero NO &#8220;de la manera normal&#8221; como es usan, ya que si se hace de forma normal, los widgets no se comportan siempre como es debido y a veces los threads ni siquiera funcionan.</p>
<p>La solución es usar los métodos <strong>gtk.gdk.threads_init()</strong>, <strong>gtk.gdk.threads_enter()</strong> y <strong>gtk.gdk.threads_leave()</strong> de la siguiente forma:</p>
<ul>
<li>Al inicio de código hay que poner gtk.gdk.threads_init() para indicarle a la aplicación que se van a usar hilos en la interfaz gráfica (linea 13 del ejemplo)</li>
<li>Luego en la parte del código que que hace el trabajo pesado (y que posiblemente congele la aplicación de manera temporal) hay que poner el gtk.gdk.threads_enter() antes de esas líneas y gtk.gdk.threads_leave() después de esas lineas (lineas 25 y 33 del ejemplo)</li>
</ul>
<p>Ahora veamos el ejemplo (con los correspondientes comentarios), mas adelante lo explico con mas detalles:</p>
<p><pre class="brush: python;">
#!/usr/bin/env python

# Escrito por Daniel Fuentes B.
# Licencia: BSD &lt;http://www.opensource.org/licenses/bsd-license.php&gt;

import pygtk
pygtk.require(&quot;2.0&quot;)
import gtk
import os
import threading

# iniciamos los thead (los iniciamos, aun no lo usamos)
gtk.gdk.threads_init()

comando = &quot;find /var&quot;

# Esta funcion hace el trabajo &quot;pesado&quot;, luego es llamada desde la ventana
def salida_comando(salida_texto, buffer_texto, comando):
    output = os.popen(comando)
    while True:
        linea = output.readline()
        if not linea:
            break
        # Comienza el trababjo pesado, asi que entramos en un thread
        gtk.gdk.threads_enter()
        # Se inserta la siguiente linea de la salida del proceso y luego se
        # coloca el cursor al final del textview (se mueve el scroll)
        iter = buffer_texto.get_end_iter()
        buffer_texto.place_cursor(iter)
        buffer_texto.insert(iter, linea)
        salida_texto.scroll_to_mark(buffer_texto.get_insert(), 0.1)
        # Finaliza el trabajo pesado, asi que salimos del thread
        gtk.gdk.threads_leave()

# Clase con la ventana principal.
class MainWindow:
    def  __init__(self):
        # Definimos la ventana inicial
        ventana = gtk.Window(gtk.WINDOW_TOPLEVEL)
        ventana.set_title(&quot;Ejemplo de threading en gtk&quot;)
        ventana.resize(450,300)
        ventana.connect(&quot;destroy&quot;, gtk.main_quit)
        
        # Creamos una caja vertical con un espacio entre widgets de 5px y con
        # la propiedad homogeneo en False. Luego agragamos las widgets al vbox
        vbox = gtk.VBox(False, 5)
        
        # Una simple etiqueta que se muestra en la parte superior de la ventana
        etiqueta = gtk.Label(&quot;Resultado del comando:&quot;)
        
        # Creamos un textview que tenga un auto scroll, o sea que se desplace
        # solo al aparecer nuevo texto que sobrepase la pantalla
        # en este textview se mostrara la salida del comando ejecutado
        scrollwin = gtk.ScrolledWindow()
        scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        salida_texto = gtk.TextView()
        buffer_texto = salida_texto.get_buffer()
        scrollwin.add(salida_texto)
        
        # creamos un boton, el que iniciara el comando al hacer click en el
        boton = gtk.Button(&quot;iniciar programa&quot;)
        boton.connect(&quot;clicked&quot;, self.on_boton_clicked, salida_texto, buffer_texto, comando)
        
        # Empacamos el textview con scroll y el boton dentro del vbox
        vbox.pack_start(etiqueta, False, False, 0)
        vbox.pack_start(scrollwin)
        vbox.pack_start(boton, False)
        
        # y luego unimos el vbox la ventana pricipal y la mostramos
        ventana.add(vbox)
        ventana.show_all()

    def on_boton_clicked(self, widget, salida_texto, buffer_texto, comando):
        # Este boton es el lanza el hilo (threading) al hacer click sobre el
        hilo = threading.Thread(target=salida_comando, args=(salida_texto, buffer_texto, comando))
        hilo.start()

if __name__ == &quot;__main__&quot;:
    MainWindow()  
    gtk.main()
</pre></p>
<p>Lo que hace el programa es ejecutar un comando <em>&#8220;find /var&#8221;</em> y luego muestra la salida de este en la ventana</p>
<p>La clase MainWindow crea la ventana de pygtk, es muy parecida al primer ejemplo que vimos <a href="http://pythonmania.wordpress.com/2009/02/05/introduccion-a-pygtk-y-glade/">en el tutorial de introducción a pygtk</a>, el único detalle es que al hacer click en el boton (<em>on_boton_clicked</em>) se inicia un thread (hilo) que ejecuta la función salida_comando con los correspondientes argumentos.</p>
<p>En cuanto a la salida_comando es una función que ejecuta un comando (usando os.popen) tal como si uno lo escribiera en un terminal y luego toma el texto que resulta de ejecutar el comando y  lo muestra en el textview de nuestra ventana. Esta funcion contiene la parte del código que hace el trabajo pesado, por esto tiene los gtk.gdk.threads_enter() y gtk.gdk.threads_leave()</p>
<p>Y así se ve la ventana funcionando:</p>
<p><img src="http://pythonmania.files.wordpress.com/2009/05/threads_en_pygtk.png?w=480" alt="threads_en_pygtk" title="threads_en_pygtk"   class="aligncenter size-full wp-image-316" /></p>
<p>Claro que esta no es la única forma de hacerlo, o sino miren en <a href="http://faq.pygtk.org/index.py?req=show&amp;file=faq23.020.htp">las faqs de pygtk</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/pythonmania.wordpress.com/297/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pythonmania.wordpress.com/297/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/pythonmania.wordpress.com/297/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pythonmania.wordpress.com/297/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/pythonmania.wordpress.com/297/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/pythonmania.wordpress.com/297/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/pythonmania.wordpress.com/297/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/pythonmania.wordpress.com/297/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/pythonmania.wordpress.com/297/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pythonmania.wordpress.com/297/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/pythonmania.wordpress.com/297/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pythonmania.wordpress.com/297/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/pythonmania.wordpress.com/297/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pythonmania.wordpress.com/297/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=297&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://pythonmania.wordpress.com/2009/05/21/threads-en-pygtk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<georss:point>-33.425360 -70.566466</georss:point>
		<geo:lat>-33.425360</geo:lat>
		<geo:long>-70.566466</geo:long>
		<media:content url="" medium="image">
			<media:title type="html">Daniel F.</media:title>
		</media:content>

		<media:content url="http://pythonmania.files.wordpress.com/2009/05/threads_en_pygtk.png" medium="image">
			<media:title type="html">threads_en_pygtk</media:title>
		</media:content>
	</item>
		<item>
		<title>Generador de contraseñas aleatoreas</title>
		<link>http://pythonmania.wordpress.com/2009/05/02/generador-de-contrasenas-aleatoreas/</link>
		<comments>http://pythonmania.wordpress.com/2009/05/02/generador-de-contrasenas-aleatoreas/#comments</comments>
		<pubDate>Sun, 03 May 2009 01:46:45 +0000</pubDate>
		<dc:creator>Daniel Fuentes B.</dc:creator>
				<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://pythonmania.wordpress.com/?p=281</guid>
		<description><![CDATA[Eso es exactamente, un generador de contraseñas aleatorias, rápido y bonito, obviamente hoy hay nada de criptografía en este, solo se escogen valores al azar obtenidos desde una cadena para formar una contraseña (como las típicas que te asignan al registrarse en algun sitio) bastante simple, en longitud se le indica la longitud de la [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=281&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Eso es exactamente, un generador de contraseñas aleatorias, rápido y bonito, obviamente hoy hay nada de criptografía en este, solo se escogen valores al azar obtenidos desde una cadena para formar una contraseña (como las típicas que te asignan al registrarse en algun sitio)</p>
<p><pre class="brush: python;">
#!/usr/bin/env python

from random import choice

longitud = 18
valores = &quot;0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&lt;=&gt;@#%&amp;+&quot;

p = &quot;&quot;
p = p.join([choice(valores) for i in range(longitud)])
print p
</pre></p>
<p>bastante simple, en <strong>longitud</strong> se le indica la longitud de la contraseña (en este caso 18 letras) y en <strong>valores</strong> son las posibles letras con las que se formaran la contraseña (allí cada uno escoge ). </p>
<blockquote><p>Nota: puede ser recomendable omitir el 1,l,O,0 porque a veces se confunden y omitir algunas letras para que por azar no se creen palabras ofensivas.</p></blockquote>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/pythonmania.wordpress.com/281/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pythonmania.wordpress.com/281/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/pythonmania.wordpress.com/281/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pythonmania.wordpress.com/281/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/pythonmania.wordpress.com/281/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/pythonmania.wordpress.com/281/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/pythonmania.wordpress.com/281/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/pythonmania.wordpress.com/281/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/pythonmania.wordpress.com/281/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pythonmania.wordpress.com/281/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/pythonmania.wordpress.com/281/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pythonmania.wordpress.com/281/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/pythonmania.wordpress.com/281/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pythonmania.wordpress.com/281/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pythonmania.wordpress.com&amp;blog=4775017&amp;post=281&amp;subd=pythonmania&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://pythonmania.wordpress.com/2009/05/02/generador-de-contrasenas-aleatoreas/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<georss:point>-33.425360 -70.566466</georss:point>
		<geo:lat>-33.425360</geo:lat>
		<geo:long>-70.566466</geo:long>
		<media:content url="" medium="image">
			<media:title type="html">Daniel F.</media:title>
		</media:content>
	</item>
	</channel>
</rss>
