<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>Razón Artificial</title>
	
	<link>http://razonartificial.com</link>
	<description>La ciencia y el arte de crear videojuegos</description>
	<lastBuildDate>Sat, 28 Aug 2010 16:46:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/RazonArtificial" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="razonartificial" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">RazonArtificial</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>Gráficos para prototipos de juegos</title>
		<link>http://razonartificial.com/2010/08/graficos-para-prototipos-de-juegos/</link>
		<comments>http://razonartificial.com/2010/08/graficos-para-prototipos-de-juegos/#comments</comments>
		<pubDate>Sat, 28 Aug 2010 11:27:02 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Gráficos]]></category>
		<category><![CDATA[Recursos]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=721</guid>
		<description><![CDATA[Os traigo un pack de recursos ideal para hacer prototipos de videojuegos o como el autor los llama Los milagrosamente flexibles gráficos para prototipos de juegos para Mundos Pequeños de Danc. El caso es que se tratan de unos gráfico en formato vectorial de una alta calidad. Son ideales para que los programadores los usen [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://razonartificial.com/wp-content/uploads/2010/08/SmallWorld-Mockup-2-790698.jpg"><img class="size-medium wp-image-722 alignright imageborder" title="SmallWorld-Mockup-2-790698" src="http://razonartificial.com/wp-content/uploads/2010/08/SmallWorld-Mockup-2-790698-279x300.jpg" alt="" width="223" height="240" /></a></p>
<p>Os traigo un pack de recursos ideal para hacer prototipos de videojuegos o como el autor los llama <strong>Los milagrosamente flexibles gráficos para prototipos de juegos para Mundos Pequeños de Danc</strong>. El caso es que se tratan de unos gráfico en formato vectorial de una alta calidad.</p>
<p>Son ideales para que los programadores los usen en prototipos de videojuego, como el autor dice, son muy útiles para juegos tipo cajón de arena, estrategias y demás juegos donde el jugador puede colocar objetos de forma arbitraria. Al ser vectoriales puedes redimensionarlos al tamaño que necesites para adaptarlo a tu proyecto.</p>
<p>Los gráficos están disponibles con una <a href="http://lostgarden.com/2007/03/lost-garden-license.html">licencia</a> Creative Commons de atribución, así que son gratuitos para su uso y distribución mientras se dé el debido crédito. Los gráficos vienen en SVG, Illustrator, Flash, además de archivo SWF.</p>
<ul>
<li><a href="http://www.lostgarden.com/2009/03/dancs-miraculously-flexible-game.html">Descargar de la página del autor</a></li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/pack-de-graficos-libres/" title="Pack de gráficos para juegos">Pack de gráficos para juegos</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/H2aFtS-VEj5NNraaGnb5OdFlUdg/0/da"><img src="http://feedads.g.doubleclick.net/~a/H2aFtS-VEj5NNraaGnb5OdFlUdg/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/H2aFtS-VEj5NNraaGnb5OdFlUdg/1/da"><img src="http://feedads.g.doubleclick.net/~a/H2aFtS-VEj5NNraaGnb5OdFlUdg/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/kM5d61IQ7yI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/graficos-para-prototipos-de-juegos/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Fmod – Audio en los videojuegos</title>
		<link>http://razonartificial.com/2010/08/fmod-audio-en-los-videojuegos/</link>
		<comments>http://razonartificial.com/2010/08/fmod-audio-en-los-videojuegos/#comments</comments>
		<pubDate>Sat, 28 Aug 2010 10:46:22 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Audio]]></category>
		<category><![CDATA[Biblioteca]]></category>
		<category><![CDATA[Fmod]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Sonido]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=711</guid>
		<description><![CDATA[Fmod es una api para manejar sonidos multiplataforma ampliamente usada en el mundo de los videojuegos. Su lenguaje principal es C++, pero soporta muchos otros como Visual Basic o Delphi. Fmod se puede usar en los siguientes dispositivos. Windows (32 bits y 64 bits) Macintosh (PPC, x86) iPhone de Apple, IPAD Linux (32 bits y [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://razonartificial.com/wp-content/uploads/2010/08/unreal01.jpg"><img class="alignright size-medium wp-image-713 imageborder" title="unreal01" src="http://razonartificial.com/wp-content/uploads/2010/08/unreal01-300x183.jpg" alt="" width="300" height="183" /></a></p>
<p><a href="http://www.fmod.org/">Fmod</a> es una api para manejar sonidos multiplataforma ampliamente usada en el mundo de los videojuegos. Su lenguaje principal es C++, pero soporta muchos otros como Visual Basic o Delphi. Fmod se puede usar en los siguientes dispositivos.</p>
<ul>
<li><span><span>Windows (32 bits y 64 bits)</span></span></li>
<li><span><span>Macintosh (PPC, x86)</span></span></li>
<li><span><span>iPhone de Apple, IPAD</span></span></li>
<li><span><span>Linux (32 bits y 64 bits)</span></span></li>
<li><span><span>Sony PS2, PS3 y PSP</span></span></li>
<li><span><span>Microsoft Xbox y Xbox 360</span></span></li>
<li><span><span>Nintendo Gamecube y Wii</span></span></li>
</ul>
<p>Tiene una gran fama en la creación de audio de grandes videojuegos, por ejemplo, se encarga de toda la saga Halo. Muchos engines profesionales tienen integración con fmod, tales como:</p>
<ul>
<li>CryENGINE (FMOD is la api por defecto)</li>
<li>Unity (FMOD is la api por defecto)</li>
<li>Unreal Engine 3 (FMOD Designer 2010 tiene una integración muy grande)</li>
<li>BigWorld (FMOD is la api por defecto)</li>
<li>Vision Engine</li>
<li>Scaleform</li>
</ul>
<p>Fmod se compone de dos parte. La <a href="http://www.fmod.org/index.php/products/fmodex">librería</a> en sí y el <a href="http://www.fmod.org/index.php/products/designer">Fmod designer</a> que es toda una interfaz para la creación de sonidos que luego se usan con la api. Tiene editor visual en los engines sitados arriba, donde el artista del audio se sentirá como pez en al agua sin necesidad de saber programar colocando sonidos.</p>
<p>Es totalmente gratuita para uso no comercial y una biblioteca obligada para todo el que esté interesado en el audio de los videojuegos.</p>
<p>Dejo un pdf que he encontrado con una pequeña introducción a Fmod, es de una versión antigua pero puede valer.</p>
<ul>
<li><a href="http://razonartificial.com/wp-content/uploads/2010/08/fmod.pdf">Descargar introducción</a></li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/" title="Arboles e inteligencia artificial II">Arboles e inteligencia artificial II</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/" title="Arboles e inteligencia Artificial">Arboles e inteligencia Artificial</a></li><li><a href="http://razonartificial.com/2010/08/orts-estrategia-en-tiempo-real-opensource/" title="ORTS. Estrategia en tiempo real OpenSource">ORTS. Estrategia en tiempo real OpenSource</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/08/curso-python-v-funciones-del-usuario/" title="Curso Python V – Funciones del usuario">Curso Python V – Funciones del usuario</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/7NLi0hYL4stfsyhl8vVYD3yhxzo/0/da"><img src="http://feedads.g.doubleclick.net/~a/7NLi0hYL4stfsyhl8vVYD3yhxzo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/7NLi0hYL4stfsyhl8vVYD3yhxzo/1/da"><img src="http://feedads.g.doubleclick.net/~a/7NLi0hYL4stfsyhl8vVYD3yhxzo/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/Kjs0ZsUCuP4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/fmod-audio-en-los-videojuegos/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Arboles e inteligencia artificial II</title>
		<link>http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/</link>
		<comments>http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/#comments</comments>
		<pubDate>Thu, 26 Aug 2010 09:21:27 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Árboles]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Juegos]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=705</guid>
		<description><![CDATA[En la parte 1 de este artículo aprendimos sobre los árboles y como crearlos. En esta parte vamos a darle uso en un problema de inteligencia artificial. El árbol de los animales Vamos a crear una I.A. que tratará de adivinar en que animal estamos pensando. El programa irá aprendiendo a medida que jugamos y [...]]]></description>
			<content:encoded><![CDATA[<p>En la parte 1 de este artículo aprendimos sobre los árboles y como crearlos. En esta parte vamos a darle uso en un problema de inteligencia artificial.</p>
<h2>El árbol de los animales</h2>
<p>Vamos a crear una I.A. que tratará de adivinar en que animal estamos pensando. El programa irá aprendiendo a medida que jugamos y jugamos conocerá más animales. Lo que vamos a hacer es crear un árbol que vaya creciendo poco a poco.</p>
<p>Veamos una ejecución  del programa para que veáis como funciona.</p>
<pre>
Estas pensando en un animal? s
Es un pajaro? n
Qué animal era? Raton
Qué diferencia a un pajaro de un Raton? vuela
Si el animal fuera un pajaro cual seria la respuesta? s
Estas pensando en un animal? s
vuela? s
Es un pajaro? n
Qué animal era? Aguila
Qué diferencia a un pajaro de un Aguila? caza
Si el animal fuera un pajaro cual seria la respuesta? n
Estas pensando en un animal? s
vuela? n
Es un Raton? n
Qué animal era? Perro
Qué diferencia a un Raton de un Perro? Ladra
Si el animal fuera un Raton cual seria la respuesta? n
Estas pensando en un animal? s
vuela? n
Ladra? n
Es un Raton? n
Qué animal era? Rinoceronte
Qué diferencia a un Raton de un Rinoceronte? tiene colmillos
Si el animal fuera un Raton cual seria la respuesta? n
Estas pensando en un animal? s
vuela? s
caza? n
Es un pajaro? n
Qué animal era? Buitre
Qué diferencia a un pajaro de un Buitre? come carroña
Si el animal fuera un pajaro cual seria la respuesta? n
Estas pensando en un animal? s
vuela? n
Ladra? n
tiene colmillos? s
Es un Rinoceronte? n
Qué animal era? Elefante
Qué diferencia a un Rinoceronte de un Elefante? tienen trompa
Si el animal fuera un Rinoceronte cual seria la respuesta? n
Estas pensando en un animal? s
vuela? n
Ladra? n
tiene colmillos? s
tienen trompa? n
Es un Rinoceronte? n
Qué animal era? Jabali
Qué diferencia a un Rinoceronte de un Jabali? vive en el agua
Si el animal fuera un Rinoceronte cual seria la respuesta? s
Estas pensando en un animal? s
vuela? n
Ladra? n
tiene colmillos? n
Es un Raton? n
Qué animal era? Jirafa
Qué diferencia a un Raton de un Jirafa? tiene el cuello largo
Si el animal fuera un Raton cual seria la respuesta? n
Estas pensando en un animal? s
vuela? s
caza? n
come carroña? n
Es un pajaro? n
Qué animal era? Mosca
Qué diferencia a un pajaro de un Mosca? es un insecto
Si el animal fuera un pajaro cual seria la respuesta? n
Estas pensando en un animal? s
vuela? n
Ladra? n
tiene colmillos? s
tienen trompa? n
vive en el agua? s
Es un Rinoceronte? s
Soy el más grande!
</pre>
<p>Como se puede ver inicialmente el programa no &#8220;sabe&#8221; nada, solo sabe el nodo inicial que es pájaro y pregunta si es un pájaro. Si se le dice que no te preguntará que animal estabas pensando y te pedira que lo diferencies del que te a sugerido él para almacenarlo en su árbol. Así ha medida que se va jugando e introduciendo animales el programa va conociendo más ya que su árbol se va ramificando.</p>
<p>Veamos otra ejecución del programa más corta para anilizarla.</p>
<pre>
Está pensando en un animal? s
Es un pájaro? n
Cómo se llama el animal? perro
Qué pregunta distinguiría a un perro de un pájaro? Puede volar
Si el animal fuera un perro, cuál sería la respuesta? n
Estás pensando en un animal? s
Puede volar? n
Es un perro? n
Cómo se llama el animal? gato
Qué pregunta distinguiría a un gato de un perro? Ladra
Si el animal fuera un gato, cuál sería la respuesta? n
Estás pensando en un animal? s
Puede volar? n
Ladra? s
Es un perro? s
Soy el más grande!
</pre>
<p>Esto generaría el siguiente árbol binario.</p>
<p><img src="http://razonartificial.com/wp-content/uploads/2010/08/diag1.png" alt="" title="diag1" width="291" height="259" class="aligncenter size-full wp-image-707" /></p>
<p>Como vemos según la información que le damos va generando nuestro árbol. Al principio de cada ronda empieza en lo más alto del árbol y hace la pregunta que contiene el nodo, cuando llega a un nodo hoja trata de adivinar. Date cuenta que todos los animales son nodos hojas y todas las preguntas son nodos ramas. Si falla pide el a usuario el nombre del nuevo animal y una diferencia con el intento fallido, entonces añade el nuevo animal y la nueva pregunta al árbol.</p>
<p>El código a continuación</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos

# Clases
# ---------------------------------------------------------------------

class Arbol:
	def __init__(self, carga=None, izq=None, der=None):
		self.carga = carga
		self.izquierda = izq
		self.derecha = der

	def __str__(self):
		return str(self.carga)

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def si(preg):
	from string import lower
	resp = lower(raw_input(preg))
	return (resp[0] == 's')

# ---------------------------------------------------------------------

def main():
	bucle = True
	raiz = Arbol(&quot;pajaro&quot;)
	while bucle:
		if not si(&quot;Estas pensando en un animal? &quot;): break

		arbol = raiz
		while arbol.izquierda != None:
			if si(arbol.carga + &quot;? &quot;):
				arbol = arbol.izquierda
			else:
				arbol = arbol.derecha

		#adivinar
		animal = arbol.carga
		if si(&quot;Es un &quot; + animal + &quot;? &quot;):
			print &quot;Soy el más grande!&quot;
			continue

		#obtener informacion
		nuevo = raw_input(&quot;Qué animal era? &quot;)
		info = raw_input(&quot;Qué diferencia a un &quot; + animal + &quot; de un &quot; + nuevo + &quot;? &quot;)
		indicador = &quot;Si el animal fuera un &quot; + animal + &quot; cual seria la respuesta? &quot;
		arbol.carga = info
		if si(indicador):
			arbol.izquierda = Arbol(animal)
			arbol.derecha = Arbol(nuevo)
		else:
			arbol.derecha = Arbol(animal)
			arbol.izquierda = Arbol(nuevo)

	return 0

if __name__ == '__main__':
	main()
</pre>
<p>La función si() devuelve verdadero si se ha escrito S o s y falso si se ha escrito otra cosa. Es esta función la que interactúa con el usuario.</p>
<p>La condición del bucle externo es 1, lo que significa que seguirá hasta que se ejecute la sentencia break cuando el usuario ya no piense en ningún animal. El bucle while interno recorre el  árbol de arriba a abajo, guiado por las respuestas del usuario. Cuando se añade un nuevo nodo al árbol, la pregunta sustituye a la carga y los dos hijos son el animal nuevo y la carga original.</p>
<p>Una carencia del programa es que, al salir, ¡olvida todo lo que le habías enseñado con tanto cuidado! Esto se soluciona almacenando la estructura del árbol en algún archivo o base de datos.</p>
<p>Este código tan simple si se le implementa una base de datos online que vaya haciendo crecer el árbol en cada juego de los usuarios. Al cabo de un tiempo, después de muchos juegos sería capaz de adivinar cualquier animal.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/" title="Arboles e inteligencia Artificial">Arboles e inteligencia Artificial</a></li><li><a href="http://razonartificial.com/2010/08/orts-estrategia-en-tiempo-real-opensource/" title="ORTS. Estrategia en tiempo real OpenSource">ORTS. Estrategia en tiempo real OpenSource</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/08/la-inteligencia-artificial-de-l4d/" title="La Inteligencia Artificial de L4D">La Inteligencia Artificial de L4D</a></li><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/Yif7ZnyUWOr7-gWTqcHLg2VotUs/0/da"><img src="http://feedads.g.doubleclick.net/~a/Yif7ZnyUWOr7-gWTqcHLg2VotUs/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/Yif7ZnyUWOr7-gWTqcHLg2VotUs/1/da"><img src="http://feedads.g.doubleclick.net/~a/Yif7ZnyUWOr7-gWTqcHLg2VotUs/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/Ow7t4reZxZk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Arboles e inteligencia Artificial</title>
		<link>http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/</link>
		<comments>http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/#comments</comments>
		<pubDate>Thu, 26 Aug 2010 06:12:33 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Árboles]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=696</guid>
		<description><![CDATA[Existen muchas estructuras de datos y conocerlas y saberlas aplicar es fundamental para programar. En este artículo os voy a hablar de una estructura de datos muy usada en el desarrollo de videojuegos en general y en la inteligencia artificial en particular. Los árboles. Los árboles son una estructura de dato compuesta de nodos que [...]]]></description>
			<content:encoded><![CDATA[<p>Existen muchas estructuras de datos y conocerlas y saberlas aplicar es fundamental para programar. En este artículo os voy a hablar de una estructura de datos muy usada en el desarrollo de videojuegos en general y en la inteligencia artificial en particular. Los árboles.</p>
<p>Los árboles son una estructura de dato compuesta de nodos que a su vez tienen nodos hijos. Cada nodo está compuesto de una carga y en enlace a sus nodos hijos.</p>
<p><img class="aligncenter size-full wp-image-697" title="arbol" src="http://razonartificial.com/wp-content/uploads/2010/08/arbol.jpg" alt="" width="513" height="310" />Como vemos en este árbol las cargas son números enteros como 65, 58, 79, etc. Los nodos tienen hijos a los que apuntan, por ejemplo, el nodo 65 tiene 2 nodos hijos 58 y 79. 58 a su vez tiene 3 hijos 25, 96 y 12.</p>
<p>Los árboles se componen de un nodo principal que no tienen padre en nuestro caso es 65 que se llama tronco (por el símil con el árbol) Luego los nodos hijos que van saliendo de él se llaman ramas hasta llegar a nodos que no tienen nodos hijos que son llamados hojas.</p>
<h2>Arboles binarios</h2>
<p>Vamos a centrarnos en este artículo en los árboles binarios. Los árboles binarios son árboles  que tienen solo dos nodos hijos. Se va bifurcando de dos en dos, por esto lo de binarios.</p>
<p><img class="aligncenter size-full wp-image-698" title="Binary_tree_(oriented_digraph)" src="http://razonartificial.com/wp-content/uploads/2010/08/Binary_tree_oriented_digraph.png" alt="" width="260" height="229" /></p>
<p>Como vemos en este árbol hay como máximo dos nodos hijos en cada rama. Esto es un árbol binario.</p>
<h3>Creando el tipo de dato</h3>
<p>Vamos a proceder a crear este tipo de dato en python:</p>
<pre class="brush: python;">
class Arbol:
	def __init__(self, carga=None, izq=None, der=None):
		self.carga = carga
		self.izquierda = izq
		self.derecha = der

	def __str__(self):
		return str(self.carga)
</pre>
<p>Como vemos recibe tres valores, la carga y sus dos nodos hijos, en un principio todo definido con None. Para crear un arbol podríamos hacer lo siguiente.</p>
<pre class="brush: python;">
arbol = Arbol(5)
</pre>
<p>Esto nos dejaría lo siguiente.</p>
<p><img src="http://razonartificial.com/wp-content/uploads/2010/08/arb1.png" alt="" title="arb1" width="131" height="94" class="aligncenter size-full wp-image-699" /></p>
<p>Para añadirle dos nodos hijos bastaría con lo siguiente.</p>
<pre class="brush: python;">
arbol = Arbol(5)
arbol.izquierda = Arbol(4)
arbol.derecha = Arbol(3)
</pre>
<p>Lo que nos dejaría el siguiente diagrama.</p>
<p><a href="http://razonartificial.com/wp-content/uploads/2010/08/arb2.png"><img src="http://razonartificial.com/wp-content/uploads/2010/08/arb2.png" alt="" title="arb2" width="304" height="189" class="aligncenter size-full wp-image-701" /></a></p>
<p>Lo anterior se puede resumir en una línea de código.</p>
<pre class="brush: python;">
arbol = Arbol(5, Arbol(4), Arbol(3))
</pre>
<p>El resultado es el mismo. Como vemos cada llamada a la clase Arbol() solo nos genera un nodo del árbol. Hemos definido el método __str__ que sustituye el valor de print aplicado al objeto, mostrando solo la carga.</p>
<p>Lo más importante para un tipo de dato es tener una manera de recorrerlo, vamos a implementar una función que recorra todos los nodos del árbol y nos devuelva la suma de sus cargas</p>
<pre class="brush: python;">
class Arbol:
	def __init__(self, carga=None, izq=None, der=None):
		self.carga = carga
		self.izquierda = izq
		self.derecha = der

	def __str__(self):
		return str(self.carga)

def suma(arbol):
	if arbol == None: return 0
	return suma(arbol.izquierda) + suma(arbol.derecha) + arbol.carga

arbol = Arbol(5, Arbol(4), Arbol(3))
print suma(arbol)
</pre>
<p>Como vemos nuestra función suma recibe el nodo padre como parámetro. Tiene la condición base de que si el arbol vale None (esta vacío) pues su valor es 0 si no se cumple se llama recursivamente para calcular el valor de sus hijos más la carga cuando alcanza un nodo que vale None retornará 0 y saldrá de la recursividad.</p>
<p>Los árboles binarios sirven para ir eligiendo entre opciones que se van ramificando. Es útil para comportamientos y toma decisiones de una posible I.A.</p>
<p>En la segunda parte veremos como aplicar los árboles a un problema de Inteligencia Artificial.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/" title="Arboles e inteligencia artificial II">Arboles e inteligencia artificial II</a></li><li><a href="http://razonartificial.com/2010/08/orts-estrategia-en-tiempo-real-opensource/" title="ORTS. Estrategia en tiempo real OpenSource">ORTS. Estrategia en tiempo real OpenSource</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/08/la-inteligencia-artificial-de-l4d/" title="La Inteligencia Artificial de L4D">La Inteligencia Artificial de L4D</a></li><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/sFxzU0zeSRfpSgLez6fk6-mP2u8/0/da"><img src="http://feedads.g.doubleclick.net/~a/sFxzU0zeSRfpSgLez6fk6-mP2u8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/sFxzU0zeSRfpSgLez6fk6-mP2u8/1/da"><img src="http://feedads.g.doubleclick.net/~a/sFxzU0zeSRfpSgLez6fk6-mP2u8/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/Mxrx7WabN0Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GameDevLesson – Crear videojuegos</title>
		<link>http://razonartificial.com/2010/08/gamedevlesson-crear-videojuegos/</link>
		<comments>http://razonartificial.com/2010/08/gamedevlesson-crear-videojuegos/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 23:54:02 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[Diseño]]></category>
		<category><![CDATA[Planificación]]></category>
		<category><![CDATA[Juegos]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=690</guid>
		<description><![CDATA[Desde el més de Abril del 2009, Chris DeLeon, un desarrollador independiente con un gran interés en ayudar a otros a crear videojuegos, ofrece en su sitio web www.gamedevlessons.com una serie de boletines mensuales y gratuitos donde instruye y da consejos a todo aquel que esté interesado en el desarrollo de videojuegos, a todos los niveles, desde [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://razonartificial.com/wp-content/uploads/2010/08/pen.jpg"><img class="size-full wp-image-685 imageborder alignright" title="pen" src="http://razonartificial.com/wp-content/uploads/2010/08/pen.jpg" alt="" width="200" height="200" /></a>Desde el més de Abril del 2009, <a href="http://gamedevlessons.com/lessons/acerca_de.html" target="_blank">Chris DeLeon</a>, un desarrollador independiente con un gran interés en ayudar a otros a crear videojuegos, ofrece en su sitio web <a href="http://www.gamedevlessons.com/" target="_blank">www.gamedevlessons.com</a> una serie de boletines mensuales y gratuitos donde instruye y da consejos a todo aquel que esté interesado en el desarrollo de videojuegos, a todos los niveles, desde el novato al experimentado.</p>
<p>En <a href="http://www.proyecto-iris.com/">Proyecto Iris</a> están llevando a cabo una traducción de estas lecciones al español, merece la pena echarle un vistazo a todo este material teórico que muchas veces pasamos por alto a la hora de crear videojuegos y es incluso más importante el diseño que la parte de programación o gráficos.</p>
<ul>
<li><a href="http://www.proyecto-iris.com/gamedevlessonscom/">Lecciones traducidas</a></li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/conceptos-de-diseno-de-videojuegos/" title="Conceptos de Diseño de Videojuegos">Conceptos de Diseño de Videojuegos</a></li><li><a href="http://razonartificial.com/2010/08/orts-estrategia-en-tiempo-real-opensource/" title="ORTS. Estrategia en tiempo real OpenSource">ORTS. Estrategia en tiempo real OpenSource</a></li><li><a href="http://razonartificial.com/2010/08/la-inteligencia-artificial-de-l4d/" title="La Inteligencia Artificial de L4D">La Inteligencia Artificial de L4D</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/" title="Arboles e inteligencia artificial II">Arboles e inteligencia artificial II</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/" title="Arboles e inteligencia Artificial">Arboles e inteligencia Artificial</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/mK1TiRxntGqMEyy81aP9W86M77g/0/da"><img src="http://feedads.g.doubleclick.net/~a/mK1TiRxntGqMEyy81aP9W86M77g/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/mK1TiRxntGqMEyy81aP9W86M77g/1/da"><img src="http://feedads.g.doubleclick.net/~a/mK1TiRxntGqMEyy81aP9W86M77g/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/q6oHLlPtQsM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/gamedevlesson-crear-videojuegos/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Conceptos de Diseño de Videojuegos</title>
		<link>http://razonartificial.com/2010/08/conceptos-de-diseno-de-videojuegos/</link>
		<comments>http://razonartificial.com/2010/08/conceptos-de-diseno-de-videojuegos/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 22:23:15 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[Diseño]]></category>
		<category><![CDATA[Enlaces]]></category>
		<category><![CDATA[Juegos]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=684</guid>
		<description><![CDATA[Me he encontrado con esta maravilla un curso de conceptos de diseño de videojuegos. Se trata de una serie de artículos bastante buenos a cerca de una de las áreas que a mi me parece muy importante dentro del desarrollo de videojuegos, su diseño que no debe confundirse con los gráficos. El curso está siendo [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://razonartificial.com/wp-content/uploads/2010/08/pen.jpg"><img class="alignright size-full wp-image-685 imageborder" title="pen" src="http://razonartificial.com/wp-content/uploads/2010/08/pen.jpg" alt="" width="200" height="200" /></a>Me he encontrado con esta maravilla un curso de <a href="http://gamedesignconcepts.pbworks.com/Spanish">conceptos de diseño de videojuegos</a>. Se trata de una serie de artículos bastante buenos a cerca de una de las áreas que a mi me parece muy importante dentro del desarrollo de videojuegos, su diseño que no debe confundirse con los gráficos.</p>
<p>El curso está siendo traducido al español por varios usuarios, van por la mitad de la parte 7, pero parece que lleva un tiempo parado. Quizá cuando tenga algo de tiempo contribuya a traducir, si alguno se anima ya sabe.</p>
<p>Tiene cosas muy interesante un enlace que sin duda se merece ir a favoritos.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/gamedevlesson-crear-videojuegos/" title="GameDevLesson &#8211; Crear videojuegos">GameDevLesson &#8211; Crear videojuegos</a></li><li><a href="http://razonartificial.com/2010/08/orts-estrategia-en-tiempo-real-opensource/" title="ORTS. Estrategia en tiempo real OpenSource">ORTS. Estrategia en tiempo real OpenSource</a></li><li><a href="http://razonartificial.com/2010/08/la-inteligencia-artificial-de-l4d/" title="La Inteligencia Artificial de L4D">La Inteligencia Artificial de L4D</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/" title="Arboles e inteligencia artificial II">Arboles e inteligencia artificial II</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/" title="Arboles e inteligencia Artificial">Arboles e inteligencia Artificial</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/pMd8nNrRglvnJ-h1ZzUHAlIP_a8/0/da"><img src="http://feedads.g.doubleclick.net/~a/pMd8nNrRglvnJ-h1ZzUHAlIP_a8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/pMd8nNrRglvnJ-h1ZzUHAlIP_a8/1/da"><img src="http://feedads.g.doubleclick.net/~a/pMd8nNrRglvnJ-h1ZzUHAlIP_a8/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/-LhhMdRCQYY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/conceptos-de-diseno-de-videojuegos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ORTS. Estrategia en tiempo real OpenSource</title>
		<link>http://razonartificial.com/2010/08/orts-estrategia-en-tiempo-real-opensource/</link>
		<comments>http://razonartificial.com/2010/08/orts-estrategia-en-tiempo-real-opensource/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 21:31:40 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[RTS]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=676</guid>
		<description><![CDATA[Os traigo un proyecto que tiene ya unos años, pero que me ha parecido muy interesante y perfecto para los interesado den la inteligencia artificial en los videojuegos. Se trata de Open Real Time Strategy que actualmente desarrolla un equipo de investigadores del grupo de Games Research del Departamento de Tecnologías de la Información de la Universidad [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://razonartificial.com/wp-content/uploads/2010/08/shot.26.08.2005-150x150.jpg"><img class="alignright size-full wp-image-677 imageborder" title="shot.26.08.2005-150x150" src="http://razonartificial.com/wp-content/uploads/2010/08/shot.26.08.2005-150x150.jpg" alt="" width="150" height="150" /></a>Os traigo un proyecto que tiene ya unos años, pero que me ha parecido muy interesante y perfecto para los interesado den la inteligencia artificial en los videojuegos. Se trata de <a href="http://www.cs.ualberta.ca/~mburo/orts/">Open Real Time Strategy</a> que actualmente desarrolla un equipo de investigadores del grupo de <a href="http://www.cs.ualberta.ca/~games/">Games Research </a>del Departamento de Tecnologías de la Información de la Universidad de Alberta.</p>
<p>Se trata de un Engine de inteligencia artificial que puede ser aplicado tanto en proyectos simples como un juego de mesa o en algo más complejo como juegos RTS e IA avanzada de shooters y RPG<strong>. </strong><strong><span style="font-weight: normal;"><a href="http://www.easports.ea.com/">Electronic Arts</a> y</span> <span style="font-weight: normal;"><a href="http://www.bioware.com/">BioWare</a>, han sido algunos de sus usuarios para juegos como FIFA o Baldur´s Gate. Uno de los integrantes Michael Buro, creador de ORTS, es el constructor de un programa de Othello que venció al campeón mundial del juego por 6 a 0.</span></strong></p>
<p><strong><span style="font-weight: normal;">El proyecto ORTS empieza en el año 2003 con la finalidad de crear un sistema cliente-servidor para el desarrollo de técnicas de Inteligencia Artificial en juegos interactivos de estrategia en tiempo real.</span></strong></p>
<p><strong><span style="font-weight: normal;">Hay mucha <a href="http://www.cs.ualberta.ca/~mburo/orts/#Documentation">documentación </a>al respecto que podemos encontrar en la red. Además se ha documentado de forma exhaustiva la estructura del <a href="http://www.cs.ualberta.ca/~mburo/orts/doxygen/html/classes.html">código </a>por lo que no es muy difícil empezar a probar algunas cosas.</span></strong></p>
<p><strong><span style="font-weight: normal;">Hoy todos los interesados en la IA que no conocierais el proyecto acabais de conseguir un juguete muy pero que muy elaborado y tan divertivo o más que cualquier otro que nos pueda caer en navidad.</span></strong></p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/la-inteligencia-artificial-de-l4d/" title="La Inteligencia Artificial de L4D">La Inteligencia Artificial de L4D</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/" title="Arboles e inteligencia artificial II">Arboles e inteligencia artificial II</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/" title="Arboles e inteligencia Artificial">Arboles e inteligencia Artificial</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/qRHXLO9-kGyFYLd_l4g_R0ZCHFo/0/da"><img src="http://feedads.g.doubleclick.net/~a/qRHXLO9-kGyFYLd_l4g_R0ZCHFo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/qRHXLO9-kGyFYLd_l4g_R0ZCHFo/1/da"><img src="http://feedads.g.doubleclick.net/~a/qRHXLO9-kGyFYLd_l4g_R0ZCHFo/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/UdUK7JaJCqg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/orts-estrategia-en-tiempo-real-opensource/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Agentes inteligentes</title>
		<link>http://razonartificial.com/2010/08/agentes-inteligentes/</link>
		<comments>http://razonartificial.com/2010/08/agentes-inteligentes/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 12:12:18 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[Agentes]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=664</guid>
		<description><![CDATA[Uno de los conceptos ampliamente utilizados en la inteligencia artificial es el concepto de Agente. Un agente como descripción general es un elemento lógico que definimos con un propósito concreto y que toma acción en un momento determinado de la ejecución con la finalidad de acercarnos a la consecución de nuestros objetivos. 1. Estructura del [...]]]></description>
			<content:encoded><![CDATA[<p>Uno de los conceptos ampliamente utilizados en la inteligencia artificial es el concepto de Agente. Un agente como descripción general es un elemento lógico que definimos con un propósito concreto y que toma acción en un momento determinado de la ejecución con la finalidad de acercarnos a la consecución de nuestros objetivos.</p>
<h2>1. Estructura del agente</h2>
<p>Un agente tiene generalmente una estructura en la que se identifican 4 elementos: capacidad de percepción, capacidad de acción, objetivos y entorno.</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-665 imageborder" title="smith" src="http://razonartificial.com/wp-content/uploads/2010/08/smith.jpg" alt="" width="302" height="218" /></p>
<h3>1.1 La capacidad de percepción</h3>
<p><a href="http:"></a>viene definida por los elementos capaces de reconocer de los que dispone el agente. Pueden ser sistemas sencillos en los que la percepción puede ser la detección o no de intrusos en su área de acción (definida fácilmente con un booleano) o bien mecanismos más complejos como una matriz de NxM que refleje la visión del agente en una orientación y momento concreto del tiempo y que requerirá un proceso más intenso e incluso una abstracción para agilizar cálculos.</p>
<h3>1.2 La capacidad de acción</h3>
<p><a href="http:"></a>Vendría definida por el conjunto de los movimientos, cálculos o respuestas en general que puede llevar a cabo el agente. Pueden ser tan sencillos como (giro izquierda/giro derecha/avanzar/retroceder) o más complejos como (evadir/emboscar/atacar/confundir).</p>
<h3>1.3 Los objetivos</h3>
<p><a href="http:"></a>Son la esencia del agente. El comportamiento del mismo irá orientado a la consecución de los mismos.</p>
<h3>1.4 El entorno</h3>
<p><a href="http:"></a>Es una característica externa al agente pero que condiciona su comportamiento. Puede ser un mundo tridimensional o una abstracción del mismo reducida a eventos. En otros casos puede ser una matriz la que modele el entorno o incluso un grafo que represente una topología concreta.</p>
<p><img class="aligncenter size-full wp-image-666" title="1.-agente" src="http://razonartificial.com/wp-content/uploads/2010/08/1.-agente.png" alt="" width="347" height="348" /></p>
<h2>2 Tipos de agentes</h2>
<p>Existe una primera clasificación de los agentes en función de diferentes aspectos como su grado de percepción del entorno o de su capacidad de proceso lógico.</p>
<p><img class="aligncenter size-full wp-image-667 imageborder" title="matrix_agentes" src="http://razonartificial.com/wp-content/uploads/2010/08/matrix_agentes.jpg" alt="" width="444" height="278" />El primero de ellos se basa en reglas sencillas y utiliza aserciones lógicas para llevar a cabo el proceso lógico que decide que acción tomar a cabo. No se tiene en cuenta el entorno donde se desenvuelve más que en la creación de las reglas.</p>
<p><img class="aligncenter size-full wp-image-668" title="2.-agentes" src="http://razonartificial.com/wp-content/uploads/2010/08/2.-agentes.png" alt="" width="590" height="339" /></p>
<p>Son rápidos y muy apropiados si el mundo es fácilmente modelable y las acciones generan el resultado apropiado de forma determinista y predecible.</p>
<h3>2.2 Agentes bien informados de todo lo que pasa</h3>
<p>En este aspecto se requiere un modelo más preciso del entorno donde las acciones que llevamos a cabo produzcan un resultado concreto y podamos observar la evolución del mundo.</p>
<p><img class="aligncenter size-full wp-image-669" title="3.-agentes-bien-informados" src="http://razonartificial.com/wp-content/uploads/2010/08/3.-agentes-bien-informados.png" alt="" width="578" height="340" /></p>
<h3><span style="color: #000000;">2.3 Agentes basados en metas</span></h3>
<p>Este tipo de agentes son más complejos puesto que requieren estructuras más complejas para garantizar comportamientos donde puede ser necesario el uso de técnicas de planificación o de búsqueda complejas que lleven al propio agente a la consecución de sus objetivos.</p>
<p><img class="aligncenter size-full wp-image-670" title="4.-agentes-por-metas" src="http://razonartificial.com/wp-content/uploads/2010/08/4.-agentes-por-metas.png" alt="" width="591" height="333" /></p>
<p>Se modificará el comportamiento en base a la retroalimentación recibida de aplicar las acciones concretas variando así su planificación o sus parámetros de búsqueda.</p>
<h3>2.4 Agentes basados en utilidad</h3>
<p>Estos se utilizan cuando no solo es necesario llegar a unos determinados objetivos de forma concreta sino que es necesario llegar de una forma eficiente.</p>
<p>Para ello se utiliza una función de utilidad acotada entre 0 y 1 que determina el grado de acercamiento a la meta que producirá el abanico de acciones disponibles. Distribuyendo dicho contenido en un acercamiento nulo (funcion de utilidad igual a cero) y una consecución de la meta (valor igual a uno).</p>
<p>De la correcta definición de la función de utilidad depende el grado de desempeño del agente.</p>
<h2>3. Arquitectura de un agente</h2>
<p>Existen diferentes arquitecturas actualmente.</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-671 imageborder" title="1999_the_matrix_vfx_005" src="http://razonartificial.com/wp-content/uploads/2010/08/1999_the_matrix_vfx_005.jpg" alt="" width="500" height="380" /></p>
<h3>3.1 Basadas en la Lógica.</h3>
<p>Conocidos también como agentes deliberativos, toman decisiones basadas en funciones lógicas que caracterizan el comportamiento. Un ejemplo sería: SI sensor_choque == ACTIVADO ENTONCES dirección = atrás.</p>
<h3>3.2 Agentes reactivos</h3>
<p>Este tipo de agentes actúa en función de los estímulos externos sin tener en cuenta el tiempo pasado del entorno ni el futuro del mismo. Responden de forma directa proporcionando un tiempo de respuesta y de proceso muy alto.</p>
<h3>3.3 Arquitectura creencia-deseo-intención.</h3>
<p>La toma de decisiones pasa por la interacción y el proceso de los elementos almacenados en las estructuras de creencias, deseos e intenciones. Se basan en deliberar primero que hay que hacer en base a los deseos utilizando las creencias y seleccionando posteriormente las acciones a realizar del grupo de intenciones.</p>
<h3>3.4 Arquitecturas híbridas.</h3>
<p>Se tienen en cuenta varias capas que utilizan conceptos del resto de arquitecturas. Suelen ser muy eficaces para el entorno concreto en el que se desarrollan pero poco generalizables a problemas que no sean muy similares.</p>
<p>La elección de una o de otra será en base a nuestro entorno por lo que no hay una mejor o peor solución sin la aplicación al problema en concreto.</p>
<h2>4. Los tipos de Entornos o Ambientes</h2>
<p>A la hora de construir un agente inteligente se tendrá muy en cuenta el entorno para el que se crea. Podemos encontrar varios tipos de entorno.</p>
<h3>4.1 Accesibles/No accesibles.</h3>
<p>Si a través de los sensores el agente tiene acceso al estado completo del entorno, este es accesible.</p>
<h3>4.2 Deterministas/No deterministas.</h3>
<p>Si es posible conocer a partir del estado actual y la decisión tomada del agente, el estado futuro del propio entorno y del mismo agente.</p>
<h3>4.3 Episódicos/No Episódicos.</h3>
<p>Es posible dividir el estado del agente en episodios con características propias.</p>
<h3>4.4 Estáticos/Dinámicos.</h3>
<p>El ambiente puede cambiar mientras el agente toma una decisión.</p>
<h3>4.5 Discretos/Continuos.</h3>
<p>Cuando es posible concretar todos los estados del entorno, este es discreto. Cuando no es posible debido a la cantidad y al tipo de variables que intervienen, este será continuo.</p>
<p>Los entornos por lo tanto condicionas en gran medida al agente que queremso construir. De la experiencia dependerá que creemos agentes más precisos y adaptados al entorno y que desempeñen por tanto su trabajo con un mayor grado de precisión y eficiencia.</p>
<p><strong>Nota:</strong> He dejado las imágenes de Matrix del <a href="http://www.starcostudios.com/blog/2010/01/agentes-inteligentes-precursores-del-agente-smith-y-compania/">autor original</a> porque soy gran fan de la película y me parece una genial manera de ilustrar el artículo con ciencia-ficción.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/" title="Arboles e inteligencia Artificial">Arboles e inteligencia Artificial</a></li><li><a href="http://razonartificial.com/2010/08/orts-estrategia-en-tiempo-real-opensource/" title="ORTS. Estrategia en tiempo real OpenSource">ORTS. Estrategia en tiempo real OpenSource</a></li><li><a href="http://razonartificial.com/2010/08/la-inteligencia-artificial-de-l4d/" title="La Inteligencia Artificial de L4D">La Inteligencia Artificial de L4D</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/" title="Arboles e inteligencia artificial II">Arboles e inteligencia artificial II</a></li><li><a href="http://razonartificial.com/2010/08/gamedevlesson-crear-videojuegos/" title="GameDevLesson &#8211; Crear videojuegos">GameDevLesson &#8211; Crear videojuegos</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/sbqXju-Ivf6fUlFDywoWT4Jkw_0/0/da"><img src="http://feedads.g.doubleclick.net/~a/sbqXju-Ivf6fUlFDywoWT4Jkw_0/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/sbqXju-Ivf6fUlFDywoWT4Jkw_0/1/da"><img src="http://feedads.g.doubleclick.net/~a/sbqXju-Ivf6fUlFDywoWT4Jkw_0/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/ug17-wjOC4A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/agentes-inteligentes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Algoritmo Minimax, un jugador incansable</title>
		<link>http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/</link>
		<comments>http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 11:43:22 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Minimax]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Teoría]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=657</guid>
		<description><![CDATA[En teoría de juegos, Minimax es un método de decisión para minimizar la pérdida máxima esperada en juegos con adversario y con información perfecta. Este cálculo se hace de forma recursiva. El funcionamiento de Minimax puede resumirse como elegir el mejor movimiento para ti mismo suponiendo que tu contrincante escogerá el peor para ti. La [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-658" title="minimax300" src="http://razonartificial.com/wp-content/uploads/2010/08/minimax300.png" alt="" width="300" height="175" /></p>
<p>En teoría de juegos, Minimax es un método de decisión para minimizar la pérdida máxima esperada en juegos con adversario y con información perfecta. Este cálculo se hace de forma recursiva.</p>
<p>El funcionamiento de Minimax puede resumirse como elegir el mejor movimiento para ti mismo suponiendo que tu contrincante escogerá el peor para ti.</p>
<p>La receta del algoritmo Minimax:</p>
<p><strong>1.</strong> Generación del árbol de juego. Se generarán todos los nodos hasta llegar a un estado terminal o determinando una profundidad concreta.</p>
<p>Vamos aplicando el algoritmo por un número fijo de iteraciones hasta alcanzar una determinada profundidad. En estas aplicaciones la profundidad suele ser el número de movimientos o los incluso el resultado de aplicar diversos pasos de planificación en un juego de estrategia.</p>
<p><strong>2.</strong> Cálculo de los valores de la función de utilidad para cada nodo terminal.</p>
<p>Para cada resultado final, cómo de beneficioso me resulta si estamos en MAX o cuanto me perjudicará si estamos en MIN.</p>
<p><strong>3.</strong> Calcular el valor de los nodos superiores a partir del valor de los inferiores. Alternativamente se elegirán los valores mínimos y máximos representando los movimientos del jugador y del oponente, de ahí el nombre de Minimax.</p>
<p><strong>4 .</strong> Elegir la jugada valorando los valores que han llegado al nivel superior.</p>
<p>El algoritmo explorará los nodos del árbol asignándoles un valor numérico mediante una función de utilidad, empezando por los nodos terminales y subiendo hacia la raíz. La función de utilidad como se ha comentado, definirá lo buena que es la posición para un jugador cuando la alcanza.</p>
<p>Versiones más avanzadas como el minimax con <strong>poda alfa beta</strong> hacen que se reduzca considerablemente el número de nodos a visitar por lo que el tiempo de cálculo se reduce ampliamente.</p>
<p>Y para terminar comentar un ejemplo cásico, el <strong>tres en raya</strong> (juego del gato, tatetí, triqui, tres en gallo, michi, la vieja o tic tac toe). Se trata de hacer una fila de tres para ganar y evitar que el oponente la haga antes que tu.</p>
<p>Al aplicar el algoritmo, se suceden una serie de estados que se resumen en la fotografía. Un estado -1 significa que MAX gana, 0 empate o -1 pierde.</p>
<p><img class="aligncenter size-full wp-image-659" title="minimaxt3" src="http://razonartificial.com/wp-content/uploads/2010/08/minimaxt3.jpg" alt="" width="410" height="338" /></p>
<p>Se distinguen los nodos terminales con jugada finalizada y los del trayecto. En este juego se puede llegar a la profundidad máxima puesto que se trata de 9 movimientos fijos, en otros como el ajedrez o las damas es muy necesario limitar la profundidad y aplicar medidas que aumenten la eficiencia.</p>
<p>El código se adjunta en python muy comentado. El bloque principal, y a partir de ahi todo lo demás en el documento adjunto, es el siguiente:</p>
<pre class="brush: python;">
b = Board()
turn = 1
while True:
	print “Turno %i.” % turn
	jugadorHumano(b, Jugador_X)
	if b.gameOver():
		break

	jugadorMaquina(b, Jugador_O)
	if b.gameOver():
	break
	turn += 1
</pre>
<p>Donde se crea una instancia del tablero, necesaria para detallar los elementos que intervienen en juego y e ir aplicando el algoritmo. Se pueden intercambiar jugadores o incluso hacer que jueguen dos máquinas o dos humanos simplemente modificando estas lineas de arriba.</p>
<p>En resumen.</p>
<ul>
<li>El minimax aporta una herramienta de proceso recursiva muy útil</li>
<li>Se pueden aplicar modificaciones al algoritmo para hacerlo más eficiente</li>
</ul>
<p>En el tres en raya:</p>
<ul>
<li>Gana el 1, pierde el -1 y empate 0</li>
<li>La profundida máxima es de 9, como el número de jugadas posible</li>
<li>La cota superior de nodos a visitar es en el peor caso (primer movimiento) 9 factoria -A&gt; 9!</li>
<li>No hay restricciones sobre la validez de un movimiento, simplemente que no se haya hecho antes, por lo que el coste del cálculo es bajo (no hay que aplicar reglas complejas).</li>
<li>Almacenar las soluciones intermedias no es excesivamente complejo</li>
<li>Generar los diferentes tableros con las soluciones intermedias a explorar no es costoso pero podría ser un problema en otros juegos y limitar la profundidad por memoria</li>
<li>La máquina nunca pierde, el juego está completado</li>
<li>Las partidas entre jugadores máquina siempre quedan en tablas.</li>
</ul>
<p>El tiempo que tarda un jugador pc en procesar la primera jugada es de 4047,181 ms en un ordenador medio, el que tarda cuando procesa la jugada que lo hace ganador en el último movimiento 0,568 ms y cuando procesa la que lo deja en tablas 0,337. La diferencia de tiempo de cálculo entre los primeros movimientos cuando quedan muchas opciones y el resto es 8000 veces mayor, por lo que el tema de la eficiencia habrá que tocarlo.</p>
<p>Puedes <a href="http://razonartificial.com/wp-content/uploads/2010/08/tresenraya.zip">descargar</a> una implementación en el clásico tres en raya.</p>
<p><a href="http://www.starcostudios.com/blog/2009/10/algoritmo-minimax-un-jugador-incansable/">Fuente</a></p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li><li><a href="http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/" title="Pathfinding A* en Python. Parte I">Pathfinding A* en Python. Parte I</a></li><li><a href="http://razonartificial.com/2010/01/el-salto-del-caballo-backtracking/" title="El salto del caballo, backtracking">El salto del caballo, backtracking</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/" title="Arboles e inteligencia artificial II">Arboles e inteligencia artificial II</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/" title="Arboles e inteligencia Artificial">Arboles e inteligencia Artificial</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/EYYFpmHStzWDHUB_ZDJpDKakiVY/0/da"><img src="http://feedads.g.doubleclick.net/~a/EYYFpmHStzWDHUB_ZDJpDKakiVY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/EYYFpmHStzWDHUB_ZDJpDKakiVY/1/da"><img src="http://feedads.g.doubleclick.net/~a/EYYFpmHStzWDHUB_ZDJpDKakiVY/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/Z5iZEkQS4HA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Curso Python V – Funciones del usuario</title>
		<link>http://razonartificial.com/2010/08/curso-python-v-funciones-del-usuario/</link>
		<comments>http://razonartificial.com/2010/08/curso-python-v-funciones-del-usuario/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 09:25:52 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=535</guid>
		<description><![CDATA[Añadir funciones Hasta ahora las funciones que hemos visto son funciones que ya están definidas, es decir, que alguien programó y nosotros usamos, pero es posible crear funciones propias que hagan lo que nosotros queramos, la definición de una función en la siguiente. def NOMBRE (LISTA PARÁMETROS): SENTENCIAS Donde def es la palabra reservada para [...]]]></description>
			<content:encoded><![CDATA[<h2>Añadir funciones</h2>
<p>Hasta ahora las funciones que hemos visto son funciones que ya están definidas, es decir, que alguien programó y nosotros usamos, pero es posible crear funciones propias que hagan lo que nosotros queramos, la definición de una función en la siguiente.</p>
<pre>
def NOMBRE (LISTA PARÁMETROS):
    SENTENCIAS
</pre>
<p>Donde <strong>def</strong> es la palabra reservada para declarar funciones, NOMBRE es el identificador de nuestra función y cumple las mismas reglas que las nombres de variables. LISTA PARÁMETROS son los datos que necesita nuestra función que puede ser ninguno, uno o varios. Por último SENTENCIAS es el código de nuestra función.</p>
<p>Veamos un ejemplo, supongamos que queremos una función que imprima una nueva linea, es decir, que haga un salto de línea. Podríamos hacer lo siguiente.</p>
<pre class="brush: python;">
def nueva_linea():
    print
</pre>
<p>La sentencia print si no se le pasa ningún parámetro simplemente deja una línea en blanco. Vamos a verlo.</p>
<pre class="brush: python;">
def nueva_linea():
	print

print &quot;Hola&quot;
nueva_linea()
print &quot;Mundo&quot;
</pre>
<p>Obtenemos lo siguiente.</p>
<pre>
Hola

Mundo
</pre>
<p>El programa anterior es equivalente a escribir</p>
<pre class="brush: python;">
print &quot;Hola&quot;
print
print &quot;Mundo&quot;
</pre>
<p>Ya que lo que hace es sustituir el nombre de nuestra función por su contenido, pero supongamos que queremos dejar 3 líneas en blanco. Podríamos hacerlo así</p>
<pre class="brush: python;">
print &quot;Hola&quot;
print
print
print
print &quot;Mundo&quot;
</pre>
<p>Pero si lo vas a usar muchas veces un salto de tres líneas, mejor definir una función que lo haga en una sola.</p>
<pre class="brush: python;">
def tres_lineas():
    print
    print
    print

print &quot;Hola&quot;
tres_lineas()
print &quot;Mundo&quot;
</pre>
<p>O incluso podríamos usar nuestra función nueva línea para hacerlo.</p>
<pre class="brush: python;">
def nueva_linea():
	print

def tres_lineas():
	nueva_linea()
	nueva_linea()
	nueva_linea()

print &quot;Hola&quot;
tres_lineas()
print &quot;Mundo&quot;
</pre>
<p>Vamos a hacer un recorrido de este programa, la primera sentencia imprime la palabra Hola. La segunda sentencia llama a la función <strong>tres_lineas()</strong> así que ahora se va a ejecutar su contenido, la primera línea de esta función es <strong>nueva_linea() </strong> así que se va a esta y ejecuta lo que hay dentro en este caso la sentencia <strong>print</strong>, cuando termina de ejecutar lo que hay dentro vuelve a donde lo dejó, es decir, sigue con la siguiente sentencia de <strong>tres_lineas()</strong> que vuelve a llamar a <strong>nueva_linea()</strong> y así hasta que termina, cuando no quedan mas sentencias en <strong>tres_lineas()</strong> vuelve a donde fue llamada, es decir, que sigue con la sentencia <strong>print </strong>&#8220;Mundo&#8221;.</p>
<p>Como ejercicio prueba a escribir una función que deje nueve líneas en blanco haciendo uso de <strong>tres_lineas()</strong>.</p>
<p class="advertencia">Las funciones deben declararse antes de usarse, es decir, antes de poder usar <strong>tres_lineas()</strong> debe haber sido declarada en el programa, si se declara después dará error.</p>
<h2>Parámetros</h2>
<p>Como vimos al principio a las funciones se les puede pasar parámetros, de hecho las funciones que hemos visto en anteriores entregas recibían parámetros como <strong>id()</strong>. Los parámetros son datos que recibe nuestra función con los que puede trabajar. Veamos un ejemplo.</p>
<pre class="brush: python;">
def saludar(nombre):
 print &quot;Hola &quot; + nombre

saludar(&quot;Adrian&quot;)
saludar(&quot;Pedro&quot;)
</pre>
<p>nos dará como salida:</p>
<pre>
Hola Adrian
Hola Pedro
</pre>
<p>Nuestra función recibe un parámetro llamado <strong>nombre</strong> que podemos usar dentro de nuestra función, en nuestro caso la unimos a la cadena &#8220;Hola &#8221; y la imprimimos en pantalla.</p>
<p>Podemos hacer que nuestras funciones tengan más de un parámetro, puede tener tantos como queremos solo debemos separarlos por comas.</p>
<pre class="brush: python;">
def imprime_suma(num1, num2):
    print num1 + num2

imprime_suma(5, 4)
imptime_suma(4.2, 7)
</pre>
<p>Como vemos nuestra función recibe dos parámetros e imprime el resultado de la suma.</p>
<h2>Retorno de valores</h2>
<p>Hasta ahora hemos visto funciones que hacen algo concreto como imprimir un mensaje en pantalla o la suma de dos números, pero ¿Y si queremos almacenar el resultado de la suma en una variable?</p>
<p>Para ello usaremos una nueva palabra reservada <strong>return</strong>. Se encarga de retornar un valor, veamos un ejemplo.</p>
<pre class="brush: python;">
def suma(num1, num2):
    suma = num1 + num2
    return suma
</pre>
<p>Esto hace que la función devuelva el resultado de la suma, se podría poner en una sola sentencia, ahorrándonos la variable suma.</p>
<pre class="brush: python;">
def suma(num1, num2):
    return num1 + num2
</pre>
<p>Ahora podríamos usarla de la siguiente manera.</p>
<pre class="brush: python;">
mi_suma = suma(num1, num2)
print mi_suma
</pre>
<p>La función devolvería el valor de la sentencia return y con el podemos hacer lo que queramos, en nuestro caso almacenarlo en la variable mi_suma.</p>
<p>Una función puede tener más de una sentencia return, pero debes saber que cuando se alcanza una sentencia return la función termina de ejecutarse y devuelve el control al programa. Lo veremos mejor cuando estudiemos los condicionales.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/curso-python-iv-%e2%80%93-funciones/" title="Curso Python IV – Funciones">Curso Python IV – Funciones</a></li><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/" title="Pygame X: Fuentes tipográficas">Pygame X: Fuentes tipográficas</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/MUzOWf6Lz_xDaxdsEke_ngCG4iU/0/da"><img src="http://feedads.g.doubleclick.net/~a/MUzOWf6Lz_xDaxdsEke_ngCG4iU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/MUzOWf6Lz_xDaxdsEke_ngCG4iU/1/da"><img src="http://feedads.g.doubleclick.net/~a/MUzOWf6Lz_xDaxdsEke_ngCG4iU/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/-UcNoRF6gaM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/curso-python-v-funciones-del-usuario/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gestionando Escenas con Pygame</title>
		<link>http://razonartificial.com/2010/08/gestionando-escenas-con-pygame/</link>
		<comments>http://razonartificial.com/2010/08/gestionando-escenas-con-pygame/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 08:44:27 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=645</guid>
		<description><![CDATA[Un videojuego generalmente no se compone de una sola pantalla, sino que hay varias como pueden ser un menú introductorio. el mapa de nuestro juego, un menú de objetos, una pantalla de puntuaciones, etc. Estas diferentes pantallas reciben el nombre de escenas cada una de ella representa algo especifico de nuestro juego. Cambiar la escena [...]]]></description>
			<content:encoded><![CDATA[<p>Un videojuego generalmente no se compone de una sola pantalla, sino que hay varias como pueden ser un menú introductorio. el mapa de nuestro juego, un menú de objetos, una pantalla de puntuaciones, etc. Estas diferentes pantallas reciben el nombre de <strong>escenas</strong> cada una de ella representa algo especifico de nuestro juego.</p>
<p>Cambiar la escena del juego puede ser algo complicado, recuerda que siempre se debe mantener el bucle de ejecución de los juegos.</p>
<p><img class="aligncenter size-full wp-image-646" title="bucle_simple" src="http://razonartificial.com/wp-content/uploads/2010/08/bucle_simple.png" alt="" width="262" height="382" />Se suele utilizar un bucle infinito que vaya manteniendo esto, pero surge el problema de que en una escena determinada de nuestro juego los eventos, la lógica y las cosas a dibujar serán unas y en otras escenas puede ser otra. Por ejemplo, en un menú habrá que gestionar como eventos si se  acciona algún botón y habrá que dibujar este menú, en otra escena del juego puedes necesitar dibujar otra cosa.</p>
<p><a href="http://razonartificial.com/wp-content/uploads/2010/08/escenas.jpg"><img class="aligncenter size-full wp-image-647" title="escenas" src="http://razonartificial.com/wp-content/uploads/2010/08/escenas.jpg" alt="" width="600" height="200" /></a>En la imagen superior podemos ver dos escenas diferentes del juego Age of Empires III a la izquierda el menú principal y a la derecha un mapa del juego.</p>
<h2>El objeto director y la escena maestra</h2>
<p>Nuestras escenas a pesar de lo diferente que puedan ser entre ellas siempre van a tener las características del bucle de arriba. Es decir, deben de inicializarse, actualizarse, gestionar eventos y dibujarse. Por tanto podríamos definir una clase maestra abstracta que se encargara de hacer esto con la escena que tengamos activa independiente de cual sea.</p>
<h3>EL objeto director</h3>
<p>En lugar de gestionar en nuestro archivo <strong>main</strong> el bucle del juego lo que vamos a hacer es crear un <strong>clase director</strong> que será la encargada de gestionar nuestro bucle de juego, este bucle recibirá una escena cualquiera y se encargará de ejecutar sus métodos de actualizar, eventos y dibujar.</p>
<pre class="brush: python;">
# -*- encoding: utf-8 -*-

# Módulos
import pygame
import sys

class Director:
    &quot;&quot;&quot;Representa el objeto principal del juego.

    El objeto Director mantiene en funcionamiento el juego, se
    encarga de actualizar, dibuja y propagar eventos.

    Tiene que utilizar este objeto en conjunto con objetos
    derivados de Scene.&quot;&quot;&quot;

    def __init__(self):
        self.screen = pygame.display.set_mode((640, 480))
        pygame.display.set_caption(&quot;Nombre Proyecto&quot;)
        self.scene = None
        self.quit_flag = False
        self.clock = pygame.time.Clock()

    def loop(self):
        &quot;Pone en funcionamiento el juego.&quot;

        while not self.quit_flag:
            time = self.clock.tick(60)

            # Eventos de Salida
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.quit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
		        self.quit()

            # detecta eventos
            self.scene.on_event()

            # actualiza la escena
            self.scene.on_update()

            # dibuja la pantalla
            self.scene.on_draw(self.screen)
            pygame.display.flip()

    def change_scene(self, scene):
        &quot;Altera la escena actual.&quot;
        self.scene = scene

    def quit(self):
        self.quit_flag = True
</pre>
<p>Este objeto debe crearse dentro de nuestra función principal <strong>main</strong> en sustitución del bucle del juego. Vamos a explicarlo:</p>
<p>En el constructor creamos la ventana de Pyagame, le damos título e iniciamos el reloj. También definimos varias variables, por un lado tenemos  <strong>self.scene = None</strong> que será la escena que queremos que represente, de momento ninguna.  <strong>self.quit_flag = False</strong> Es una &#8220;bandera&#8221; que nos indica si queremos salir.</p>
<p>Luego viene el método loop que es el que contiene el bucle de nuestro juego, tiene como condición para salir del bucle que la variable  <strong>self.quit_flag</strong> sea verdadera, cuando lo sea saldrá del bucle. para hacer esta variable verdadera solo hay que llamar desde cualquier lado del bucle al <strong>método quit</strong> que como vemos cambia la variable a verdadera.</p>
<p>Ya dentro del bucle lo primero es establecer el framerate, en este caso lo tenemos a 60. Luego ya empezamos con el bucle, comprobamos si se ha producido un evento de salida. En nuestro caso aparte de eso comprobamos también como evento de salida si se ha pulsado la tecla escape (esto a gusto del consumidor y del juego). Si se ha producido un evento de salida como vemos llamamos a <strong>self.quit()</strong>.</p>
<p>Luego llama a <strong>self.scene.on_event()</strong>, pero, ¿<strong>self.scene</strong> no valía <strong>None</strong>? Exacto así que hacemos un inciso aquí en la clase director para explicar la clase scene.</p>
<h3>La clase Scene</h3>
<p>La clase <strong>Scene</strong> representa a una clase abstracta del juego. Es una clase padre que debe ser heredada por todas las escenas de nuestro juego, veamos.</p>
<pre class="brush: python;">
class Scene:
    &quot;&quot;&quot;Representa un escena abstracta del videojuego.

    Una escena es una parte visible del juego, como una pantalla
    de presentación o menú de opciones. Tiene que crear un objeto
    derivado de esta clase para crear una escena utilizable.&quot;&quot;&quot;

    def __init__(self, director):
        self.director = director

    def on_update(self):
        &quot;Actualización lógica que se llama automáticamente desde el director.&quot;
        raise NotImplemented(&quot;Tiene que implementar el método on_update.&quot;)

    def on_event(self, event):
        &quot;Se llama cuando llega un evento especifico al bucle.&quot;
        raise NotImplemented(&quot;Tiene que implementar el método on_event.&quot;)

    def on_draw(self, screen):
        &quot;Se llama cuando se quiere dibujar la pantalla.&quot;
        raise NotImplemented(&quot;Tiene que implementar el método on_draw.&quot;)
</pre>
<p>Como vemos es muy sencilla, el constructor solo recibe como parámetro el objeto director. Luego implementa tres métodos. <strong>on_update</strong>, <strong>on_event</strong> y <strong>on_draw</strong>. Cada uno se encarga de hacer las tareas de actualizar, gestionar eventos y dibujar respectivamente. Pero como vemos en el cuerpo de cada uno de los métodos lo que hay es un error de que no de ha implementado ese método, esto es porque Scene es una escena padre que debe ser llamada por las escenas de nuestro juego e implementar estos tres métodos para que hagan las acciones específicas de nuestra escena. Vamos allá.</p>
<h3>Creando una escena</h3>
<p>Vamos a crear una sencilla escena que no haga nada, simplemente que exista:</p>
<pre class="brush: python;">
class SceneHome(scene.Scene):
    &quot;&quot;&quot;Escena inicial del juego, esta es la primera que se carga cuando inicia&quot;&quot;&quot;

    def __init__(self, director):
        scene.Scene.__init__(self, director)

    def on_update(self):
        pass

    def on_event(self):
        pass

    def on_draw(self, screen):
        pass
</pre>
<p>Como vemos nuestra escena hereda de <strong>Scene</strong> (puedes ver que en el código pone scene.Scene, esto es porque yo la tengo en un archivo aparte llamada scene), como vemos en el __init__ lo primero que hacemos es llamar al __init__ de Scene y pasarle el objeto director. Luego implementamos y sustituimos los métodos de la clase padre con los de nuestras escena. En esta caso los tres con la sentencia pass, que no hace nada.</p>
<p>Veamos como inicalizar la escena, volviendo al archivo <strong>main</strong>.</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import pygame
import director
import scene_home

def main():
    dir = director.Director()
    scene = scene_home.SceneHome(dir)
    dir.change_scene(scene)
    dir.loop()

if __name__ == '__main__':
    pygame.init()
    main()
</pre>
<p>Este es el archivo <strong>main</strong> de nuestro proyecto, como vemos importa tres módulos, <strong>pygame</strong> para que pueda ser inicializado, el módulo <strong>director</strong> que contiene la clase director y el modulo <strong>scene_home</strong> que contiene la escena con la que queremos iniciar nuestro juego.</p>
<p>Luego ya en la función <strong>main</strong> creamos el objeto director con <strong>dir = director.Director()</strong>. Esto llama al constructor del objeto director que como vimos arriba crea la ventana, le pone titulo, crea el reloj y define la variable <strong>self.scene = None</strong>.</p>
<p>A continuación creamos un objeto scene con nuestra escena:  <strong>scene = scene_home.SceneHome(dir)</strong>. y llamamos al método <strong>change_scene</strong> de la clase director pasándole como parámetro el objeto scene que acabamos de crear, veamos que hace este método.</p>
<pre class="brush: python;">
def change_scene(self, scene):
    &quot;Altera la escena actual.&quot;
    self.scene = scene
</pre>
<p>Pues como era de esperar establece que la variable <strong>self.scene</strong> del objeto director sea el objeto <strong>scene</strong> que acabamos de crear. a continuación llama a <strong>dir.loop()</strong> que es el bucle de nuestro juego que dejamos a medias. Volvamos a él.</p>
<h3>Continuando con el objeto director</h3>
<p>Nos quedaba por explicar lo siguiente del objeto director.</p>
<pre class="brush: python;">
# detecta eventos
self.scene.on_event()

# actualiza la escena
self.scene.on_update()

# dibuja la pantalla
self.scene.on_draw(self.screen)
pygame.display.flip()
</pre>
<p>Pues lo que hace es llamar a los tres métodos de nuestra escena cargada que se encarga de gestionar las actualizaciones, los eventos y el dibujado. Por último se llama a <strong>pygame.display.flip()<br />
</strong> para dibujar la pantalla.</p>
<p>Como vemos ya tenemos la manera de cargar una escena cualquiera desde nuestro objeto director con sus propios métodos de actualización, eventos y dibujado. Ahora para cambiar de scene solo hace falta llamar desde cualquiera parte dentro de nuestra escena activa a <strong>director.change_scene(scene)</strong> donde scene es la nueva scena que queremos que pase a tener el control ya que esto modificará a self.scene que es la que implementa los métodos.</p>
<p>Puede resultar lioso así de primera, pero a continuación dejo el código de este ejemplo. Si no lo entiendes a la primera el artículo mira el código y trata de probar cosas que puede ser lioso si solo se lee de pasada.</p>
<ul>
<li><a href='http://razonartificial.com/wp-content/uploads/2010/08/base.zip'>Descargar ejemplo</a></li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li><li><a href="http://razonartificial.com/2010/08/pyia-competicion-de-inteligencia-artificial-en-python/" title="PyIA &#8211; Competición de Inteligencia Artificial en Python">PyIA &#8211; Competición de Inteligencia Artificial en Python</a></li><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/07/pygame-el-juego-de-la-serpiente/" title="[Pygame] El juego de la serpiente">[Pygame] El juego de la serpiente</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/qiAnM_wWhGsDAtHRKbc1oy0rEQo/0/da"><img src="http://feedads.g.doubleclick.net/~a/qiAnM_wWhGsDAtHRKbc1oy0rEQo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/qiAnM_wWhGsDAtHRKbc1oy0rEQo/1/da"><img src="http://feedads.g.doubleclick.net/~a/qiAnM_wWhGsDAtHRKbc1oy0rEQo/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/ptojt2YzVQw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/gestionando-escenas-con-pygame/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>La Inteligencia Artificial de L4D</title>
		<link>http://razonartificial.com/2010/08/la-inteligencia-artificial-de-l4d/</link>
		<comments>http://razonartificial.com/2010/08/la-inteligencia-artificial-de-l4d/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 00:35:50 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Valve]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=630</guid>
		<description><![CDATA[Los grandes juegos de las grandes compañías deben de ser una fuente de inspiración para el desarrollo amateur. Si esta compañía se llama Valve y además publica documentos sobre como desarrolla ciertas cosas, pues es un material imperdible. Os traigo un documento sobre como trabaja la inteligencia artificial del juego Left 4 Dead. Habla de [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-631 imageborder" title="ial4d" src="http://razonartificial.com/wp-content/uploads/2010/08/ial4d.png" alt="" width="200" height="200" />Los grandes juegos de las grandes compañías deben de ser una fuente de inspiración para el desarrollo amateur. Si esta compañía se llama Valve y además publica documentos sobre como desarrolla ciertas cosas, pues es un material imperdible.</p>
<p>Os traigo un documento sobre como trabaja la inteligencia artificial del juego <strong>Left 4 Dead</strong>. Habla de el modo de operar a grandes rasgos, a mi en especial me ha entusiasmado la parte donde explican como utilizan el pathfinding para encontrar caminos cortos y realistas en fin un documento que todo desarrollador de videojuegos no se puede perder.</p>
<ul>
<li><a href="http://www.valvesoftware.com/publications/2009/ai_systems_of_l4d_mike_booth.pdf">Descargar PDF</a></li>
</ul>
<p>Podéis encontrar algunas publicaciones más de Valve en: <a href="http://www.valvesoftware.com/publications.html">http://www.valvesoftware.com/publications.html</a></p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/orts-estrategia-en-tiempo-real-opensource/" title="ORTS. Estrategia en tiempo real OpenSource">ORTS. Estrategia en tiempo real OpenSource</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/" title="Arboles e inteligencia artificial II">Arboles e inteligencia artificial II</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/" title="Arboles e inteligencia Artificial">Arboles e inteligencia Artificial</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/ZTQJFB89AcMp4Xf6uSFCKLhSams/0/da"><img src="http://feedads.g.doubleclick.net/~a/ZTQJFB89AcMp4Xf6uSFCKLhSams/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ZTQJFB89AcMp4Xf6uSFCKLhSams/1/da"><img src="http://feedads.g.doubleclick.net/~a/ZTQJFB89AcMp4Xf6uSFCKLhSams/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/2_9ssl3XTC4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/la-inteligencia-artificial-de-l4d/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Curso Python IV – Funciones</title>
		<link>http://razonartificial.com/2010/08/curso-python-iv-%e2%80%93-funciones/</link>
		<comments>http://razonartificial.com/2010/08/curso-python-iv-%e2%80%93-funciones/#comments</comments>
		<pubDate>Fri, 20 Aug 2010 21:43:29 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Curso]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=526</guid>
		<description><![CDATA[Llamada a funciones Ya hemos visto en anteriores entregas la llamada a una función. &#62;&#62;&#62; type("32") &#60; type 'string'&#62; El nombre de la función es type y lo que está entre paréntesis se llama parámetro, las funciones pueden recibir un parámetro, varios parámetros o ningún parámetro. Nuestra función type recibe 1 parámetro, en este caso [...]]]></description>
			<content:encoded><![CDATA[<h2>Llamada a funciones</h2>
<p>Ya hemos visto en anteriores entregas la llamada a una función.</p>
<pre>&gt;&gt;&gt; type("32")
&lt; type 'string'&gt;</pre>
<p>El nombre de la función es <strong>type</strong> y lo que está entre paréntesis se llama parámetro, las funciones pueden recibir un parámetro, varios parámetros o ningún parámetro. Nuestra función <strong>type </strong>recibe 1 parámetro, en este caso puede ser cualquier valor. Y cuando es llamada devuelve el tipo de dato que es el que le hemos pasado como parámetro. Esa es su función, valga la redundancia.</p>
<p>Si pusiéramos la función <strong>type</strong> dentro de un script al ejecutarlo nos dariamos cuenta de que no pasa nada, esto es así porque no le hemos dicho que hacer con ese valor, podríamos imprimirlo en pantalla:<span id="more-526"></span></p>
<pre class="brush: python;">
print type(&quot;Hola&quot;)
</pre>
<p>O almacenarlo en una variable</p>
<pre class="brush: python;">
tipo_dato = type(&quot;Hola&quot;)
print tipo_dato
</pre>
<p>Otra ejemplo de función es la función <strong>id()</strong> esta función devuelve un identificador único para cada variable o número en la memoria del ordenador.</p>
<pre>&gt;&gt;&gt; id(10)
31246556
&gt;&gt;&gt; a = 10
&gt;&gt;&gt; id(a)
31246556
&gt;&gt;&gt; id(4)
31246628</pre>
<p>Como vemos tanto el valor 10 como la variable a tienen el mismo identificador, esto es así porque al tener el mismo valor python ahorra memoria usando la misma dirección de memoria ya que contienen lo mismo.</p>
<h2>Conversión de tipos</h2>
<p>Python posee una funciones muy útiles para la convertir variables de un tipo a otro, siempre que la conversión sea posible.</p>
<p>Tenemos la función <strong>int()</strong> que convierte un valor pasado en un entero, si se puede.</p>
<pre>&gt;&gt;&gt; int("25")
25
&gt;&gt;&gt; int(25.423)
25
&gt;&gt;&gt; int(6.9999)
6
&gt;&gt;&gt; int("Hola")
Traceback (most recent call last):
  File "", line 1, in
ValueError: invalid literal for int() with base 10: 'Hola'</pre>
<p>Como vemos podemos convertir la cadena &#8220;25&#8243; a tipo int o el número decimal 24.423, pero no podemos convertir la cadena &#8220;Hola&#8221; a un tipo entero.</p>
<p>Otra función es <strong>float()</strong> que como imaginaréis convierte a un número decimal.</p>
<pre>&gt;&gt;&gt; float(4)
4.0
&gt;&gt;&gt; float("5")
5.0
&gt;&gt;&gt; float("5.25")
5.25</pre>
<p class="advertencia">Para python 4 es diferente a 4.0, puede que representen el mismo valor, pero se representan de forma diferente dentro del ordenador.</p>
<p>Por último tenmos la función <strong>str()</strong> que convierte el valor pasado en una cadena.</p>
<pre>&gt;&gt;&gt; str(42)
'42'
&gt;&gt;&gt; str(4.215)
'4.215'</pre>
<h2>Coerción de tipos</h2>
<p>Si queremos saber la fracción de hora que ha pasado, podríamos usar algo como lo siguiente</p>
<pre class="brush: python;">
minutos = 45
fraccion = minutos / 60
print fraccion
</pre>
<p>Esto en teoría nos devolvería la fracción de hora transcurrida, es decir 0.75 (el 75% de la hora), sin embargo si lo ejecutamos veremos que el resultado es 0, esto ocurre porque estamos haciendo una división de enteros. La solución sería convertir los datos a tipo float.</p>
<pre class="brush: python;">
minutos = 45
fraccion = float(minutos) / 60.0
print fraccion
</pre>
<p>O directamente aprovecharnos de la coerción de tipos de python que hace que si uno de los valores de la opereción es de tipo float, convierte los demás automáticamente a ese tipo, por lo que podríamos hacer.</p>
<pre class="brush: python;">
minutos = 45
fraccion = minutos/60.0
print fraccion
</pre>
<h2>Funciones y matemáticas</h2>
<p>Si tienes una base matemática entender las funciones no te habrá supuesto mucho problema ya que actúan de forma similar a las funciones matemáticas. Por ejemplo si tenemos la siguiente función:</p>
<pre>F(x) = Sin(1/2)</pre>
<p>Sabemos que primero se evalúa la expresión 1/2 que da 0.5 y luego se halla el seno de 0.5 que sería 0.4794 aproximadamente. También podemos tener funciones dentro de funciones</p>
<pre>F(x) = Sin(log(25))</pre>
<p>Donde primero se calcularía el logaritmo de 25 y luego el seno del resultado.</p>
<p>En programación sucede igual si tu tienes una función dentro de una función, primero se evalúa la funciones interiores y luego las exteriores.</p>
<p>Por cierto, python dispone de un módulo para las funciones matemáticas más habituales llamado math. Los módulos en python es código ya escrito que contienen clases y funciones listas para ser usada, veamos un ejemplo</p>
<pre>&gt;&gt;&gt; import math
&gt;&gt;&gt; math.sin(5)
-0.95892427466313845
&gt;&gt;&gt; math.sin(45)
0.85090352453411844
&gt;&gt;&gt; math.cos(45)
0.52532198881772973
&gt;&gt;&gt; math.sqrt(25)
5.0
&gt;&gt;&gt; math.log(25)
3.2188758248682006</pre>
<p>como vemos a través de <strong>import math</strong> importamos el módulo y para usar lo que contiene ese modulo lo hacemos a través de módulo.funcion(), como por ejemplo <strong>math.sqrt(49)</strong> que nos devolvería la raiz cuadrada de 49.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/curso-python-v-funciones-del-usuario/" title="Curso Python V – Funciones del usuario">Curso Python V – Funciones del usuario</a></li><li><a href="http://razonartificial.com/2010/08/curso-python-iii-%e2%80%93-scripts-y-comentarios/" title="Curso Python III – Scripts y Comentarios">Curso Python III – Scripts y Comentarios</a></li><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/B970DxuZUGiCFuMCpJy370g0iw4/0/da"><img src="http://feedads.g.doubleclick.net/~a/B970DxuZUGiCFuMCpJy370g0iw4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/B970DxuZUGiCFuMCpJy370g0iw4/1/da"><img src="http://feedads.g.doubleclick.net/~a/B970DxuZUGiCFuMCpJy370g0iw4/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/Jd_sON7JQRU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/curso-python-iv-%e2%80%93-funciones/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Curso Python III – Scripts y Comentarios</title>
		<link>http://razonartificial.com/2010/08/curso-python-iii-%e2%80%93-scripts-y-comentarios/</link>
		<comments>http://razonartificial.com/2010/08/curso-python-iii-%e2%80%93-scripts-y-comentarios/#comments</comments>
		<pubDate>Fri, 20 Aug 2010 08:12:54 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Curso]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=522</guid>
		<description><![CDATA[Escribiendo Scripts El intérprete está muy bien para probar pequeños códigos o hacer alguna cosa rápida, pero como norma general querrá guardar sus programas para poder editarlos y ejecutarlos cuando quiera. Esto se hace a través de un script, un script de Python no son más que sentencias que se le pasan al intérprete una [...]]]></description>
			<content:encoded><![CDATA[<h2>Escribiendo Scripts</h2>
<p>El intérprete está muy bien para probar pequeños códigos o hacer alguna cosa rápida, pero como norma general querrá guardar sus programas para poder editarlos y ejecutarlos cuando quiera.</p>
<p>Esto se hace a través de un script, un script de Python no son más que sentencias que se le pasan al intérprete una detrás de otra, veamos un ejemplo de script.</p>
<pre class="brush: python;">
a = 5
b = 2
c = (a+b) * (a+b)
mensaje = &quot;Hola Mundo&quot;

print c
print mensaje
</pre>
<p>Esto se guarda en un fichero de texto plano con la extensión <strong>.py</strong> y ya tenemos nuestro Script ahora cuando lo ejecutemos el intérprete empezará a leer y ejecutar sentencia por sentencia, dándonos esta salida.<span id="more-522"></span></p>
<pre>49
Hola Mundo</pre>
<p>Como vemos ha hecho las operaciones con las variable y luego a ejecutado las dos sentencias print devolviendo los valores pasados.</p>
<p>A partir de ahora trabajaremos con Scripts y usaremos la consola para probar pequeñas cosas.</p>
<h2>Comentarios</h2>
<p>Conforme los programas van creciendo de tamaño y complicándose, se vuelven más complicados de leer. Los lenguajes formales son densos y con frecuencia es difícil observar un trozo de código y averiguar lo que hace, o por qué lo hace.</p>
<p>Por ello es una buena idea añadir notas a su programa que expliquen, en un lenguaje natural, qué hace el programa. Estas notas se llaman comentarios y se marcan con el símbolo <strong>#</strong>:</p>
<pre class="brush: python;">
# calcula el porcentaje de la hora que ha pasado ya
porcentaje = (minuto * 100) / 60
</pre>
<p>En este caso el comentario ocupa toda una línea, pero también se pueden poner al final de una sentencia:</p>
<pre class="brush: python;">
porcentaje = (minuto * 100) / 60 # ojo: división de enteros
</pre>
<p>Todo lo que va del # al final de la línea se ignora (no tiene efecto sobre el programa). El mensaje está destinado al programador, o a futuros programadores que podrían tener que usar el código. En este caso avisa al lector sobre el sorprendente comportamiento de la división de enteros.</p>
<p class="consejo">Usa comentarios a menudo, cuando tus programas sean de miles de líneas de código y lleves unas semanas sin mirarlo me lo agradecerás</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/curso-python-iv-%e2%80%93-funciones/" title="Curso Python IV – Funciones">Curso Python IV – Funciones</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-ii-tipos-y-variables/" title="Curso Python II &#8211; Tipos y variables">Curso Python II &#8211; Tipos y variables</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-i-interprete-y-scripts/" title="Curso Python I &#8211; Intérprete y scripts">Curso Python I &#8211; Intérprete y scripts</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-%e2%80%93-presentacion/" title="Curso Python – Presentación">Curso Python – Presentación</a></li><li><a href="http://razonartificial.com/2010/01/curso-python/" title="Curso Python">Curso Python</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/VibtGLOElzu_wvJgC0p3k6ETkU8/0/da"><img src="http://feedads.g.doubleclick.net/~a/VibtGLOElzu_wvJgC0p3k6ETkU8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/VibtGLOElzu_wvJgC0p3k6ETkU8/1/da"><img src="http://feedads.g.doubleclick.net/~a/VibtGLOElzu_wvJgC0p3k6ETkU8/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/R5HYsC0L0Qg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/curso-python-iii-%e2%80%93-scripts-y-comentarios/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tilemapping – Juegos basados en tiles</title>
		<link>http://razonartificial.com/2010/08/tilemapping-juegos-basados-en-tiles/</link>
		<comments>http://razonartificial.com/2010/08/tilemapping-juegos-basados-en-tiles/#comments</comments>
		<pubDate>Fri, 20 Aug 2010 02:03:12 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Teoría]]></category>
		<category><![CDATA[Tilemapping]]></category>
		<category><![CDATA[Tutoriales]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=484</guid>
		<description><![CDATA[Vamos a hablar sobre la teoría de los juegos basados en tiles y qué es necesario para desarrollarlos. ¿Qué es el tilemapping? Bueno, asi a lo simple el tilemapping es dividir el terreno (o mapa) de juego en casillas iguales, a las que se les llama“tiles”. Cada una de estas casillas puede tener un gráfico [...]]]></description>
			<content:encoded><![CDATA[<p>Vamos a hablar sobre la teoría de los juegos basados en tiles y qué es necesario para desarrollarlos.</p>
<h2>¿Qué es el tilemapping?</h2>
<p>Bueno, asi a lo simple el tilemapping es dividir el terreno (o mapa) de juego en casillas iguales, a las que se les llama<strong>“tiles”</strong>. Cada una de estas casillas puede tener un gráfico distinto, y juntando muchas casillas se consigue un mapa complejo de una manera sencilla.</p>
<p>Un ejemplo: Hundir la Flota</p>
<p>En este juego, el mapa es una cuadrícula de casillas. Cada casilla puede tener varios estados (agua, barco, barco tocado, barco hundido, etc&#8230;). Y cada uno de estos estados se representan en pantalla cambiando el color de la casilla, o usando una imagen distinta.</p>
<p>A la hora de dibujar la cuadrícula usando una librería de programación gráfica 2D como SDL lo que haremos será recorrer todo el mapa, y dibujar el gráfico (o tile) que corresponda dependiendo del estado, en la posición que sea.</p>
<p><img class="aligncenter size-full wp-image-307" title="map-representation" src="http://razonartificial.com/wp-content/uploads/2010/04/map-representation.png" alt="" width="481" height="306" /></p>
<p><span id="more-484"></span></p>
<h2>Representación</h2>
<p>Lo que nos permite este sistema es representar el mundo del juego de una forma muy simple. Lo único que tenemos que hacer es guardar una matriz de casillas. Y por cada casilla, el gráfico que le corresponda. (además de la información que el juego necesite, por supuesto).</p>
<p>De momento. Podemos suponer que sólo tenemos que guardar el gráfico, así que podemos definir el mapa así:</p>
<pre class="brush: cpp;">int mapa[ANCHO_MAPA][ALTO_MAPA];</pre>
<p>y si mapa[x][y] = 4, eso significa que en la posición (x, y) del mapa hay una casilla con el gráfico número 4 (guardamos simplemente un índice)</p>
<p>Claro, necesitaremos también los gráficos de cada casilla. En vez de crear una superficie para cada uno, como por regla general serán bastante pequeños, lo que hacemos es agrupar muchos en una única superficie. Y a eso es a lo que llamamos <strong>Tileset</strong>.</p>
<p>Un ejemplo con varios tipos de tiles:</p>
<p><img class="aligncenter size-full wp-image-306" title="mud-tile-example" src="http://razonartificial.com/wp-content/uploads/2010/04/mud-tile-example.png" alt="" width="463" height="320" /></p>
<p>Así que lo que haremos para dibujar el mapa es recorrer la matriz, y por cada casilla, ver que “tile” hay que dibujar, y hacer un blit desde el “tileset” que contenga todos los tiles a la superficie destino (la pantalla).</p>
<p>De momento vamos a suponer que al Tileset solo hace falta indicarle el índice del tile que hay que dibujar, y la posición en la pantalla donde debe aparecer, y él se encarga de hacer el blit.</p>
<pre class="brush: cpp;">for (y = 0; y &lt; ANCHO_MAPA; y++) {
   for (x=0; x &lt; ANCHO_MAPA; x++) {
      dibujar mapa[x][y] en (posX, posY)
   }
}</pre>
<p>De momento aquí vemos algo curioso: Aparecen dos sistemas de coordenadas distintos:</p>
<ul>
<li>(x, y) son las coordenadas de la casilla en la matriz de casillas (el mapa).</li>
<li>(posX, posY) son las coordenadas en pixels del punto de la pantalla donde dibujaremos la casilla.</li>
</ul>
<h2>Coordenadas</h2>
<p>Bueno, lo acabais de ver. Tenemos más de un sistema de coordenadas al convertir nuestra matriz de casillas en algo dibujado en pantalla. Lo que tenemos que ver es cuántos sistemas tenemos, y cómo pasar de uno a otro.</p>
<p>De momento, a (x, y) las vamos a llamar <strong>“Coordenadas lógicas”</strong> o “Coordenadas de mapa”.</p>
<p>Y a (posX, posY) las llamaremos “World Coordinates”, o en español, “Coordenadas del Mundo”, o<strong>“Coordenadas Absolutas”.</strong></p>
<p>Al proceso de pasar de las coordenadas lógicas a las coordenadas absolutas lo vamos a llamar <strong>“Plotting”</strong>, o más específicamente: “Tile Plotting”.</p>
<p>Al proceso de pasar de pasar de las coordenadas absolutas a las coordenadas lógicas lo vamos a llamar <strong>“Mouse Mapping”</strong> (lo del Mouse es porque se suele usar para detectar sobre qué casilla ha clickeado el jugador).</p>
<p><img class="aligncenter size-full wp-image-485" title="tutoSDL41" src="http://razonartificial.com/wp-content/uploads/2010/08/tutoSDL41.jpg" alt="" width="500" height="225" /></p>
<p>En nuestro caso pasar de un sistema de coordenadas a otro es muy sencillo. Suponed que cada tile tiene un ancho y alto de 50 pixels. Entonces:</p>
<ul>
<li>La casilla (0, 0) tiene las coordenadas absolutas (0, 0) (esquina superior izquierda)</li>
<li>La casilla (1, 0) (la siguiente a la derecha) tiene las coordenadas absolutas (50, 0)</li>
<li>La casilla (2, 0) (la siguiente) tiene las coordenadas abs. (100, 0)</li>
<li>La casilla (2, 1), tiene las coordenadas abs. (100, 50)</li>
<li>La casilla (x, y) tiene las coordenadas abs. (50 * x, 50 * y)</li>
</ul>
<p>Así que:</p>
<pre class="brush: cpp;">plot (x, y) = (ANCHO_TILE * x, ALTO_TILE * y)</pre>
<p>Y el proceso inverso es igual de sencillo:</p>
<pre class="brush: cpp;">mouseMap (x, y) = (x / ANCHO_TILE, y / ALTO_TILE)</pre>
<p>Así que el algoritmo de antes se nos queda en esto:</p>
<pre class="brush: cpp;">for (y = 0; y &lt; ANCHO_MAPA; y++)
   for (x=0; x &lt; ANCHO_MAPA; x++) {
      tileset-&gt;dibuja (mapa[x][y], ANCHO_TILE * x, ALTO_TILE * y, pantalla);
   }</pre>
<p>(He supuesto que tileset tiene un método para dibujar los tiles que recibe el índice del tile, las coordenadas, y la superficie destino)</p>
<p>Desde luego, habrá que implementar ese método en tileset, que básicamente consistirá en averiguar qué rectángulo corresponde al tile indicado, y hacer un blit a las coordenadas que nos pasen, nada complicado.</p>
<p>Bueno, pues ya está. Aunque es un poco simple, no? Vamos a darle una vuelta de tuerca más:</p>
<h2>Scrolling</h2>
<p>Supongo que la mayoría sabréis en que consiste el scroll, pero bueno:</p>
<p>Imaginad que tenemos un mapa muy grande. Al ser tan grande, no cabe dentro de la pantalla, así que no podemos verlo todo de una vez. Lo que hacemos es que la pantalla se convierta en una “ventana” dentro del mundo del juego.</p>
<p>Y por supuesto, el jugador va a ir moviendo esa ventana, desplazándola de un lugar a otro:<br />
<img class="aligncenter size-full wp-image-486" title="tutoSDL42" src="http://razonartificial.com/wp-content/uploads/2010/08/tutoSDL42.jpg" alt="" width="550" height="313" /></p>
<p>El desplazamiento de esa ventana es lo que llamamos <strong>“Scroll”</strong>, y lo mediremos siempre relativo a las coordenadas absolutas de la casilla (0,0). Así que este desplazamiento se medirá en pixels.</p>
<p>Con esto, introducimos un nuevo sistema de coordenadas. Además de lo que teníamos antes, ahora hay que tener en cuenta que las coordenadas de la casilla en la pantalla dependerán del desplazamiento de la pantalla respecto a la casilla (0,0).</p>
<p>Por ejemplo, la casilla con coordenadas lógicas (4, 1) puede tener las coordenadas absolutas (200, 50), y a la hora de dibujarse en pantalla, teniendo en cuenta el desplazamiento, puede que se dibuje en (451, 37).</p>
<p>A estas nuevas coordenadas las llamaremos <strong>“Coordenadas de Pantalla”</strong> (Screen Coordinates)</p>
<p><img class="aligncenter size-full wp-image-487" title="tutoSDL43" src="http://razonartificial.com/wp-content/uploads/2010/08/tutoSDL43.jpg" alt="" width="550" height="382" />El convertir de coordenadas absolutas a coordenadas de pantalla es tan sencillo que lo podemos hacer como parte del plotting:</p>
<pre class="brush: cpp;">plot (x, y) = ((ANCHO_TILE * x) – scroll.x, (ALTO_TILE * y) – scroll.y)</pre>
<p>Y al revés:</p>
<pre class="brush: cpp;">mouseMap (x, y) = ((x + scroll.x) / ANCHO_TILE, y / (y + scroll.y) ALTO_TILE)</pre>
<p>Y por lo tanto el algoritmo se convierte en:</p>
<pre class="brush: cpp;">for (y = 0; y &lt; ANCHO_MAPA; y++)
   for (x=0; x &lt; ANCHO_MAPA; x++) {
      tileset-&gt;dibuja (mapa[x][y], (ANCHO_TILE * x) – scroll.x,
                       (ALTO_TILE * y) – scroll.y, pantalla);
   }</pre>
<p>Ya que hemos llegado hasta aquí, démosle otra vuelta de tuerca más&#8230;</p>
<h2>Optimizaciones</h2>
<p>Vale, volved a imaginar el mapa gigante. Es enorme. Ocupa el equivalente a 8 pantallas de ancho y 5 de alto. Son un montón de casillas. Pero sólo vamos a ver las que “quepan” en pantalla.</p>
<p>Entonces&#8230; ¿para qué estamos recorriendo todas las demás y diciéndoles que se dibujen? Si no se van a ver.</p>
<p>En programación gráfica, la primera regla de oro es “No dibujarás nada que no se vaya a ver en pantalla”, así que vamos a ver si podemos optimizar esto un poco, y evitar dibujar siempre todo el mapa.</p>
<p>Lo que está claro es que vamos a dibujar todas las casillas que estén dentro de la pantalla, es decir, estas:<br />
<img class="aligncenter size-full wp-image-404" title="tutoSDL44" src="http://razonartificial.com/wp-content/uploads/2010/07/tutoSDL44.jpg" alt="" width="450" height="302" /></p>
<p>Todas las casillas marcadas en verde azuloide serán las que tengamos que dibujar. Todas las demás no hacen falta.</p>
<p>Asi que lo que tenemos que hacer es limitar el bucle de nuestro algoritmo a ese rectángulo verdi azuloide. Pero para hacer eso, necesitamos conocer cuáles son las casillas de sus esquinas. Necesitamos saber sus coordenadas lógicas, no?</p>
<p>No las tenemos, pero si que tenemos sus coordenadas de Pantalla. Si la pantalla es de 800&#215;600, las coordenadas de pantalla de las esquinas son:</p>
<ul>
<li>(0, 0) para la esquina superior izquierda</li>
<li>(800, 0) para la esquina superior derecha</li>
<li>(0, 600) para la esquina inferior izquierda</li>
<li>(800, 600) para la esquina inferior derecha</li>
</ul>
<p>Si mapeamos estas coordenadas, obtendremos las coordenadas de las casillas que se encuentran en cada una de las esquinas. Es decir, las casillas que delimitan el rectángulo verdi azuloide. Es decir, las que debemos meter en nuestro bucle para dibujar sólo las que realmente son necesarias&#8230;</p>
<p>Pues venga:</p>
<pre class="brush: cpp;">inicial = mouseMap (0, 0);

limDerecho = mouseMap (800, 0);
limInferior = mouseMap (0, 600);

for (y = inicial.y; y &lt; limInferior.y; y++)
   for (x=inicial.x; x &lt; limDerecho.x; x++) {
      tileset-&gt;dibuja (mapa[x][y], (ANCHO_TILE * x) – scroll.x,
                       (ALTO_TILE * y) – scroll.y, pantalla);
   }</pre>
<p class="advertencia"><strong>Nota:</strong> Sería necesario comprobar también si la casilla que vamos a dibujar es &#8220;válida&#8221;. Es decir, está dentro del mapa, para no dibujar casillas como (-3, 0), por ejemplo.</p>
<p>Por último vamos a ver tratamiento de capas.</p>
<h2>Layering</h2>
<p>¿Qué es el layering? Pues simplemente, tener varias capas de tiles por cada casilla. Si queremos guardar no sólo el tipo de terreno, sino también si hay un objeto en la casilla, necesitamos más información que un simple entero.</p>
<p>Lo que tenemos entonces son varios “tiles” en una casilla, que se dibujan desde el fondo hacia arriba (primero el suelo, luego los objetos, etc&#8230;).</p>
<p>En nuestro caso lo que haremos será que la casilla no sea un “int”, sino una estructura (o clase) Casilla, que guardará el tipo de suelo, pero también el tipo de pared, si tiene algún objeto, etc&#8230;</p>
<p>A la hora de dibujarlo, habrá que dibujar todo eso en orden:</p>
<pre class="brush: cpp;">tilesetSuelos-&gt;dibuja (mapa[x][y].tipoSuelo, (ANCHO_TILE * x) – scroll.x,
                       (ALTO_TILE * y) – scroll.y, pantalla);

tilesetParedes-&gt;dibuja (mapa[x][y].tipoPared, (ANCHO_TILE * x) – scroll.x,
                        (ALTO_TILE * y) – scroll.y, pantalla);

tilesetObjetos-&gt;dibuja (mapa[x][y].tipoObjeto, (ANCHO_TILE * x) – scroll.x,
                        (ALTO_TILE * y) – scroll.y, pantalla);</pre>
<p>Y os podeis imaginar que será algo más complicadillo, ¿verdad?</p>
<p><a href="http://www.wired-weasel.com/users/serhid/tutos/tut4.html">Fuente</a></p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-iii/" title="Introducción a la programación gráfica 2D (III)">Introducción a la programación gráfica 2D (III)</a></li><li><a href="http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-ii/" title="Introducción a la programación gráfica 2D (II)">Introducción a la programación gráfica 2D (II)</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-i/" title="Introducción a la programación gráfica 2D (I)">Introducción a la programación gráfica 2D (I)</a></li><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/oBCDxoAKLBnq9dZfCwLYkvyqrZo/0/da"><img src="http://feedads.g.doubleclick.net/~a/oBCDxoAKLBnq9dZfCwLYkvyqrZo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/oBCDxoAKLBnq9dZfCwLYkvyqrZo/1/da"><img src="http://feedads.g.doubleclick.net/~a/oBCDxoAKLBnq9dZfCwLYkvyqrZo/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/OCFMuaX-BbM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/tilemapping-juegos-basados-en-tiles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducción a la programación gráfica 2D (III)</title>
		<link>http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-iii/</link>
		<comments>http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-iii/#comments</comments>
		<pubDate>Fri, 20 Aug 2010 02:00:44 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Teoría]]></category>
		<category><![CDATA[Tutoriales]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=508</guid>
		<description><![CDATA[En este tutorial vamos a hablar algo más acerca de los superficies y el &#8220;Blit&#8221;. Ya que al final todo juego 2D se basa en copiar superficies (por lo menos la parte gráfica). En realidad el &#8220;Blittelado&#8221; es algo más complejo que copiar y pegar de una superficie a otra, a lo mejor las superficies [...]]]></description>
			<content:encoded><![CDATA[<p>En este tutorial vamos a hablar algo más acerca de los superficies y el &#8220;Blit&#8221;. Ya que al final todo juego 2D se basa en copiar superficies (por lo menos la parte gráfica).</p>
<p>En realidad el &#8220;Blittelado&#8221; es algo más complejo que copiar y pegar de una superficie a otra, a lo mejor las superficies no tienen el mismo formato de pixel y hay que convertirlos, por lo general esto será trasparente para el usuario y se encargará de ello la api gráfica, de todos modos esto es mejor consultar sobre la api en particular que se esté usando.</p>
<h2><span style="font-weight: normal;">Sistemas de coordenadas</span></h2>
<p>Todas las superficies de las apis gráficas deben de tener un sistema de coordenadas, este se utiliza para saber en que parte se debe copiar una superficie a otra o que tamaño tiene una imagen que al fin y al cabo es lo que van a contener las superficies de nuestras aplicaciones.</p>
<p>El sistema de coordenadas tiene su origen en la esquina superior izquiera de la superficie, siendo ese pixel de la superficie la coordenada (0, 0) de la imagen.</p>
<div><img class="aligncenter size-full wp-image-509" title="Diagrama1" src="http://razonartificial.com/wp-content/uploads/2010/08/Diagrama1.png" alt="" width="301" height="217" /></div>
<div>Como vemos en la imagen tenemos dos ejes (x, y) siendo <strong>x</strong> el ancho de la superficie e<strong> y</strong> el alto. La imagen de arriba representa a cualquier superficie y como ya hemos dicho más de una vez una superficie es tanto una imagen como la misma pantalla.<span id="more-508"></span></div>
<h2><span style="font-weight: normal;">Las superficies son rectangulares siempre</span></h2>
<p>Es muy importante que se entienda que las superficies siempre son rectángulos. Y tu puedes decir, mentira, ¡El mismo Pacman es redondo! y yo te diré tu lo ves redondo, pero internamente no es más que un rectángulo que tiene un colo transparente (más adelante hablaremos del canal alpha, colorkey y demás).</p>
<p>Bien vamos a tratar con una superficie que represente una imagen, pongamos que tenemos esta imagen (No os riáis, no me llevo bien con el dibujo).</p>
<p><img class="aligncenter size-full wp-image-510" title="comecocos" src="http://razonartificial.com/wp-content/uploads/2010/08/comecocos.png" alt="" width="98" height="103" /></p>
<p>Está imagen podría ser la superficie de nuestro juego y tendría su coordenada (0, 0) en la parte superior derecha luego tendría un ancho y un elto en esta caso 98&#215;103 por tanto el pixel inferior derecho tendría la coordenada (98, 103). Otras coordenadas son las superior derecha sería la (98, 0) y la inferior izquierda sería la (0, 103). Creo que se capta la idea.</p>
<p>Ahora supongamos que queremos hacer un blit de nuestra superficie a la superficie screen, en otras palabras, copiar nuestra imagen en la pantalla. ¿Dónde se copiaría), pues en la coordenada que le pasemos a nuestra función que se encargue de hacer el blit.</p>
<p>Supongamos que tenemos una  superficie screen de 320&#215;240 y nuestra imagen y queremos copiarla en la coordenada (50, 47). Pues se copiará de la siguiente manera:</p>
<p><img class="aligncenter size-full wp-image-511" title="screen_comecocos" src="http://razonartificial.com/wp-content/uploads/2010/08/screen_comecocos.png" alt="" width="320" height="240" /></p>
<p>Como vemos la coordenada (0, 0) de la superficie origen se copia en la coordenada que elijamos de la superficie destino, es decir, la coordenada (0, 0) de nuestra superficie imagen la colocamos en la coordenada (50, 47) de la superficie de la pantalla. Por lo que para obtener la posición que ocupa el pixel inferior derecho de la imagen en la pantalla valdría una simple suma. (X+ANCHO_IMAGEN, Y+ALTO_IMAGEN), en nuestro caso sería (50+98, 47+103) que nos daría la coordenada del pixel final de la imagen.</p>
<p>Por lo general las bibliotecas gráficas existentes a parte del inicio se le puede indicar el final de lo que se quiere copar por lo que solo quedaría copiada esta área de la imagen. Vamos a hablar de los clippers.</p>
<h2><span style="font-weight: normal;">Clippers</span></h2>
<p>Lo que hace el clipper es definir el área de la superficie destino sobre el que podemos blittear. Todo lo que caiga fuera de ese área, no se dibuja.</p>
<p><img class="aligncenter size-full wp-image-512" title="tutoSDL33" src="http://razonartificial.com/wp-content/uploads/2010/08/tutoSDL33.jpg" alt="" width="460" height="305" /></p>
<p>El clipper de una superficie solo afecta a los blits que tengan como DESTINO a esa superficie. No afecta para nada al origen.</p>
<p>En la imagen de la izquierda dice “sin clipper”, pero eso no es completamente correcto. En realidad, siempre hay un clipper, sólo que por defecto su área abarca toda la superficie, dejando que bliteemos en todas partes.</p>
<p>La razón de que existan los clippers es sencillamente el evitar que al hacer un blit podamos escribir en zonas de memoria que no corresponden a la superficie. El rectángulo nunca puede extenderse más allá del limite de la superficie, así que ese problema desaparece automáticamente.</p>
<p>Pero además de eso, podemos darle más utilidades para optimizar el dibujado. Si sólo necesitamos actualizar una zona de la superficie destino, pero la región que estamos blitteando es enorme, usando un clipper nos evitamos escribir pixels que no necesitamos (o que no debemos, porque no queremos machacarlos).</p>
<h2><span style="font-weight: normal;">Color Keys</span></h2>
<p><span style="font-weight: normal;">Volvamos al problema que teníamos más arriba, donde decíamos que todos las superficies han de ser rectangulares, como el Pacman de más arriba. En realidad lo ideal sería que solo se dibujara nuestro sprite y no el área rosa de alrededor, para ello se usa el colorkey, esto consisten en definir un color de la imagen como transparente. Todo el color de una imagen marcado como colorkey se volverá transparente. Pongamos un ejemplo:</span></p>
<p><span style="font-weight: normal;"><img class="aligncenter size-full wp-image-513" title="tutoSDL34" src="http://razonartificial.com/wp-content/uploads/2010/08/tutoSDL34.jpg" alt="" width="500" height="290" />Como vemos el recuadro blanco queda muy mal, la solución es definir que en nuestra superficie de origen el colorkey se la imagen sería el blanco, por lo que nos quedaría:</span></p>
<p><span style="font-weight: normal;"><img class="aligncenter size-full wp-image-514" title="tutoSDL35" src="http://razonartificial.com/wp-content/uploads/2010/08/tutoSDL35.jpg" alt="" width="500" height="278" /></span></p>
<p><span style="font-weight: normal;">Como vemos mucho mejor, pero no olvidemos dos cosas importantes.</span></p>
<ol>
<li>Aunque el rectángulo blanco sea transparente sigue estando ahí y la esquina superior izquieda de nuestra imagen sigue siendo la que era antes, aunque no se vea.</li>
<li>El colorkey hace que TODOS los píxeles de ese color se vuelvan transparentes por lo que debes asegurarte de que el color que uses como colorkey no forma parte de la imagen. Se suelen usar colores poco comunes como el (255, 0, 255) que es el rosa chillón de arriba, pero si tu imagen tiene este color basta con usar otro.</li>
</ol>
<h2><span style="font-weight: normal;">Canal Alpha</span></h2>
<p>Por último mencionar el canal Alpha, consiste en definir un grado de transparencia para la imagen.</p>
<p><img class="aligncenter size-full wp-image-515" title="tutoSDL36" src="http://razonartificial.com/wp-content/uploads/2010/08/tutoSDL36.jpg" alt="" width="400" height="261" />No voy a explicar mucho más de el porque en apis 2D que no usen tratamiento por gráficos 3D como OpenGL o DirectX usar el canal alpha gasta muchos recursos pues no solo hay que leer la imagen de origen sino también el destino para la mezcla de colores haciendo que en ocasiones pueda ser un verdadero cuello de botella para el rendimiento.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/tilemapping-juegos-basados-en-tiles/" title="Tilemapping – Juegos basados en tiles">Tilemapping – Juegos basados en tiles</a></li><li><a href="http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-ii/" title="Introducción a la programación gráfica 2D (II)">Introducción a la programación gráfica 2D (II)</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-i/" title="Introducción a la programación gráfica 2D (I)">Introducción a la programación gráfica 2D (I)</a></li><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/VUSTnd5AKhrz7lIPv0TbPxn4BhE/0/da"><img src="http://feedads.g.doubleclick.net/~a/VUSTnd5AKhrz7lIPv0TbPxn4BhE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/VUSTnd5AKhrz7lIPv0TbPxn4BhE/1/da"><img src="http://feedads.g.doubleclick.net/~a/VUSTnd5AKhrz7lIPv0TbPxn4BhE/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/aufG39VPRtw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-iii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducción a la programación gráfica 2D (II)</title>
		<link>http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-ii/</link>
		<comments>http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-ii/#comments</comments>
		<pubDate>Thu, 19 Aug 2010 18:49:06 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Teoría]]></category>
		<category><![CDATA[Tutoriales]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=501</guid>
		<description><![CDATA[Ahora que sabemos lo básico vamos a entrar en materia diferenciando los gráficos 2D y 3D y explicando los conceptos básicos de como trabajan las bibliotecas 2D. Diferencias entre 3D y 2D En primer lugar, una API 3D se basa en polígonos. Estos polígonos están formados por vértices con coordenadas en 3D. Lo que hacemos [...]]]></description>
			<content:encoded><![CDATA[<p>Ahora que sabemos lo básico vamos a entrar en materia diferenciando los gráficos 2D y 3D y explicando los conceptos básicos de como trabajan las bibliotecas 2D.</p>
<h2>Diferencias entre 3D y 2D</h2>
<p>En primer lugar, una API 3D se basa en polígonos. Estos polígonos están formados por vértices con coordenadas en 3D. Lo que hacemos (o lo que hace la API), es “proyectar” estos polígonos sobre un plano (la pantalla, o más concretamente, un trozo de la pantalla al que se llama “viewport”)</p>
<p>Cuando esos polígonos los dibujamos en pantalla, además tenemos la opción de rellenarlos con una imagen, a la que llamamos “textura”. Este proceso se llama “rasterización”.</p>
<p>Entonces, para hacer una aplicación 2D en una librería 3D, bastaría con usar una proyección ortogonal.</p>
<p>Eso es completamente correcto para las librerías 3D, que se basan en el proceso de “proyección + rasterización”. Sin embargo, al usar una librería 2D (SDL, Pygame&#8230;), esos conceptos sencillamente no existen.</p>
<p>Para entender cómo es la filosofía de la programación clásica 2D, hay que pensar cómo eran los ordenadores de hace 15 años. En esa época las tarjetas aceleradoras no existían (o costaban una pasta), y todo este proceso de “proyección + rasterización” tenía que hacerse mediante software. Y en aquella época, los procesadores no eran especialmente rápidos, especialmente en operaciones en punto flotante.</p>
<p>Así que es lógico que al programar una aplicación en 2D, se hiciese mediante un sistema en el que las proyecciones y rasterizaciones no existan, y todos los cálculos sean únicamente operaciones enteras, que los procesadores pueden realizar mucho más rápido.<span id="more-501"></span></p>
<h2>Conceptos básicos de programación 2D</h2>
<p>Una librería gráfica 2D se basa en el concepto de <strong>SUPERFICIES</strong>, y de operaciones entre superficies. Una superficie no es más que un espacio en memoria donde guardar una imagen, y las operaciones que se realizan entre superficies, son copias de trozos de una superficie origen sobre una superficie destino.</p>
<p>Un ejemplo: el Paint.<br />
Al cargar el paint, el lienzo representaría una superficie. Puede tener una imagen cargada desde un archivo, puede estar en blanco, etc&#8230;</p>
<p>Ahora imaginad que ejecutamos 2 paints. Cada uno con su lienzo. Eso representa 2 superficies en memoria. Podemos tener una superficie vacía (blanca), y otra con una imagen cargada del archivo.</p>
<p>Y la operación básica entre superficies, sería hacer un “Copy-Paste”. Seleccionar una región en la superficie A, y copiarla sobre algún lugar en la superficie B. Esta operación es a la que se llama “Blit”, y es la más importante en cualquier librería 2D.</p>
<p><img class="aligncenter size-full wp-image-503" title="tutoSDL11" src="http://razonartificial.com/wp-content/uploads/2010/08/tutoSDL11.jpg" alt="" width="557" height="354" /></p>
<p>Al igual que en Paint, al hacer un Blit, lo que había en la superficie destino en la región que sobreescribimos se pierde para siempre. Al copiar sobre esa posición machacamos los datos anteriores. Esto es importante si tenemos, por ejemplo, un personaje moviéndose sobre un escenario. Al dibujar el personaje destruimos esa región del escenario, así que si el personaje se mueve, tendremos que volver a dibujar de nuevo el escenario por cada fotograma.</p>
<p>También de esto sacamos que el orden en que hagamos los blits importa, y mucho. Si algo tiene que quedar por encima, tiene que ser lo último que bliteemos.</p>
<p><img class="aligncenter size-full wp-image-504" title="tutoSDL12" src="http://razonartificial.com/wp-content/uploads/2010/08/tutoSDL12.jpg" alt="" width="515" height="297" /></p>
<p>Todo esto está muy bien para copiar imágenes entre superficies. ¿Pero cómo se muestra todo eso en pantalla?. Fácil, tendremos una superficie especial, que represente a la pantalla propiamente dicha. Todo lo que pongamos en esa superficie será lo que aparecerá por pantalla.</p>
<p>Esa superficie suele llamarse screen (Pantalla) y tiene como tamaño la resolución, por ejemplo, si tu aplicación es una ventana de 640&#215;480 pues ese será el tamaño de tu superficie y ahí podras hacer todo los blit que quieras, a diferencia que lo que hay en esta superficie es lo que se muestra.</p>
<h2>Flipping</h2>
<p>Vale, ahora tenemos una imagen que hemos compuesto sobre el Buffer Primario. Ya tenemos todo listo para que se muestre en el monitor. ¿Como hacemos para “actualizar” el monitor?</p>
<p>Depende, hay dos maneras de hacerlo, la fácil, y la difícil.</p>
<p>La fácil es llamar a la función de nuestra biblioteca que se encargue de  dibujar y actualizar directamente todo a la superficie de nuestra screen. El problema de esto es que el monitor tiene un refresco de actualización, y si llamamos a esta función en el momento en que el monitor está dibujando algo, lo que veremos será un parpadeo bastante molesto.</p>
<p>Lo que queremos es que esa actualización se produzca justo en el momento en que el monitor ha terminado de dibujar un fotograma, y esta preparándose para el siguiente. A esto se le llama “sincronizarlo con el refresco vertical”, o en inglés, “VSYNC”.</p>
<p>Para hacer eso, lo que se usa es una técnica llamada “Double Buffer”. Consiste en que tendremos un buffer Secundario (o “BackBuffer”), además del primario. Nuestra imagen la compondremos en el secundario, y llegado el momento, intercambiaremos ambos buffers para que el secundario pase a ser el primario y viceversa, actualizando la imagen en el monitor. Este intercambio estará sincronizado con el refresco del monitor.</p>
<p><img class="aligncenter size-full wp-image-505" title="tutoSDL13" src="http://razonartificial.com/wp-content/uploads/2010/08/tutoSDL13.jpg" alt="" width="500" height="309" /></p>
<p>La mayoría de las bibliotecas gráficas modernas tienen funciones o clases que se encargan ellas solas de hacer todo este del doblebuffer y nosotros simplemente tenemos que decir que actualice la pantalla y ella se encarga de crearlo, pero es importante conocer como funciona.</p>
<h2>Resumiendo:</h2>
<ul>
<li>Programación 3D != Programación 2D.</li>
<li>Programación 3D == Punto Flotante, matrices, proyecciones + rasterizaciones.</li>
<li>Programación 2D == Operaciones enteras, ints, copias de trozos de memoria de un lado a otro.</li>
</ul>
<ul>
<li>Superficie: Espacio en memoria donde tenemos una imagen.</li>
<li>Blit: Copy-paste de una región de una superficie sobre otra.</li>
<li>Buffer Primario: Superficie que contiene lo que se dibuja en pantalla.</li>
<li>Double Buffer: Algo raro que evita los parpadeos.</li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/tilemapping-juegos-basados-en-tiles/" title="Tilemapping – Juegos basados en tiles">Tilemapping – Juegos basados en tiles</a></li><li><a href="http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-iii/" title="Introducción a la programación gráfica 2D (III)">Introducción a la programación gráfica 2D (III)</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-i/" title="Introducción a la programación gráfica 2D (I)">Introducción a la programación gráfica 2D (I)</a></li><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/elqLD1XqogScAfJPZwIVg8tBy28/0/da"><img src="http://feedads.g.doubleclick.net/~a/elqLD1XqogScAfJPZwIVg8tBy28/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/elqLD1XqogScAfJPZwIVg8tBy28/1/da"><img src="http://feedads.g.doubleclick.net/~a/elqLD1XqogScAfJPZwIVg8tBy28/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/imqatq-6wHw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-ii/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Introducción a la programación gráfica 2D (I)</title>
		<link>http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-i/</link>
		<comments>http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-i/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 20:41:58 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Teoría]]></category>
		<category><![CDATA[Tutoriales]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=492</guid>
		<description><![CDATA[Un problema bastante común para los que se inician en la programación de videojuegos es el paso de programar en la consola a hacer aplicaciones gráficas, saben que tienen que usar bibliotecas gráficas como DirectX, OpenGL, SDL, Pygame, Allegro, etc. Pero no saben como empezar con todo esto y como funciona. En la red hay [...]]]></description>
			<content:encoded><![CDATA[<p>Un problema bastante común para los que se inician en la programación de videojuegos es el paso de programar en la consola a hacer aplicaciones gráficas, saben que tienen que usar bibliotecas gráficas como DirectX, OpenGL, SDL, Pygame, Allegro, etc. Pero no saben como empezar con todo esto y como funciona. En la red hay documentación, pero está bastante dispersa y no sigue una línea voy a intentar cogiendo un poco de aquí y de allá y algo de aportación propia hacer una guía básica sobre los fundamentos de como trabajar con aplicaciones gráficas para los que se inician.</p>
<p>Esto no será para ningún lenguaje concreto será teoría aplicable a cualquier lenguaje y biblioteca de gráficos 2D.</p>
<h2>Hardware y representación de imágenes</h2>
<p>Vamos a comenzar repasando algunos conceptos básicos sobre las imágenes y su representación en un ordenador.</p>
<p>Una imagen puede ser representada como un conjunto de puntos. Cada uno de esos puntos tienen un color asociado. El número de puntos que representa una imagen puede variar segúna la definición que queramos obtener. Con cuantos más puntos sea representada una imagen más calidad tendrá y más espacio necesitaremos para almacenarla. Este aumento de tamaño provocará un aumento de tiempo de computación para que pueda ser mostrada. Esto se traduce en un mayor consumo de espacio de disco y que las transferencias de datos que hace que la imagen se nos muestre en la pantalla de nuestro ordenador estén más cargadas al tener más datos que intercambiar. Por este motivo es fundamental trabajar con una resolución idónea, buscando el equilibrio entre espacio y calidad.</p>
<p><span id="more-492"></span></p>
<p>Estos puntos a los que hacemos referencia se conocen como <strong>píxeles</strong> y determinan la resolución de una imagen. Los monitores tienen una limitación en cuanto al número de píxeles que pueden mostrar. Esta limitación es un máximo ya que siempre podrá mostrar un número menor de píxeles. Cada uno de estos píxeles tendrá asociado un color para los que se destinará un determinado número de bits (<strong>bits por píxel</strong> o bpp) que determinaran la calidad, medida en profundida de color, de la imagen. Los valores más comunes para el bpp son:</p>
<ul>
<li>8 bits (256 colores)
<ul>
<li>Debemos usar una paleta para establecer los distintos 256 posibles colores.</li>
</ul>
</li>
<li>16 bits (65,536 colores o Highcolor)
<ul>
<li>Existen distintas combinaciones para el uso de estos 16 bits. Las más comunes son:
<ul>
<li>5 bits para rojo, 6 bits para verde y 5 para azul. Se utiliza esta distribución porque el ojo humano distingue más colores verdes que otros.</li>
<li>4 bits para rojo, 4 bits para verde, 4 para azul y 4 para transparencias. Este es un modelo más equitativo.</li>
</ul>
</li>
</ul>
</li>
<li>24 bits (16,777,216 colores o Truecolor)
<ul>
<li>Este es el modelo RGB puro. Se destinan 8 bits para cada color que cubren todo el espectro.</li>
</ul>
</li>
<li>32 bits (16,777,216 colores)
<ul>
<li>Utiliza RGB más 8 bits destinados a canales <em>alpha</em> o transparencias.</li>
</ul>
</li>
</ul>
<p><img class="aligncenter size-full wp-image-495" title="Resolucion_imagen" src="http://razonartificial.com/wp-content/uploads/2010/08/Resolucion_imagen1.png" alt="" width="659" height="133" /></p>
<p>Depende del sistema en el que trabajamos y para el que vaya destinado la aplicación definiran unas resoluciones de trabajo con una profundidad de color bien determinada. Como puedes suponer cuanto mayor sea el número de bits por píxel mayor será el tamaño de la imagen. Este es otro factor a considerar ya que necesitaremos la cantidad de bits indicada por el bpp para almacenar un sólo píxel. SDL nos proporciona funciones que nos permiten establecer estos modos de video así como consultar su compatibilidad con el sistema.</p>
<p>Un concepto importante es el de framebuffer que aparecerá varias veces en el tutorial. El framebuffer no es más que la zona de memoria que se corresponde con la imagen que mostrará el sistema en pantalla. Cada píxel tendrá una concordancia exacta en pantalla en una determinada posición. El formato del framebuffer suele ser un vector para simplificar la escritura sobre él. Al ser un vector unidimensional, a la hora de querer modficiar un píxel dado por unas coordenadas (x, y) tendremos que realizar una conversión de escala.</p>
<h2>Subsistema de Vídeo</h2>
<p>El subsistema de vídeo es la parte del sistema que nos permite interactuar con los dispositivos de vídeo. Generalmente el hardware de vídeo está compuesto por una tarjeta gráfica y un monitor o pantalla de visualización.</p>
<p>Existen numerosos tipos de tarjetas gráficas en el mercado pero todas ellas tienen características comunes que nos permiten trabajar con ellas independientemente del fabricante o del tipo de chip que monten dichas tarjetas. Poseen una unidad de procesamiento de gráficos y una memoria, ya sea compartida o dedicada, donde almacenar las estructuras o imágenes que se deben mostrar por pantalla.</p>
<p>El número de pantallas existentes en el mercado también es muy amplio pero no es algo que nos afecte a la hora de desarrollar un videojuego actualmente a no ser que lo hagamos para un dispostivo específico. En otros tiempos conocer la cantidad de colores que podía manejar un subsistema de vídeo era fundamental para diseñar cualquier aplicación para dicho sistema. Hoy en día la mayoría de los ordenadores que tenemos en casa son capaces de manejar el conocido como color real o <em>true color</em> a unas resoluciones que son prácticamente estándar.</p>
<p>Los principales aspectos que tenemos que tener encuenta de estos dispositivos son dos:</p>
<ul>
<li>La primera es la resolución de ambos dispositivos. Siempre deberemos trabajar a una resolución que sea admisible por el hardware en cuestión. Sería absurdo realizar un videojuego con un tamaño de ventana de 5000 x 5000 para un ordenador personal actual. Algo más avanzado el capítulo presentaremos las resoluciones más habituales.</li>
</ul>
<p>El concepto de resolución de pantalla es bastante simple. Se trata del número de píxeles que puede ser mostrada por pantalla. Viene presentada, normalmente, por la ecuación x * y donde x hace referencia al número de columnas de píxeles e y indica el número de filas de píxeles. Puedes observar las referencias en la imagen que se muestra a continuación.</p>
<p><img class="aligncenter size-full wp-image-497" title="Resolucion" src="http://razonartificial.com/wp-content/uploads/2010/08/Resolucion.png" alt="" width="650" height="279" /></p>
<ul>
<li>La segunda es la posibilidad de crear superficies en la memoria de la tarjeta gráfica. Algunas tarjetas gráficas tienen la memoria integrada en la placa base del ordenador por lo que comparten memoria con la CPU y emularán este comportamiento aunque almacenen el contenido en la memoria principal del sistema. El poder almacenar en dicha memoria las superficies que queramos mostrar es muy importante ya que concederá un mayor rendimiento a nuestra aplicación. Esta memoria es conocida como RAMDAC.</li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/tilemapping-juegos-basados-en-tiles/" title="Tilemapping – Juegos basados en tiles">Tilemapping – Juegos basados en tiles</a></li><li><a href="http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-iii/" title="Introducción a la programación gráfica 2D (III)">Introducción a la programación gráfica 2D (III)</a></li><li><a href="http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-ii/" title="Introducción a la programación gráfica 2D (II)">Introducción a la programación gráfica 2D (II)</a></li><li><a href="http://razonartificial.com/2010/06/engine-vi-formato-tmx/" title="Engine VI: El formato TMX">Engine VI: El formato TMX</a></li><li><a href="http://razonartificial.com/2010/03/a-pathfinding-camino-optimo/" title="A* Pathfinding. Camino óptimo">A* Pathfinding. Camino óptimo</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/2DVGkF6RJD5ak7MKijjCzbPrGUE/0/da"><img src="http://feedads.g.doubleclick.net/~a/2DVGkF6RJD5ak7MKijjCzbPrGUE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/2DVGkF6RJD5ak7MKijjCzbPrGUE/1/da"><img src="http://feedads.g.doubleclick.net/~a/2DVGkF6RJD5ak7MKijjCzbPrGUE/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/IhLgEUmK2wo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-i/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Muestra del Engine de PyIA</title>
		<link>http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/</link>
		<comments>http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/#comments</comments>
		<pubDate>Tue, 10 Aug 2010 21:34:22 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Competiciones]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=474</guid>
		<description><![CDATA[Bueno después de anunciar el concurso y de enseñar algo de lo que llevaba ya he avanzado bastante con el engine y ya es &#8220;usable&#8221;. ya es capaz de cargar distintos niveles y tiene varios obstáculos y algún ayudante. Publico para el que esté interesado en el concurso pueda ir probándolo. De momento es como [...]]]></description>
			<content:encoded><![CDATA[<p>Bueno después de anunciar el concurso y de enseñar algo de lo que llevaba ya he avanzado bastante con el engine y ya es &#8220;usable&#8221;. ya es capaz de cargar distintos niveles y tiene varios obstáculos y algún ayudante. Publico para el que esté interesado en el concurso pueda ir probándolo. De momento es como un juego de plataforma controlado por el jugador con el pad de direcciones, suficiente para ir porbando la mecánica del juego.</p>
<p>El objetivo de todo nivel es encontrar la E verde que es la salida. Pero habrá trampas como los fosos de pinchos en los que debemos evitar caer.</p>
<p><img class="aligncenter size-full wp-image-475" title="1" src="http://razonartificial.com/wp-content/uploads/2010/08/1.jpg" alt="" width="477" height="226" /></p>
<p>Los bloques amarillos harán que nuestro personaje salte el triple pudiendo superar grandes alturas.</p>
<p><img class="aligncenter size-full wp-image-476" title="2" src="http://razonartificial.com/wp-content/uploads/2010/08/2.jpg" alt="" width="363" height="219" />Los bloques verdes son trampas móviles que van de arriba abajo y los rojos de izquierda a derecha, hay que evitar tocarlas pasando en el momento justo. Vamos como podemos usar los bloques amarillos para superar también grandes distancias.</p>
<p><img class="aligncenter size-full wp-image-477" title="3" src="http://razonartificial.com/wp-content/uploads/2010/08/3.jpg" alt="" width="550" height="179" />El juego se controla con las flechas de dirección izquierda-derecha y arriba para saltar.</p>
<p>El Engine aún esta verde y no hay sistema de puntuación, no están todas las trampas y ayudantes creadas y los 3 niveles que hay son de prueba. Pero ya aunque sea es jugable.</p>
<p>Para ejecutarlo abrir el archivo main.py que esta en la carpeta src.</p>
<ul>
<li><a href="http://razonartificial.com/wp-content/uploads/2010/08/pyIA1.zip">Descargar pyIA</a> (Corregido error de la tecl enter).</li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/pyia-competicion-de-inteligencia-artificial-en-python/" title="PyIA &#8211; Competición de Inteligencia Artificial en Python">PyIA &#8211; Competición de Inteligencia Artificial en Python</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/07/pygame-el-juego-de-la-serpiente/" title="[Pygame] El juego de la serpiente">[Pygame] El juego de la serpiente</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/MWxPtAZUHiFs_y3be1sJEsmZYok/0/da"><img src="http://feedads.g.doubleclick.net/~a/MWxPtAZUHiFs_y3be1sJEsmZYok/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/MWxPtAZUHiFs_y3be1sJEsmZYok/1/da"><img src="http://feedads.g.doubleclick.net/~a/MWxPtAZUHiFs_y3be1sJEsmZYok/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/b6BZmDsUPXg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>PyIA – Competición de Inteligencia Artificial en Python</title>
		<link>http://razonartificial.com/2010/08/pyia-competicion-de-inteligencia-artificial-en-python/</link>
		<comments>http://razonartificial.com/2010/08/pyia-competicion-de-inteligencia-artificial-en-python/#comments</comments>
		<pubDate>Wed, 04 Aug 2010 21:56:31 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Competiciones]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=470</guid>
		<description><![CDATA[Se me ha ocurrido desarrollar una competición de Inteligencia Artificial usando Python y Pyame. La idea aún es un esbozo y estoy desarrollando el engine base, pero publico de que va el asunto a ver si tiene acogida y si alguien está dispuesto a participar. ¿En qué consiste? La idea es mediante la creación de [...]]]></description>
			<content:encoded><![CDATA[<p>Se me ha ocurrido desarrollar una competición de Inteligencia Artificial usando Python y Pyame. La idea aún es un esbozo y estoy desarrollando el engine base, pero publico de que va el asunto a ver si tiene acogida y si alguien está dispuesto a participar.</p>
<h2>¿En qué consiste?</h2>
<p>La idea es mediante la creación de una IA, manejar a un personaje por una serie de niveles de plataformas superando obstáculos, como muros, pinchos, fosos y demás. El objetivo sería encontrar la salida. Los participantes no juegan, solo programan su IA y está es la que compite por ellos, a parte de superar los obstáculos y  llegar a la meta, se compite con otros participantes por lo que se cronometra el tiempo y quien llega antes, se busca la mejor IA.</p>
<p>Por ahora las normas son un esbozo y actualmente estoy desarrollando el engine base del proyecto. He hecho algunas pruebas de una IA básica que es capaz de saltar muros para encontrar la salida, dejo un video de demostración:</p>
<p style="text-align: center;">[There is a video that cannot be displayed in this feed. <a href="http://razonartificial.com/2010/08/pyia-competicion-de-inteligencia-artificial-en-python/">Visit the blog entry to see the video.]</a></p>
<p>Como se puede ver por ahora solo están implementados los muros y las colisiones con esto, falta implementar en el engine, las trampas, control de tiempos, menús y demas.</p>
<p>Luego habría que definir unas normas de que y que no se puede hacer. En principio la IA sera un Script que solo recibe como parámetros el player y la información del mapa para consultar y solo se podría ejecutar acciones predefinidas como player.move() o player.jump() que son las que llevo implementada de momento, ¿Se os ocurre alguna más?  Tal vez la posibilidad de agacharse.</p>
<p>Bueno, espero opiniones de que les parece el proyecto y de si estarían dispuestos a participar.</p>
<p>La idea está inspirada en un concurso de Game Maker llamado GIA, aquí podéis ver un video de como fue aquella competición:</p>
<p style="text-align: center;">[There is a video that cannot be displayed in this feed. <a href="http://razonartificial.com/2010/08/pyia-competicion-de-inteligencia-artificial-en-python/">Visit the blog entry to see the video.]</a></p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/" title="Pathfinding A* en Python. Parte III">Pathfinding A* en Python. Parte III</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/" title="Arboles e inteligencia Artificial">Arboles e inteligencia Artificial</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/08/gestionando-escenas-con-pygame/" title="Gestionando Escenas con Pygame">Gestionando Escenas con Pygame</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/GKE_PvK53C11w_V3XkIRzREX6-Q/0/da"><img src="http://feedads.g.doubleclick.net/~a/GKE_PvK53C11w_V3XkIRzREX6-Q/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/GKE_PvK53C11w_V3XkIRzREX6-Q/1/da"><img src="http://feedads.g.doubleclick.net/~a/GKE_PvK53C11w_V3XkIRzREX6-Q/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/kKBnARvWANw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/08/pyia-competicion-de-inteligencia-artificial-en-python/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>El juego de la vida en C++</title>
		<link>http://razonartificial.com/2010/07/el-juego-de-la-vida-en-c/</link>
		<comments>http://razonartificial.com/2010/07/el-juego-de-la-vida-en-c/#comments</comments>
		<pubDate>Thu, 29 Jul 2010 01:40:40 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Ejemplos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[STL]]></category>
		<category><![CDATA[Vida Artificial]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=466</guid>
		<description><![CDATA[Buenas, volviendo un poco con el tema de la vida artificial que lo tengo apartado, ahora que estoy aprendiendo C++ he vuelto a los orígenes y he programado una versión del juego de la vida para consola usando C++ y la STL, biblioteca que quiero conocer. Ya sabía algo de C básico, pero ahora quiero [...]]]></description>
			<content:encoded><![CDATA[<p>Buenas, volviendo un poco con el tema de la vida artificial que lo tengo apartado, ahora que estoy aprendiendo C++ he vuelto a los orígenes y he programado una versión del <a href="http://razonartificial.com/2010/01/el-juego-de-la-vida/">juego de la vida</a> para consola usando C++ y la <a href="http://www.google.es/url?sa=t&amp;source=web&amp;cd=7&amp;ved=0CEYQFjAG&amp;url=http%3A%2F%2Fes.wikipedia.org%2Fwiki%2FC%252B%252B&amp;ei=3ttQTL_XN4r80wSZk5SRBw&amp;usg=AFQjCNE_pq34xuE-LOkANrTbWI9vUuQjEw&amp;sig2=wEWCFRwiNj46mOu6xnA6XQ">STL</a>, biblioteca que quiero conocer.</p>
<p>Ya sabía algo de C básico, pero ahora quiero pasar el desarrollo de videojuegos a C++ y me he puesto a aprender Orientación a Objetos en C++ y a usar la STL que es una gran biblioteca estándar de C++ que contiene muchas cosas que nos facilitan el trabajo. Bueno después del salto dejo el código.<span id="more-466"></span></p>
<pre class="brush: cpp;">
#include &lt;iostream&gt;
#include &lt;cstdlib&gt;
#include &lt;vector&gt;
#include &lt;unistd.h&gt;

using namespace std;

class Mapa
{
public:
	int fil;
	int col;
	int vecinos;
	vector&lt;vector&lt;int&gt; &gt; mapa;

	Mapa(int f, int c);
	void dibujar();
	int analizarVecinos(int posf, int posc);
	void ciclo();
};

Mapa::Mapa(int f, int c)
{
	fil = f;
	col = c;
	mapa.resize(fil);
	for(int i=0; i&lt;mapa.size(); i++)
	{
		mapa[i].resize(col);
	}

	for(int f=0; f&lt;fil; f++)
	{
		for(int c=0; c&lt;col; c++)
		{
			mapa[f][c] = rand()%2;
		}
	}
}

void Mapa::dibujar()
{
	for(int f=0; f&lt;fil; f++)
	{
		for(int c=0; c&lt;col; c++)
		{
			if(mapa[f][c] == 1)
				cout &lt;&lt; &quot;* &quot;;
			else
				cout &lt;&lt; &quot;. &quot;;
		}
		cout &lt;&lt; &quot;\n&quot;;
	}
}

int Mapa::analizarVecinos(int posf, int posc)
{
	vecinos = 0;
	if(posf-1 &gt;= 0 and posc-1 &gt;= 0)
		if(mapa[posf-1][posc-1] == 1)
			vecinos++;
	if(posf-1 &gt;= 0)
		if(mapa[posf-1][posc] == 1)
			vecinos++;
	if(posf-1 &gt;= 0 and posc+1 &lt;= col-1)
		if(mapa[posf-1][posc+1] == 1)
			vecinos++;
	if(posc-1 &gt;= 0)
		if(mapa[posf][posc-1] == 1)
			vecinos++;
	if(posc+1 &lt;= col-1)
		if(mapa[posf][posc+1] == 1)
			vecinos++;
	if(posf+1 &lt;= fil-1 and posc-1 &gt;= 0)
		if(mapa[posf+1][posc-1] == 1)
			vecinos++;
	if(posf+1 &lt;= fil-1)
		if(mapa[posf+1][posc] == 1)
			vecinos++;
	if(posf+1 &lt;= fil-1 and posc+1 &lt;= col-1)
		if(mapa[posf+1][posc+1] == 1)
			vecinos++;
	return vecinos;
}

void Mapa::ciclo()
{
	vector&lt;vector&lt;int&gt; &gt; nueva_conf = mapa;

	for (int f=0; f&lt;fil; f++)
	{
		for(int c=0; c&lt;col; c++)
		{
			int n_vecinos = analizarVecinos(f, c);
			if(mapa[f][c] == 0)
			{
				if(vecinos == 3)
					nueva_conf[f][c] = 1;
				else
					nueva_conf[f][c] = 0;
			}
			if (mapa[f][c] == 1)
			{
				if(vecinos == 2 || vecinos == 3)
					nueva_conf[f][c] = 1;
				else
					nueva_conf[f][c] = 0;
			}
		}
	}

	mapa = nueva_conf;
}

int main()
{
	srand(time(NULL));
	Mapa mapa(20, 20);
	while(1)
	{
		mapa.dibujar();
		usleep(100000);
		system(&quot;clear&quot;);
		mapa.ciclo();
	}
}
</pre>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/01/optimizacion-basada-en-colonias-de-hormigas-en-la-naturaleza/" title="Optimización basada en colonias de hormigas">Optimización basada en colonias de hormigas</a></li><li><a href="http://razonartificial.com/2010/01/el-juego-de-la-vida-en-python/" title="El juego de la vida en Python">El juego de la vida en Python</a></li><li><a href="http://razonartificial.com/2010/01/el-juego-de-la-vida/" title="El juego de la vida">El juego de la vida</a></li><li><a href="http://razonartificial.com/2010/08/fmod-audio-en-los-videojuegos/" title="Fmod &#8211; Audio en los videojuegos">Fmod &#8211; Audio en los videojuegos</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial-ii/" title="Arboles e inteligencia artificial II">Arboles e inteligencia artificial II</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/u4oP-jj5W4EpsjCLn0bIOkv1ZsM/0/da"><img src="http://feedads.g.doubleclick.net/~a/u4oP-jj5W4EpsjCLn0bIOkv1ZsM/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/u4oP-jj5W4EpsjCLn0bIOkv1ZsM/1/da"><img src="http://feedads.g.doubleclick.net/~a/u4oP-jj5W4EpsjCLn0bIOkv1ZsM/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/HIWXNhlF2Kk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/el-juego-de-la-vida-en-c/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Avances del Engine RPG: Añadido el Scroll</title>
		<link>http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/</link>
		<comments>http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/#comments</comments>
		<pubDate>Sat, 24 Jul 2010 19:10:45 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Engine]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RPG]]></category>
		<category><![CDATA[Videos]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=464</guid>
		<description><![CDATA[Coninúa el desarrollo del Engine RPG. Se ha reescrito toda la parte del dibujado de mapa para hacerlo más eficiente, además ya he añadido la capacidad de scroll en el mapa. Dejo un vídeo: [There is a video that cannot be displayed in this feed. Visit the blog entry to see the video.] Entradas relacionadasEngine [...]]]></description>
			<content:encoded><![CDATA[<p>Coninúa el desarrollo del Engine RPG. Se ha reescrito toda la parte del dibujado de mapa para hacerlo más eficiente, además ya he añadido la capacidad de scroll en el mapa. Dejo un vídeo:</p>
<p style="text-align: center;">[There is a video that cannot be displayed in this feed. <a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/">Visit the blog entry to see the video.]</a></p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/" title="Engine XI: Creando al héroe">Engine XI: Creando al héroe</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li><li><a href="http://razonartificial.com/2010/04/haciendo-un-engine-para-juegos-con-python-y-pygame/" title="Haciendo un engine para juegos">Haciendo un engine para juegos</a></li><li><a href="http://razonartificial.com/2010/06/engine-x-la-clase-mapa-iii/" title="Engine X: La clase mapa III">Engine X: La clase mapa III</a></li><li><a href="http://razonartificial.com/2010/06/engine-ix-cargando-el-tileset/" title="Engine IX: Cargando el tileset">Engine IX: Cargando el tileset</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/GPNV-TEpKJ8z3Aqarok7hNXkepA/0/da"><img src="http://feedads.g.doubleclick.net/~a/GPNV-TEpKJ8z3Aqarok7hNXkepA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/GPNV-TEpKJ8z3Aqarok7hNXkepA/1/da"><img src="http://feedads.g.doubleclick.net/~a/GPNV-TEpKJ8z3Aqarok7hNXkepA/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/PbFLJEwgyLw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Video con los avances del nuevo engine</title>
		<link>http://razonartificial.com/2010/07/video-con-los-avances-del-nuevo-engine/</link>
		<comments>http://razonartificial.com/2010/07/video-con-los-avances-del-nuevo-engine/#comments</comments>
		<pubDate>Fri, 23 Jul 2010 01:19:24 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Engine]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RPG]]></category>
		<category><![CDATA[Video]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=459</guid>
		<description><![CDATA[Aquí les dejo un video de como van los avances del nuevo engine, actualmente estoy trabajando en el desarrollo de prioridades de las capas, como puedes ver en el video si nuestro heroe pasa detrás de un árbol o algo que lo cubra, este se dibuja detrás. [There is a video that cannot be displayed [...]]]></description>
			<content:encoded><![CDATA[<p>Aquí les dejo un video de como van los avances del nuevo engine, actualmente estoy trabajando en el desarrollo de prioridades de las capas, como puedes ver en el video si nuestro heroe pasa detrás de un árbol o algo que lo cubra, este se dibuja detrás.</p>
<p style="text-align: center;">[There is a video that cannot be displayed in this feed. <a href="http://razonartificial.com/2010/07/video-con-los-avances-del-nuevo-engine/">Visit the blog entry to see the video.]</a></p>
<p>Pronto estará lista la wiki con toda la información de esta nueva etapa del proyecto.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/" title="Engine XI: Creando al héroe">Engine XI: Creando al héroe</a></li><li><a href="http://razonartificial.com/2010/06/engine-x-la-clase-mapa-iii/" title="Engine X: La clase mapa III">Engine X: La clase mapa III</a></li><li><a href="http://razonartificial.com/2010/06/engine-ix-cargando-el-tileset/" title="Engine IX: Cargando el tileset">Engine IX: Cargando el tileset</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/dU6yiqY08nG77tQoxO2vZ0ZbiEo/0/da"><img src="http://feedads.g.doubleclick.net/~a/dU6yiqY08nG77tQoxO2vZ0ZbiEo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/dU6yiqY08nG77tQoxO2vZ0ZbiEo/1/da"><img src="http://feedads.g.doubleclick.net/~a/dU6yiqY08nG77tQoxO2vZ0ZbiEo/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/ef_LC2jNLYk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/video-con-los-avances-del-nuevo-engine/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Repositorio en github para el Engine-RPG</title>
		<link>http://razonartificial.com/2010/07/repositorio-en-github-para-el-engine-rpg/</link>
		<comments>http://razonartificial.com/2010/07/repositorio-en-github-para-el-engine-rpg/#comments</comments>
		<pubDate>Thu, 22 Jul 2010 19:06:17 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Engine]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=456</guid>
		<description><![CDATA[Bueno aunque los tutoriales están pausados debido a la restructuración, el nuevo código avanza y he creado un repositorio de código en github para el que desee seguir el proyecto día a día. Lo puedes encontrar aquí: http://github.com/adrigm/Engine-RPG Para obtener el código y los cambios cuando se produzcan necesitan instalar git y saber usar lo [...]]]></description>
			<content:encoded><![CDATA[<p>Bueno aunque los tutoriales están pausados debido a la restructuración, el nuevo código avanza y he creado un repositorio de código en github para el que desee seguir el proyecto día a día. Lo puedes encontrar aquí:</p>
<ul>
<li><a href="http://github.com/adrigm/Engine-RPG">http://github.com/adrigm/Engine-RPG</a></li>
</ul>
<p>Para obtener el código y los cambios cuando se produzcan necesitan instalar git y saber usar lo básico para descargar el código y actualizarlo, <a href="http://geneura.ugr.es/~jmerelo/tutoriales/git/">este es un buen tutorial</a>.</p>
<p>Si tenéis dudas podéis preguntarme en los comentarios.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/07/video-con-los-avances-del-nuevo-engine/" title="Video con los avances del nuevo engine">Video con los avances del nuevo engine</a></li><li><a href="http://razonartificial.com/2010/07/futuro-del-engine-y-los-tutoriales/" title="Futuro del Engine y los tutoriales">Futuro del Engine y los tutoriales</a></li><li><a href="http://razonartificial.com/2010/07/destacamos-del-foro/" title="Destacamos del foro">Destacamos del foro</a></li><li><a href="http://razonartificial.com/2010/07/razon-artificial-crece/" title="Razón Artificial Crece">Razón Artificial Crece</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/e_6hk2dc6wXg-r-0f1xWUdl_tfw/0/da"><img src="http://feedads.g.doubleclick.net/~a/e_6hk2dc6wXg-r-0f1xWUdl_tfw/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/e_6hk2dc6wXg-r-0f1xWUdl_tfw/1/da"><img src="http://feedads.g.doubleclick.net/~a/e_6hk2dc6wXg-r-0f1xWUdl_tfw/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/lGhcGkYjYNk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/repositorio-en-github-para-el-engine-rpg/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Futuro del Engine y los tutoriales</title>
		<link>http://razonartificial.com/2010/07/futuro-del-engine-y-los-tutoriales/</link>
		<comments>http://razonartificial.com/2010/07/futuro-del-engine-y-los-tutoriales/#comments</comments>
		<pubDate>Tue, 20 Jul 2010 02:08:17 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=452</guid>
		<description><![CDATA[Esto es para todos los que están siguiendo el desarrollo del Engine RPG. Y es que ha surgido un dilema, lo que empezó como una forma de hacer algo por diversión y escribir unos tutoriales, ahora cada vez engancha más y lo quieres hacer más y más grande. En principio esto es bueno, pero surgen [...]]]></description>
			<content:encoded><![CDATA[<p>Esto es para todos los que están siguiendo el desarrollo del Engine RPG. Y es que ha surgido un dilema, lo que empezó como una forma de hacer algo por diversión y escribir unos tutoriales, ahora cada vez engancha más y lo quieres hacer más y más grande. En principio esto es bueno, pero surgen algunos problemas.</p>
<p>Como es software en desarrollo muchas cosas hay que cambiarlas y adaptarlas y en concreto el engine está algo mal estructurado, porque en su día comencé sin planificar. Ahora lo estoy reescribiendo desde cero, pero esta vez lo estoy documentando todo y planificando para el futuro.</p>
<p>El problema no es el engine, son los tutoriales, ¿Como hago ahora para continuar por donde íbamos si los restructurado todo? Se me ocurren varias soluciones.</p>
<ol>
<li>Desechamos los tutoriales hasta ahora y empiezo una serie nueva.</li>
<li>Montar una wiki dedicada al proyecto donde publicar todo lo que voy haciendo y demás. Esta idea me gusta, porque no es solo la parte de código, podría estrurar los tipos de formato y como usar las cosas.</li>
<li>No hago restructuración para los tutoriales y sigo una versión con lo que tenemos hasta tener algo jugable. La verdad es que no me motiva mucho sería doble trabajo y encima este jamás sería como el nuevo.</li>
</ol>
<p>Opinad vosotros que debería hacer, y que preferís. También podéis aportar ideas, alguien ya me ha dicho de montar un servidor SVN para actualizar el proyecto y demás.</p>
<h2><span style="color: #ff0000;">Actualización</span></h2>
<p><strong></strong>Muchos en los comentarios creéis que lo mejor sería una wiki, y me planteáis que si no será complicado mantener tantos sistemas. Y puede que un poco así sea, ya que a parte de llevar la web y el foro tengo que escribir contenido para estoys y seguir con el engine.</p>
<p>Es por eso que pregunto si hay alguno de vosotros interesado en gestionar la wiki, encargarse de gestionarla y ponerla a punto y demás cosas necesarias. Porque si me encargo de la wiki también el proyecto va a avanzar más bien poco.</p>
<p>Ya la nueva estructura del engine está y demás información que tengo por aquí, lo que si me dedico a ponerla toda en una wiki pues no avanzo, espero que ya alguno interesado.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/repositorio-en-github-para-el-engine-rpg/" title="Repositorio en github para el Engine-RPG">Repositorio en github para el Engine-RPG</a></li><li><a href="http://razonartificial.com/2010/07/destacamos-del-foro/" title="Destacamos del foro">Destacamos del foro</a></li><li><a href="http://razonartificial.com/2010/07/razon-artificial-crece/" title="Razón Artificial Crece">Razón Artificial Crece</a></li><li><a href="http://razonartificial.com/2010/07/%c2%bfuna-comunidad/" title="¿Una comunidad?">¿Una comunidad?</a></li><li><a href="http://razonartificial.com/2010/06/opiniones-sobre-division/" title="Opiniones sobre división">Opiniones sobre división</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/HBlLB3uSzgEiN5zZY0QpJUmh7i4/0/da"><img src="http://feedads.g.doubleclick.net/~a/HBlLB3uSzgEiN5zZY0QpJUmh7i4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/HBlLB3uSzgEiN5zZY0QpJUmh7i4/1/da"><img src="http://feedads.g.doubleclick.net/~a/HBlLB3uSzgEiN5zZY0QpJUmh7i4/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/tr99YRetcr4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/futuro-del-engine-y-los-tutoriales/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Juego de la serpiente paso a paso. Parte 2</title>
		<link>http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/</link>
		<comments>http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/#comments</comments>
		<pubDate>Sat, 17 Jul 2010 15:01:34 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=443</guid>
		<description><![CDATA[En esta parte definiremos sub-rutinas que nos servirán para controlar varios loops dentro de un juego, muy útil para mostrar menús, pausar el juego y demás. Adaptando a subrutinas Antes de seguir vamos a mirar al futuro, la idea es que el juego muestre al iniciar un menú donde puedas elegir nuevo juego, opciones, mejores [...]]]></description>
			<content:encoded><![CDATA[<p>En esta parte definiremos sub-rutinas que nos servirán para controlar varios loops dentro de un juego, muy útil para mostrar menús, pausar el juego y demás.</p>
<h2>Adaptando a subrutinas</h2>
<p>Antes de seguir vamos a mirar al futuro, la idea es que el juego muestre al iniciar un menú donde puedas elegir nuevo juego, opciones, mejores puntuaciones y salir. Por lo que el bucle principal de nuestro juego debería ser este menú y luego según la opción llamar a una función u otra que se encargue de gestionar un sub-bucle propio.</p>
<p>Primero que nada vamos a crear la función que ejecuta el juego que sería la siguiente:</p>
<p><span id="more-443"></span></p>
<pre class="brush: python;">
def nuevo_juego(screen):
	background_image = load_image('images/fondo.jpg');

	clock = pygame.time.Clock()

	while True:
		time = clock.tick(60)
		keys = pygame.key.get_pressed()
		salir(keys)

		mapa.dibujar(screen)
		screen.blit(background_image, (0, 0))
		pygame.display.flip()
</pre>
<p>y el bucle principal entonces nos queda así:</p>
<pre class="brush: python;">
def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)

	while True:
		nuevo_juego(screen)
	return 0
</pre>
<p>Como vemos la ventana (screen) se sigue creando en el bucle principal, pero se la pasamos como parámetro a nuestra sub-rutina <strong>nuevo_juego</strong>. Por ahora lo único que hacemos dento del bucle principal es llamar a la sub-rutina nuevo_juego y que esta tome el control, por lo que por ahora trabajaremos sobre esta.</p>
<p>Tenemos que crear el objeto mapa dentro de nuestra función nuevo_juego, para ello añadimos la siguiente línea:</p>
<pre class="brush: python;">
mapa = Mapa(&quot;mapa.txt&quot;)
</pre>
<h2>Dibujando el mapa</h2>
<p>Como ya hemos dicho será la clase mapa la encargada de dibujar todo, por lo que será el mapa con los valores de sus casillas los que dibujarán una cosa u otra, así que vamos con el método dibujar de la clase mapa:</p>
<pre class="brush: python;">
def dibujar(self, screen):
	for f in range(self.fil):
		for c in range(self.col):
			if self.mapa[f][c] == 1:
				screen.blit(self.bloque, (self.rect_bloque.w*c, self.rect_bloque.h*f))
			if self.mapa[f][c] == 2 or self.mapa[f][c] == 5:
				screen.blit(self.snake, (self.rect_snake.w*c, self.rect_snake.h*f))
			if self.mapa[f][c] == 3:
				screen.blit(self.comida, (self.rect_comida.w*c, self.rect_comida.h*f))
</pre>
<p>Muy simple, recorremos el mapa usando self.fil y self.col que definimos en el primer tutorial y comprobamos el valor de la casilla y guiandonos por nuestro esquema de valores que definimos dibujamos una cosa u otra.</p>
<p>Por ejemplo, el 1 representaba un muro por lo que si la casilla vale 1 dibujamos en pantalla un sprite bloque. Especial atencion a que lo dibujo usando su rect (self.rect_bloque.w*c, self.rect_bloque.h*f) es decir que la estoy pasando donde debe colocar la esquina superior izquierda del sprite, en este caso le digo que la coordenada x del punto está en self.rect_bloque.w*c, es decir, el ancho del sprite por la columna en la que se encuentra y la coordenada y en el punto self.rect_bloque.h*f, la altura del sprite por la fila en la que se encuentra por lo que un muro en la fila 2 columna 4 con un sprite de 16&#215;16 píxeles dibujaría su esquina superior izquierda en la coordenada (16&#215;4, 16&#215;2) o lo que es lo mismo (64, 32).</p>
<p>lo único que nos queda es dibujar el mapa en nuestra bucle de la función nuevo_juego, recuerda hacerlo después de dibujar el fondo, sino no verás nada (el fondo siempre es lo primero que se dibuja):</p>
<pre class="brush: python;">
screen.blit(background_image, (0, 0))
mapa.dibujar(screen)
</pre>
<p>y si ejecutamos veremos lo siguiente:<br />
<img src="http://razonartificial.com/wp-content/uploads/2010/07/Serpiente_002.png" alt="" title="Serpiente_002" width="642" height="503" class="aligncenter size-full wp-image-444" /></p>
<p>El juego nos queda así:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

class Mapa(pygame.sprite.Sprite):
	def __init__(self, archivo):
		pygame.sprite.Sprite.__init__(self)

		self.bloque = load_image(&quot;images/bloque.png&quot;)
		self.rect_bloque = self.bloque.get_rect()

		self.snake = load_image(&quot;images/snake.png&quot;)
		self.rect_snake = self.snake.get_rect()

		self.comida = load_image(&quot;images/comida.png&quot;, True)
		self.rect_comida = self.comida.get_rect()

		self.mapa = leerMapa(archivo)
		self.fil = len(self.mapa)
		self.col = len(self.mapa[0])

	def dibujar(self, screen):
		for f in range(self.fil):
			for c in range(self.col):
				if self.mapa[f][c] == 1:
					screen.blit(self.bloque, (self.rect_bloque.w*c, self.rect_bloque.h*f))
				if self.mapa[f][c] == 2 or self.mapa[f][c] == 5:
					screen.blit(self.snake, (self.rect_snake.w*c, self.rect_snake.h*f))
				if self.mapa[f][c] == 3:
					screen.blit(self.comida, (self.rect_comida.w*c, self.rect_comida.h*f))

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

# Quita el ultimo caracter de una lista.
def quitarUltimo(lista):
	for i in range(len(lista)):
		lista[i] = lista[i][:-1]
	return lista

# Covierte una cadena en una lista.
def listarCadena(cadena):
	lista = []
	for i in range(len(cadena)):
		if cadena[i] == &quot;.&quot;:
			lista.append(0)
		if cadena[i] == &quot;#&quot;:
			lista.append(1)
		if cadena[i] == &quot;*&quot;:
			lista.append(2)
	return lista

# Lee un archivo de texto y lo convierte en una lista.
def leerMapa(archivo):
	mapa = open(archivo, &quot;r&quot;)
	mapa = mapa.readlines()
	mapa = quitarUltimo(mapa)
	for i in range(len(mapa)):
		mapa[i] = listarCadena(mapa[i])
	return mapa

# Carga una imagen a Pygame
def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

def salir(keys):
	for eventos in pygame.event.get():
		if eventos.type == QUIT:
			sys.exit(0)
		if keys[K_ESCAPE]:
			sys.exit(0)

def nuevo_juego(screen):
	background_image = load_image('images/fondo.jpg');

	clock = pygame.time.Clock()

	mapa = Mapa(&quot;mapa.txt&quot;)

	while True:
		time = clock.tick(60)
		keys = pygame.key.get_pressed()
		salir(keys)

		screen.blit(background_image, (0, 0))
		mapa.dibujar(screen)
		pygame.display.flip()

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Serpiente&quot;)

	while True:
		nuevo_juego(screen)
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/07/juego-serpiente-paso-a-paso-parte-1/" title="Juego de la serpiente paso a paso. Parte 1">Juego de la serpiente paso a paso. Parte 1</a></li><li><a href="http://razonartificial.com/2010/07/pygame-el-juego-de-la-serpiente/" title="[Pygame] El juego de la serpiente">[Pygame] El juego de la serpiente</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/SmWRkNicBrILO39Q6nOm2kZ5_HU/0/da"><img src="http://feedads.g.doubleclick.net/~a/SmWRkNicBrILO39Q6nOm2kZ5_HU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/SmWRkNicBrILO39Q6nOm2kZ5_HU/1/da"><img src="http://feedads.g.doubleclick.net/~a/SmWRkNicBrILO39Q6nOm2kZ5_HU/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/jPJu8Ta5Cgo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Juego de la serpiente paso a paso. Parte 1</title>
		<link>http://razonartificial.com/2010/07/juego-serpiente-paso-a-paso-parte-1/</link>
		<comments>http://razonartificial.com/2010/07/juego-serpiente-paso-a-paso-parte-1/#comments</comments>
		<pubDate>Sat, 17 Jul 2010 13:36:13 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Serpiente]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=436</guid>
		<description><![CDATA[Vamos a hacer paso a paso el juego de la serpiente usando Python y Pygame. La idea del juego para el que no lo conozca es una pequeña serpiente que debemos mover por una pantalla cogiendo la comida que aparece que es lo que da puntos, pero entre más comes más crece la serpiente. Manos [...]]]></description>
			<content:encoded><![CDATA[<p>Vamos a hacer paso a paso el juego de la serpiente usando Python y Pygame. La idea del juego para el que no lo conozca es una pequeña serpiente que debemos mover por una pantalla cogiendo la comida que aparece que es lo que da puntos, pero entre más comes más crece la serpiente. Manos a la obra.</p>
<p>Antes de hacer este tutorial es totalmente recomendable hacer el <a href="http://razonartificial.com/tutoriales-pygame/">tutorial del Pong</a> ya que las cosas que explique en él no las voy a volver a explicar y las daré por sabidas.</p>
<h2>Directorio Base</h2>
<p>Lo primero de todo os dejo el directorio base para trabajar que contiene todo lo necesario para hacer nuestro juego: Imágenes, tipografías y plantilla base de Pygame que ya creamos en el tutorial del pong. También contiene un txt que será el mapa de nuestro juego.</p>
<ul>
<li><a href="http://razonartificial.com/wp-content/uploads/2010/07/tuto_serpiente.zip">Descargar Tutorial Serpiente</a></li>
</ul>
<p><span id="more-436"></span></p>
<h2>La clase Mapa</h2>
<p>Al ser un juego tan simple no voy a hacer una clase para cada Sprite, sino que será la clase Mapa la que gestione todos los sprites del juego. Solo habrá 3 sprites: Uno que representa a las paredes, otro para la serpiente y otro para la comida.</p>
<p>Así que lo primero que haremos será inicializar la clase mapa y cargar nuestros gráficos con la función<strong> load_image</strong> que tenemos ya ahí.</p>
<pre class="brush: python;">
class Mapa(pygame.sprite.Sprite):
	def __init__(self, archivo):
		pygame.sprite.Sprite.__init__(self)

		self.bloque = load_image(&quot;images/bloque.png&quot;)
		self.rect_bloque = self.bloque.get_rect()

		self.snake = load_image(&quot;images/snake.png&quot;)
		self.rect_snake = self.snake.get_rect()

		self.comida = load_image(&quot;images/comida.png&quot;, True)
		self.rect_comida = self.comida.get_rect()
</pre>
<h2>El archivo mapa.txt</h2>
<p>El archivo mapa.txt será el que usemos para cargar nuestro mapa base, si abrimos el mapa.txt veremos esto:</p>
<pre># # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . * . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #</pre>
<p>Las <strong>almohadillas</strong> representan las paredes, los puntos por donde se puede pasar y el <strong>asterísco</strong> representa la cabeza de la serpiente (Ojo, los 3 caracteres a la izquierda de la cabeza de la serpiente deben ser puntos porque irá el resto del cuerpo de la serpiente).</p>
<p>Bien, necesitamos convertir este txt en una lista de Python y darle valores según el carácter, yo voy a usar la siguiente combinación para representar los elementos:</p>
<ul>
<li>Muros → 1</li>
<li>Libres → 0</li>
<li>Serpiente → 2</li>
<li>Cabeza serpiente → 5</li>
<li>Comida → 3</li>
</ul>
<p>Bueno ya teniendo un código lo que hay que hacer es convertir el mapa, lo voy a hacer a través de 3 funciones:</p>
<pre class="brush: python;">
# Quita el ultimo caracter de una lista.
def quitarUltimo(lista):
	for i in range(len(lista)):
		lista[i] = lista[i][:-1]
	return lista

# Covierte una cadena en una lista.
def listarCadena(cadena):
	lista = []
	for i in range(len(cadena)):
		if cadena[i] == &quot;.&quot;:
			lista.append(0)
		if cadena[i] == &quot;#&quot;:
			lista.append(1)
		if cadena[i] == &quot;*&quot;:
			lista.append(2)
	return lista

# Lee un archivo de texto y lo convierte en una lista.
def leerMapa(archivo):
	mapa = open(archivo, &quot;r&quot;)
	mapa = mapa.readlines()
	mapa = quitarUltimo(mapa)
	for i in range(len(mapa)):
		mapa[i] = listarCadena(mapa[i])
	return mapa
</pre>
<p>La que lee el mapa realmente es la última de todas, pero necesita las dos anteriores. Así que explico esta última y las 2 anteriores.</p>
<p>leerMapa recibe como parámetro un archivo de texto, la primera línea abre y lee el archivo, la segunda utiliza la el método readlines() que tienen los archivos abiertos y que lee las lineas de nuestro archivo. Con esto lo que tenemos es una lista que contiene unas cadenas de caracteres por cada línea de nuestro archivo (ojo que contiene al final el carácter de salto de línea también &#8220;\n&#8221;).</p>
<p>Para solucionar esto último la función <strong>quitarUltimo</strong> que se encarga de eliminar el último carácter de cada una de las cadenas de la lista. Nada complicado de ver como lo hace.</p>
<p>Bien ahora lo que necesitamos es convertir las cadanas de nuestra lista en listas con los valores que representan cada carácter, para ello recorremos la lista de cadenas y a cada una de ellas le aplicamos la función <strong>listarCadena</strong> que como vemos lo que hace es crear una lista vacía y recorrer la cadena pasada y si encuantra un punto (.) añade a la lista un 1, si encuentre una almuhadilla (#) un 2 y así con todo, finalmente retorna la nueva lista y en la función leerMapa sustituimos la cadena que había por la nueva lista. Finalmente leerMapa nos retorna el mapa perfectamente convertido a un array bidimensional.</p>
<p>Ahora lo que queda es cargarlo en nuestra clase mapa, añadimos después de la creación de Sprites lo siguiente:</p>
<pre class="brush: python;">
self.mapa = leerMapa(archivo)
self.fil = len(self.mapa)
self.col = len(self.mapa[0])
</pre>
<p>Recuerda que archivo se lo pasamos como parámetro a nuestro método __init__, es decir cuando se crea la clase. Como vez almacenamos el mapa en self.mapa y creamos también self.fil y seld.col que contiene el tamaño de las filas y columnas del mapa, muy útil para recorrer el mapa.</p>
<p>Bueno con esto ya tenemos los Sprites creadosy el mapa cargado. El juego nos queda por ahora así:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

class Mapa(pygame.sprite.Sprite):
	def __init__(self, archivo):
		pygame.sprite.Sprite.__init__(self)

		self.bloque = load_image(&quot;images/bloque.png&quot;)
		self.rect_bloque = self.bloque.get_rect()

		self.snake = load_image(&quot;images/snake.png&quot;)
		self.rect_snake = self.snake.get_rect()

		self.comida = load_image(&quot;images/comida.png&quot;, True)
		self.rect_comida = self.comida.get_rect()

		self.mapa = leerMapa(archivo)
		self.fil = len(self.mapa)
		self.col = len(self.mapa[0])

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

# Quita el ultimo caracter de una lista.
def quitarUltimo(lista):
	for i in range(len(lista)):
		lista[i] = lista[i][:-1]
	return lista

# Covierte una cadena en una lista.
def listarCadena(cadena):
	lista = []
	for i in range(len(cadena)):
		if cadena[i] == &quot;.&quot;:
			lista.append(0)
		if cadena[i] == &quot;#&quot;:
			lista.append(1)
		if cadena[i] == &quot;*&quot;:
			lista.append(2)
	return lista

# Lee un archivo de texto y lo convierte en una lista.
def leerMapa(archivo):
	mapa = open(archivo, &quot;r&quot;)
	mapa = mapa.readlines()
	mapa = quitarUltimo(mapa)
	for i in range(len(mapa)):
		mapa[i] = listarCadena(mapa[i])
	return mapa

# Carga una imagen a Pygame
def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

def salir(keys):
	for eventos in pygame.event.get():
		if eventos.type == QUIT:
			sys.exit(0)
		if keys[K_ESCAPE]:
			sys.exit(0)

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)
	background_image = load_image('images/fondo.jpg');

	clock = pygame.time.Clock()

	while True:
		time = clock.tick(60)
		keys = pygame.key.get_pressed()
		salir(keys)

		screen.blit(background_image, (0, 0))
		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/07/pygame-el-juego-de-la-serpiente/" title="[Pygame] El juego de la serpiente">[Pygame] El juego de la serpiente</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/THMg1VyBekMEaWz50AQla6y7X9E/0/da"><img src="http://feedads.g.doubleclick.net/~a/THMg1VyBekMEaWz50AQla6y7X9E/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/THMg1VyBekMEaWz50AQla6y7X9E/1/da"><img src="http://feedads.g.doubleclick.net/~a/THMg1VyBekMEaWz50AQla6y7X9E/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/KQLrPoxngqk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/juego-serpiente-paso-a-paso-parte-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Pygame] El juego de la serpiente</title>
		<link>http://razonartificial.com/2010/07/pygame-el-juego-de-la-serpiente/</link>
		<comments>http://razonartificial.com/2010/07/pygame-el-juego-de-la-serpiente/#comments</comments>
		<pubDate>Sat, 17 Jul 2010 04:29:21 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Ejemplos]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=430</guid>
		<description><![CDATA[He programado una versión del clásico juego de la serpiente usando Python y Pyagame. La idea es hacer un tutorial de como lo he hecho, como hice en su día con el pong, creo que es una buena forma de aprender ver como se hacen juegos paso a paso, por el momento aquí dejo el [...]]]></description>
			<content:encoded><![CDATA[<p>He programado una versión del clásico juego de la serpiente usando Python y Pyagame. La idea es hacer un tutorial de como lo he hecho, como hice en su día con el pong, creo que es una buena forma de aprender ver como se hacen juegos paso a paso, por el momento aquí dejo el juego para trastear con él y ver como está hecho.</p>
<p><img class="aligncenter size-full wp-image-432" title="Serpiente_001" src="http://razonartificial.com/wp-content/uploads/2010/07/Serpiente_001.png" alt="" width="642" height="503" /></p>
<p>Los gráficos la verdad es que no son ninguna belleza, parece que los programadores no servimos para el arte gráfico. Quizás se podría completar con un sistema que registre las mejores puntuaciones y el aumento de velocidad según consigas puntos, todo es cuestión de implementarlo, quizás para el tutorial le añada un sistema de puntuaciones para trabajar con archivos.</p>
<ul>
<li><a href="http://razonartificial.com/wp-content/uploads/2010/07/serpiente.zip">Descargar Serpiente</a></li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/" title="Engine XI: Creando al héroe">Engine XI: Creando al héroe</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/xiJSB4WDZTzzd5Kln3-DyQipY38/0/da"><img src="http://feedads.g.doubleclick.net/~a/xiJSB4WDZTzzd5Kln3-DyQipY38/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/xiJSB4WDZTzzd5Kln3-DyQipY38/1/da"><img src="http://feedads.g.doubleclick.net/~a/xiJSB4WDZTzzd5Kln3-DyQipY38/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/XBD767Aqer4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/pygame-el-juego-de-la-serpiente/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pack de gráficos para juegos</title>
		<link>http://razonartificial.com/2010/07/pack-de-graficos-libres/</link>
		<comments>http://razonartificial.com/2010/07/pack-de-graficos-libres/#comments</comments>
		<pubDate>Fri, 16 Jul 2010 22:11:05 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Gráficos]]></category>
		<category><![CDATA[Recursos]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=422</guid>
		<description><![CDATA[Aquí os dejo un pack de recursos gráficos muy bueno para vuestros proyectos RPG o RTS son de http://www.lostgarden.com/ y son muy buenos los tiles son de 40 x 40 y vienen para que cada cual los adapte a sus juegos, no en formato de tileset. Una captura de lo bien que se ve: Los [...]]]></description>
			<content:encoded><![CDATA[<p>Aquí os dejo un pack de recursos gráficos muy bueno para vuestros proyectos RPG o RTS son de <a href="http://www.lostgarden.com/">http://www.lostgarden.com/</a> y son muy buenos los tiles son de 40 x 40 y vienen para que cada cual los adapte a sus juegos, no en formato de tileset. Una captura de lo bien que se ve:</p>
<p style="text-align: center;"><a href="http://razonartificial.com/wp-content/uploads/2010/07/bosque.png"><img class="aligncenter size-full wp-image-423" title="bosque" src="http://razonartificial.com/wp-content/uploads/2010/07/bosque.png" alt="" width="640" height="480" /></a></p>
<p style="text-align: left;">Los gráficos traen los efectos de sombra y demás, pero estan preparados para que cada uno lo adapte a su sistema. Dejo el pack para descargar.</p>
<ul>
<li><a href="http://razonartificial.com/wp-content/uploads/2010/07/2DCircleGraphic.zip"></a><a href="http://razonartificial.com/wp-content/uploads/2010/07/2DCircleGraphic.zip">Descargar 2D Circle Graphic</a></li>
</ul>
<p><strong>Licencia de uso:</strong> http://www.lostgarden.com/2007/03/lost-garden-license.html</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/graficos-para-prototipos-de-juegos/" title="Gráficos para prototipos de juegos">Gráficos para prototipos de juegos</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/UqAOOvCUMd5ek6L32HGNTiytTNA/0/da"><img src="http://feedads.g.doubleclick.net/~a/UqAOOvCUMd5ek6L32HGNTiytTNA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/UqAOOvCUMd5ek6L32HGNTiytTNA/1/da"><img src="http://feedads.g.doubleclick.net/~a/UqAOOvCUMd5ek6L32HGNTiytTNA/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/sCI62Rms11Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/pack-de-graficos-libres/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Destacamos del foro</title>
		<link>http://razonartificial.com/2010/07/destacamos-del-foro/</link>
		<comments>http://razonartificial.com/2010/07/destacamos-del-foro/#comments</comments>
		<pubDate>Fri, 16 Jul 2010 02:25:38 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Foro]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=418</guid>
		<description><![CDATA[Para darle vida al nuevo foro y que la comunidad crezca vamos a poner cada semana no los post más destacados del foro y que pueden ser de interés para nuestros lectores. Con la inauguración destacamos: Técnicas e ideales de desarrollo de videojuegos El diseñador de juegos y el riesgo de las ideas Proyectos Hipermedia Tips de [...]]]></description>
			<content:encoded><![CDATA[<p>Para darle vida al nuevo foro y que la comunidad crezca vamos a poner cada semana no los post más destacados del foro y que pueden ser de interés para nuestros lectores.</p>
<p>Con la inauguración destacamos:</p>
<ul>
<li><a href="http://razonartificial.com/foro/index.php/topic,4.0.html">Técnicas e ideales de desarrollo de videojuegos</a></li>
<li><a href="http://razonartificial.com/foro/index.php/topic,5.0.html">El diseñador de juegos y el riesgo de las ideas</a></li>
<li><a href="http://razonartificial.com/foro/index.php/topic,7.0.html">Proyectos Hipermedia</a></li>
<li><a href="http://razonartificial.com/foro/index.php/topic,6.0.html">Tips de programación de videojuegos</a></li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/repositorio-en-github-para-el-engine-rpg/" title="Repositorio en github para el Engine-RPG">Repositorio en github para el Engine-RPG</a></li><li><a href="http://razonartificial.com/2010/07/futuro-del-engine-y-los-tutoriales/" title="Futuro del Engine y los tutoriales">Futuro del Engine y los tutoriales</a></li><li><a href="http://razonartificial.com/2010/07/razon-artificial-crece/" title="Razón Artificial Crece">Razón Artificial Crece</a></li><li><a href="http://razonartificial.com/2010/07/%c2%bfuna-comunidad/" title="¿Una comunidad?">¿Una comunidad?</a></li><li><a href="http://razonartificial.com/2010/06/opiniones-sobre-division/" title="Opiniones sobre división">Opiniones sobre división</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/JNIatzNzIkFhCMN_0_waVs8SWGI/0/da"><img src="http://feedads.g.doubleclick.net/~a/JNIatzNzIkFhCMN_0_waVs8SWGI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/JNIatzNzIkFhCMN_0_waVs8SWGI/1/da"><img src="http://feedads.g.doubleclick.net/~a/JNIatzNzIkFhCMN_0_waVs8SWGI/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/fmeR8zqz9E4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/destacamos-del-foro/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Razón Artificial Crece</title>
		<link>http://razonartificial.com/2010/07/razon-artificial-crece/</link>
		<comments>http://razonartificial.com/2010/07/razon-artificial-crece/#comments</comments>
		<pubDate>Wed, 14 Jul 2010 19:44:50 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=414</guid>
		<description><![CDATA[Ayer lo consultaba con vosotros, para ver vuestra opinión, pero lo cierto es que el proyecto de hacer crecer Razón Artificial de Blog a comunidad lleva tiempo gestandose, por este motivo no he actualizado el blog estas semanas. Las novedades son las siguientes: Razón Artificial amplia su temática al desarrollo de videojuegos, la intención es [...]]]></description>
			<content:encoded><![CDATA[<p>Ayer lo consultaba con vosotros, para ver vuestra opinión, pero lo cierto es que el proyecto de hacer crecer Razón Artificial de Blog a comunidad lleva tiempo gestandose, por este motivo no he actualizado el blog estas semanas.</p>
<p>Las novedades son las siguientes:</p>
<ul>
<li>Razón Artificial amplia su temática al desarrollo de videojuegos, la intención es cubrir todas las áreas del desarrollo y no solo la parte de programación como veníamos haciendo hasta ahora, trabajaremos con Diseño, gráficos, audio y por supuesto seguiremos con la programación.</li>
<li>Abrimos un foro de debate. podéis acceder a través de http://razonartificial.com/foro/ en el se encontrará mucha mas información adicional al blog y los usuarios podrán participar y publicar sus propios temas,  tutoriales, proyectos, dudas y demás, para entre todos tener un lugar de desarrollo de videojuegos.</li>
<li>Cambiamos el diseño acorde a la nueva filosofía de la web. Sigue siendo un tema limpio y claro.</li>
<li>Intentaré publicar más a menudo y lo más destacado del foro podrá verse en la portada del blog.</li>
</ul>
<p>Bueno espero que los que han seguido el blog me apoyen en esta nueva etapa de la web y que participen en lo posible, cada uno con lo que pueda aportar. Yo seguiré escribiendo tutoriales y artículos que considere útiles.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/repositorio-en-github-para-el-engine-rpg/" title="Repositorio en github para el Engine-RPG">Repositorio en github para el Engine-RPG</a></li><li><a href="http://razonartificial.com/2010/07/futuro-del-engine-y-los-tutoriales/" title="Futuro del Engine y los tutoriales">Futuro del Engine y los tutoriales</a></li><li><a href="http://razonartificial.com/2010/07/destacamos-del-foro/" title="Destacamos del foro">Destacamos del foro</a></li><li><a href="http://razonartificial.com/2010/07/%c2%bfuna-comunidad/" title="¿Una comunidad?">¿Una comunidad?</a></li><li><a href="http://razonartificial.com/2010/06/opiniones-sobre-division/" title="Opiniones sobre división">Opiniones sobre división</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/DK5DnDxjBcgdHvXRMxTcQyryz1U/0/da"><img src="http://feedads.g.doubleclick.net/~a/DK5DnDxjBcgdHvXRMxTcQyryz1U/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/DK5DnDxjBcgdHvXRMxTcQyryz1U/1/da"><img src="http://feedads.g.doubleclick.net/~a/DK5DnDxjBcgdHvXRMxTcQyryz1U/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/J9uwdM28wGc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/razon-artificial-crece/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>¿Una comunidad?</title>
		<link>http://razonartificial.com/2010/07/%c2%bfuna-comunidad/</link>
		<comments>http://razonartificial.com/2010/07/%c2%bfuna-comunidad/#comments</comments>
		<pubDate>Tue, 13 Jul 2010 19:57:16 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=410</guid>
		<description><![CDATA[Muchos lleváis tiempo esperando que publique nuevas entrega de nuestro tutorial del Engine, otros que siga con el de Pygame básico y algunos que continúe con el de Python. A todos vosotros deciros que poco a poco saldrán mas tutoriales y entregas, que n0 voy a dejarlo. He estado trabajando en el engine aunque no [...]]]></description>
			<content:encoded><![CDATA[<p>Muchos lleváis tiempo esperando que publique nuevas entrega de nuestro tutorial del Engine, otros que siga con el de Pygame básico y algunos que continúe con el de Python. A todos vosotros deciros que poco a poco saldrán mas tutoriales y entregas, que n0 voy a dejarlo. He estado trabajando en el engine aunque no halla publicado nuevos tutoriales porque quiero poder ponerlo de la mejor forma y cuando estás desarrollando algo muchas veces hay que rectificar código cuando estás más avanzado y para evitar volver esto un lío prefiero publicar nuevas entregas cuando todo está más sólido.</p>
<p>El motivo de este post viene para otra consulta, este blog a crecido muy rápido, apenas tiene unos 6 meses de vida y aunque no hay muchos post pienso que lo que hay no son noticias banales sino cosas prácticas y útiles. Hoy me plante ampliar razón artificial a una comunidad. Los comento, la idea es mantener el blog y seguir publicando tutoriales y posiblemente ampliarlo hacia el desarrollo de videojuegos con nuevos temas. Pero también he pensado en abrir un foro de debate en el que vosotros podáis mostrar vuestros proyectos, dudas, códigos y demás cosas relacionadas, podáis también publicar tutoriales y demás que puedan mostrarse en el blog.</p>
<p>Bueno espero vuestros comentarios sobre la idea, ¿Os gustaría que Razón Artificial fuera una comunidad y no solo un blog?</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/repositorio-en-github-para-el-engine-rpg/" title="Repositorio en github para el Engine-RPG">Repositorio en github para el Engine-RPG</a></li><li><a href="http://razonartificial.com/2010/07/futuro-del-engine-y-los-tutoriales/" title="Futuro del Engine y los tutoriales">Futuro del Engine y los tutoriales</a></li><li><a href="http://razonartificial.com/2010/07/destacamos-del-foro/" title="Destacamos del foro">Destacamos del foro</a></li><li><a href="http://razonartificial.com/2010/07/razon-artificial-crece/" title="Razón Artificial Crece">Razón Artificial Crece</a></li><li><a href="http://razonartificial.com/2010/06/opiniones-sobre-division/" title="Opiniones sobre división">Opiniones sobre división</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/sizVDlnPW5HZwCwcZCmyMxL2u5k/0/da"><img src="http://feedads.g.doubleclick.net/~a/sizVDlnPW5HZwCwcZCmyMxL2u5k/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/sizVDlnPW5HZwCwcZCmyMxL2u5k/1/da"><img src="http://feedads.g.doubleclick.net/~a/sizVDlnPW5HZwCwcZCmyMxL2u5k/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/PkvC9R9on6A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/07/%c2%bfuna-comunidad/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Engine XI: Creando al héroe</title>
		<link>http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/</link>
		<comments>http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/#comments</comments>
		<pubDate>Mon, 14 Jun 2010 17:44:29 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RPG]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=393</guid>
		<description><![CDATA[Ya tenemos listo nuestro mapa, preparado para ser puesto en pantalla, pero en un juego RPG la cámara sigue al héroe, es decir, se ve el trozo de mapa alrededor del héroe, por eso necesitamos antes de representar el mapa a nuestro héroe para poder representar la parte que necesitamos del mapa. Cortando un chareset Un charaset es una [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" title="engine" width="190" height="150" class="alignright size-full wp-image-292" /></p>
<p>Ya tenemos listo nuestro mapa, preparado para ser puesto en pantalla, pero en un juego RPG la cámara sigue al héroe, es decir, se ve el trozo de mapa alrededor del héroe, por eso necesitamos antes de representar el mapa a nuestro héroe para poder representar la parte que necesitamos del mapa.</p>
<h2>Cortando un chareset</h2>
<p>Un charaset es una imagen que contiene todas las posiciones de un personaje, que superpuestas crean una animación, como vale más una imagen que mil palabras dejo un ejemplo.</p>
<p><img class="aligncenter size-full wp-image-394" title="chara" src="http://razonartificial.com/wp-content/uploads/2010/06/chara.png" alt="" width="128" height="192" />Como vemos, este simula el movimiento de caminar en 4 direcciones, se podría hacer uno de 8 direcciones, pero el nuestro caminará tan solo en cuatro.</p>
<p>Vale lo que tenemos que hacer es parecido a cuando cortamos el tileset, cortat cada uno de los frames de nuestro charaset y almacenarlos en una array, esta vez será bidimensional, así que con solo ir cambiando los índices del array podemos mostrar un frame u otro.<br />
<span id="more-393"></span></p>
<p>Creamos una funcion en nuestro archivo funciones.py debajo de la función de cortar tilesets.</p>
<pre class="brush: python;">
# Corta un chara en las fil y col indicadas. Array Bidimensional.
def cortar_chara(ruta, fil, col):
	image = load_image(ruta, True)
	rect = image.get_rect()
	w = rect.w / col
	h = rect.h / fil
	sprite = range(fil)
	for i in range(fil):
		sprite[i] = range(col)

	for f in range(fil):
		for c in range(col):
			sprite[f][c] = image.subsurface((rect.left, rect.top, w, h))
			rect.left += w
		rect.top += h
		rect.left = 0

	return sprite
</pre>
<p>Como vemos muy parecida a la de cortar tilesets, pero esta vez a parte de almacenarlo en un array bidimensional, también le decimos cuantas filas y columnas tiene nuestro charaset. Esto lo hacemos así para que sea mas universal y podamos almacenar todo tipo de charas de cualquier tamaño, solo debemos especificas cuantas filas y columnas y el se encargará de cortarlo.</p>
<h2>La clase Actors</h2>
<p>Vamos a crear el fichero que se encargará de gestionar a nuestro héroe, ya sabes hacemos una copia del archivo plantilla.py y creamos el archivo <strong>actors.py</strong>. y creamos la clase Actors.</p>
<pre class="brush: python;">
class Actor:
	def __init__(self, pos):
		self.pos = pos
		self.chara = cortar_chara(&amp;quot;graphics/charasets/chara.png&amp;quot;, 4, 4)

		self.image = self.chara[0][0]
		self.rect = self.image.get_rect()

	def dibujar(self, screen):
		screen.blit(self.image, self.rect)
</pre>
<p>De momento para el método de inicialización recibe la posición del charaset. en un futuro debería recibir otra como la imagen y demás, pero ya habrá tiempo de generalizar el código cuando este la base.</p>
<p>Almacenamos la posición inicial en self.pos y creamos un array bidimensional llamado self.chara con la función que acabamos de crear. En nuestro caso tiene 4 filas y 4 columnas.</p>
<p>Luego definimos que frame está activo en self.image en este caso y a modo de prueba cogemos el [0, 0] es decir el de la primera fila y la primera columna de nuestro chara. A continuación obtenemos el rect de esa imagen.</p>
<p>Por último hacemos a modo de esbozo el método dibujar que será el encargado de gestionar el dibujado de nuestro chara. Por ahora es muy simple y solo muestra en pantalla el chara. Atención a que recibe como parámetro la variable screen, esto es nuestra pantalla, porque debe saber donde tiene que dibujarlo.</p>
<h2>Dibujando en pantalla</h2>
<p>Hasta ahora código, teoría y mas código, alguna salida en consola, pero nuestra ventana sigue en negro. Bueno para los desesperados vamos a mostrar nuestro chara en pantalla para ver que realmente funciona lo que estamos haciendo.</p>
<p>nos vamos a nuestro engine.py, el archivo principal y le añadimos lo siguiente.</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

from maps import *
from actors import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def salir():
	keys = pygame.key.get_pressed()
	for eventos in pygame.event.get():
		if eventos.type == QUIT:
			sys.exit(0)
		if keys[K_ESCAPE]:
			sys.exit(0)

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&amp;quot;Engine RPG&amp;quot;)

	clock = pygame.time.Clock()

	mapa = Mapa(&amp;quot;bosque.tmx&amp;quot;)
	heroe = Actor(mapa.start)

	while True:
		time = clock.tick(60)
		salir()

		heroe.dibujar(screen)
		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>Primero importamos nuestro módulo actors después del módulo maps. Creamos un objeto Actor llamado heroe debajo del objeto Mapa. Atención a que tiene que ser despues y no antes porque recibe como parámentro mapa.start como la posición inicial y esta esta dentro de la clase Mapa. por último tenemos que llamar a su método dibujar dentro del bucle principal con heroe.dibujar(screen).</p>
<p>Debería mostrarse el primer frame de nuestro chara en la parte superior izquierda de la pantalla.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li><li><a href="http://razonartificial.com/2010/04/haciendo-un-engine-para-juegos-con-python-y-pygame/" title="Haciendo un engine para juegos">Haciendo un engine para juegos</a></li><li><a href="http://razonartificial.com/2010/06/engine-x-la-clase-mapa-iii/" title="Engine X: La clase mapa III">Engine X: La clase mapa III</a></li><li><a href="http://razonartificial.com/2010/06/engine-ix-cargando-el-tileset/" title="Engine IX: Cargando el tileset">Engine IX: Cargando el tileset</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/DS51mctnvwHAUSptyea0reiR7r0/0/da"><img src="http://feedads.g.doubleclick.net/~a/DS51mctnvwHAUSptyea0reiR7r0/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/DS51mctnvwHAUSptyea0reiR7r0/1/da"><img src="http://feedads.g.doubleclick.net/~a/DS51mctnvwHAUSptyea0reiR7r0/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/j6cWGFUmwDM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>Engine X: La clase mapa III</title>
		<link>http://razonartificial.com/2010/06/engine-x-la-clase-mapa-iii/</link>
		<comments>http://razonartificial.com/2010/06/engine-x-la-clase-mapa-iii/#comments</comments>
		<pubDate>Sat, 12 Jun 2010 15:40:06 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RPG]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=388</guid>
		<description><![CDATA[Ya tenemos una array bidimensional llamada self.capas que contiene unos números que se corresponde con los tiles que ocupa y tenemos un array unidimensional llamado self.tileset que contiene los sptites de nuestro tilesets (los tiles). Pues el siguiente paso será crear un array bidimensional igual a self.capas, pero sustituyendo los valores por nuestros sprites que [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-292" title="engine" src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" width="190" height="150" /></p>
<p>Ya tenemos una array bidimensional llamada self.capas que contiene unos números que se corresponde con los tiles que ocupa y tenemos un array unidimensional llamado self.tileset que contiene los sptites de nuestro tilesets (los tiles). Pues el siguiente paso será crear un array bidimensional igual a self.capas, pero sustituyendo los valores por nuestros sprites que tenemos en self.tileset.</p>
<p>Esto lo haremos creando la variable de clase self.mapa y lo hacemos con el siguiente método de la clase mapa:<br />
<span id="more-388"></span></p>
<pre class="brush: python;">
def crear_mapa(self):
	self.mapa = self.capas
	for i in range(len(self.capas)):
		for f in range(self.height):
			for c in range(self.width):
				if self.capas[i][f][c]:
					self.mapa[i][f][c] = self.tileset[self.capas[i][f][c]]
				else:
					self.mapa[i][f][c] = None
</pre>
<p>Lo primero que hace el metodo es una copia exacta de self.capas en self.mapa, así ya tenemos nuestra array col los valores que hay que sustituir. A continuación empezamos a recorres nuestra array tridimensional, para hacerlo para casa capa, con la variable i recorremos las capas y con las variables f y c las filas y las columnas (observad que sacamos los valores de los datos que extraemos del mapa. y a continuación tenemos un if. Si el valor de esa celda es distinto de none hace lo siguiente.</p>
<pre class="brush: python;">
self.mapa[i][f][c] = self.tileset[self.capas[i][f][c]]
</pre>
<p>osea sustituye el valor de la variable self.mapa de la casilla que este mirando por self.tileset[indice] donde indice es el valor de self.capa en se lugar, por tanto si en nuestro mapa, teniamos que hay iba el tile número 5 le estamos diciendo que en self.mapa[i][f][ c ] ponga el sprite self.tileset[5].</p>
<p>Si no se entiende decidmelo y lo explico mejor en los comentarios. Por ultimo si no hay nada en ese cuadro añadimos el valor None.</p>
<p>Con esto ya tenemos nuestro mapa creado y estaríamos listos para mostrarlo en pantalla, pero ahora hay que crear la camára, no se puede mostrar el mapa entero pues no cabe en pantalla, ya veremos como hacerlo.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/" title="Engine XI: Creando al héroe">Engine XI: Creando al héroe</a></li><li><a href="http://razonartificial.com/2010/06/engine-ix-cargando-el-tileset/" title="Engine IX: Cargando el tileset">Engine IX: Cargando el tileset</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/1tN7dh8xGRq_ZlhDkAroQy_FHfk/0/da"><img src="http://feedads.g.doubleclick.net/~a/1tN7dh8xGRq_ZlhDkAroQy_FHfk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/1tN7dh8xGRq_ZlhDkAroQy_FHfk/1/da"><img src="http://feedads.g.doubleclick.net/~a/1tN7dh8xGRq_ZlhDkAroQy_FHfk/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/S8oc5qoR3d0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/06/engine-x-la-clase-mapa-iii/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Engine IX: Cargando el tileset</title>
		<link>http://razonartificial.com/2010/06/engine-ix-cargando-el-tileset/</link>
		<comments>http://razonartificial.com/2010/06/engine-ix-cargando-el-tileset/#comments</comments>
		<pubDate>Sat, 12 Jun 2010 14:52:41 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RPG]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=376</guid>
		<description><![CDATA[Antes de empezar con este tema he ordenado un poco el código para que esté todo bien estructurado desde el principio que sino luego es liante saber donde está cada cosa, hay rutinas y funciones que usaremos a menudo, como las que usaremos para cargar imágenes sonidos, etc. Por eso he pensado que sería mejor [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" title="engine" width="190" height="150" class="alignright size-full wp-image-292" /></p>
<p>Antes de empezar con este tema he ordenado un poco el código para que esté todo bien estructurado desde el principio que sino luego es liante saber donde está cada cosa, hay rutinas y funciones que usaremos a menudo, como las que usaremos para cargar imágenes sonidos, etc. Por eso he pensado que sería mejor tener todas estas funciones de uso genérico en un fichero llamado <strong>funciones.py</strong> y ordenarlas por temas y según en que módulo de nuestro engine nos haga falta una u otra cargarla desde ahí.</p>
<p><span id="more-376"></span></p>
<p>Por tanto nuestro maps.py nos queda así:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import pygame
from pygame.locals import *
from xml.dom import minidom, Node

from funciones import *
from engine import WIDTH, HEIGHT

# Clases
# ---------------------------------------------------------------------

class Mapa:
	def __init__(self, nombre):
		self.nombre = nombre
		self.capas = []

		self.cargar_mapa() # Inicializa los valores desde el xml.

	# Extrae valores mapa desde XML.
	def cargar_mapa(self):
		xmlMap = minidom.parse(&quot;maps/&quot;+self.nombre)
		nPrincipal = xmlMap.childNodes[0]

		# Tamaño mapa
		self.width = int(nPrincipal.attributes.get(&quot;width&quot;).value)
		self.height = int(nPrincipal.attributes.get(&quot;height&quot;).value)

		for i in range(len(nPrincipal.childNodes)):
			if nPrincipal.childNodes[i].nodeType == 1:
				if nPrincipal.childNodes[i].nodeName == &quot;tileset&quot;:
					if nPrincipal.childNodes[i].attributes.get(&quot;name&quot;).value != &quot;config&quot;:
						width = nPrincipal.childNodes[i].attributes.get(&quot;tilewidth&quot;).value
						height = nPrincipal.childNodes[i].attributes.get(&quot;tileheight&quot;).value
						nombre = nPrincipal.childNodes[i].childNodes[1].attributes.get(&quot;source&quot;).value
						nombre = extraer_nombre(nombre)
						self.tileset = nombre
					self.tam_tiles = (int(width), int(height))
				if nPrincipal.childNodes[i].nodeName == &quot;layer&quot;:
					if  nPrincipal.childNodes[i].attributes.get(&quot;name&quot;).value != &quot;colisiones&quot;:
						layer = nPrincipal.childNodes[i].childNodes[1].childNodes[0].data.replace(&quot;\n&quot;, &quot;&quot;).replace(&quot; &quot;, &quot;&quot;)
						layer = decodificar(layer) # Decodifica la lista
						layer = convertir(layer, self.width) # Convierta en array bidimensional
						self.capas.append(layer)
				if nPrincipal.childNodes[i].nodeName == &quot;objectgroup&quot;:
					x = nPrincipal.childNodes[i].childNodes[1].attributes.get(&quot;x&quot;).value
					y = nPrincipal.childNodes[i].childNodes[1].attributes.get(&quot;y&quot;).value
					self.start = (int(x), int(y))

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

# Convierta una array unidimensional en una bidimensional.
def convertir(lista, col):
	nueva = []
	for i in range(0, len(lista), col):
		nueva.append(lista[i:i+col])
	return nueva

# Extra el nombre de un archivo de una ruta.
def extraer_nombre(ruta):
	a = -1
	for i in range(len(ruta)):
		if ruta[i] == &quot;/&quot; or ruta[i] == &quot;\\&quot;:
			a = i
	if a == -1:
		return ruta
	return ruta[a+1:]

# ---------------------------------------------------------------------

def main():
	return 0

if __name__ == '__main__':
	main()
</pre>
<p>y tenemos un archivo funciones.py de la siguiente manera:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import base64
import gzip
import StringIO
import pygame
from pygame.locals import *

# Mapas
# ---------------------------------------------------------------------

def decodificar(cadena):
	# Decodificar.
	cadena = base64.decodestring(cadena)

	# Descomprimir.
	copmressed_stream = StringIO.StringIO(cadena)
	gzipper = gzip.GzipFile(fileobj=copmressed_stream)
	cadena = gzipper.read()

	# Convertir.
	salida = []
	for idx in xrange(0, len(cadena), 4):
		val = ord(str(cadena[idx])) | (ord(str(cadena[idx + 1])) &lt;&lt; 8) | \
		(ord(str(cadena[idx + 2])) &lt;&lt; 16) | (ord(str(cadena[idx + 3])) &lt;&lt; 24)
		salida.append(val)

	return salida

# ---------------------------------------------------------------------

# Pygame
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------
</pre>
<h2>Cortando el tileset</h2>
<p>Bien ahora necesitamos coger nuestra imagen de tileset, cortar los tiles que la componen y almacenarlos en un array unidimensional y ese índice coincidirá con el que almacena nuestro archivo mapa.</p>
<p>Primero que nada necesitamos una función para la carga de imágenes en Pygame, ya escribimos una bastante buena en el tutorial de Pygame y esa es la que utilizaremos.</p>
<pre class="brush: python;">
# Carga una imagen transparencia y color tranasparente opcionales.
def load_image(filename, transparent=False, pixel=(0,0)):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at(pixel)
                image.set_colorkey(color, RLEACCEL)
        return image
</pre>
<p>Esta funciión va en nuestro archivo funciones.py pues desde todos lados de nuestro engine vamos a necesitar cargar imágenes, atención al archivo funciones.py que dejé arriba que importa pygame, necesario para esta función y otras.</p>
<p>Bien ya que tenemos la forma de cargar imágenes con python y pygame estamos listos para cortar nuestro tileset. Añadimos una nueva función al funciones.py</p>
<pre class="brush: python;">
# Corta un tilest y lo almacena en un array unidimensional.
def cortar_tileset(ruta, (w, h)):
	image = load_image(ruta, True)
	rect = image.get_rect()
	col = rect.w / w
	fil = rect.h / h
	sprite = [None]

	for f in range(fil):
		for c in range(col):
			sprite.append(image.subsurface((rect.left, rect.top, w, h)))
			rect.left += w
		rect.top += h
		rect.left = 0

	return sprite
</pre>
<p>Bien analicemos. Recibe 2 parámetros, la ruta del tileset y una tupla (w, h) que es el ancho y el alto de nuestros tiles, recuerda que el tileset que estoy usando de ejemplo usamos tiles de 40&#215;40, pero que lo común es encontrar en internet tilesets con tiles de 32&#215;32. De todas maneras nuestro engine se adapta a cualquier tamaño.</p>
<p>A continuación Carga la imagen con nuestra función anterior estableciendo que tiene color transparente y como no definimos de que pixel lo toma pues lo tomará del pixel (0, 0) Por eso es muy importante que nuestros tilesets para este engine el primer tile sea del color que vamos a usar como transparente (un buen color es el (255, 0, 255) que es un rosa intenso muy poco común en las paletas).</p>
<p>La siguiente línea obtiene el rect de la imagen para poder manipularla. A continuación creamos dos variables fil y col que las obtenemos de dividir el ancho y alto del tileset por el ancho y el alto de los tiles, por ejemplo, nuestro tileset tiene de ancho 320px (lo obtenemos con rect.w) y lo dividimos entre w (recuerda que lo recibe como parámetro y en nuestro caso vale 40) 320/40 nos da 8 que es el numero de columnas que hay en nuestro tileset. Lo mismo para el alto y sacar las filas.</p>
<p>A continuación creamos la array sptrite que contendrá nuestro tileset, una lista unidimensional. Observa que tiene un valor nuestra lista none, ¿Por qué esto? Pues veras nuestro mapa guarda las posiciones de los tiles a partir del 1 y el 0 lo toma como que no hay ningún tile en ese cuadro del mapa, es por esto que para que coincidan los índices el valor 0 de nuestro tileset contendrá none, es decir, nada.</p>
<p>luego recorremos las filas y columnas de nuestro tileset y vamos añadiendo al final de nuestra array sprite una subsurfase, ¿Qué es esto? Pues una imagen que se obtiene a partir de otra, es decir, recortamos de una mas grande un trozo de ella y la guardamos. Mirad el bucle y lo entenderéis, es bueno que vayas sustituyendo las variables por los valores de ejmplo para ver cuanto vale cada cosa en cada momento y ver como funciona.</p>
<p>Con esto ya tenemos un array unidimensional que tiene las imágenes de nuestros tiles. Hacemos que la función retorne esta lista.</p>
<p>Ahora hay que usarla en nuestro archivo maps.py Añadimis la siguiente línea en el método init de la clase  mapa, justo después de cargar el mapa</p>
<pre class="brush: python;">
self.tileset = cortar_tileset(&quot;graphics/tilesets/&quot;+self.tileset, self.tam_tiles)
</pre>
<p>Como ves le pasamos valores que extraímos de nuestro mapa, el nombre del tileset (Ahora vemos lo que explique de que solo necesitábamos el nombre del mapa porque la ruta ya se la dábamos nosotros) y le pasamos la tupla self.tam_tiles que en nuestro caso vale (40, 40).</p>
<p>Ya no podemos probar la clase mapa dentro del módulo mapa, sino que debemos de hacerlo en el archivo principal, engine.py esto es porque al estar ya tratando con pygame y conversiones de imagen, Pygame necesita saber cosas como la resolución o la profundidad de color del ordenador para convertir las imágenes.</p>
<p>Basta con importar el archivo maps.py en engine.py</p>
<pre class="brush: python;">
from maps import *
</pre>
<p>y añadir debajo de la carga del reloj, antes del empezar el bucle del juego:</p>
<pre class="brush: python;">
clock = pygame.time.Clock()

mapa = Mapa(&quot;bosque.tmx&quot;)
print mapa.tileset
</pre>
<p>Con esto cargamos el mapa, en este caso el mío se llama bosque.tmx y con print mapa.tileset podemos ver una lista de sprites que guarda nuestro tileset, atendemos como el primer valor es None y el resto ya es los tiles de nuestro tileset.</p>
<p>Puede que este tutorial haya sido algo lioso por numerosos cambios que hemos hecho, así que dejo para descargar el proyecto como lo llevo hasta ahora, incluyo todo menos el tiled que cada uno debe usar su versión y añadirla a la carpeta.</p>
<ul>
<li><a href='http://razonartificial.com/wp-content/uploads/2010/06/engine.zip'>Descargar Proyecto</a></li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/" title="Engine XI: Creando al héroe">Engine XI: Creando al héroe</a></li><li><a href="http://razonartificial.com/2010/06/engine-x-la-clase-mapa-iii/" title="Engine X: La clase mapa III">Engine X: La clase mapa III</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/5W-pZocu4vIhtj66V86zWogEHC4/0/da"><img src="http://feedads.g.doubleclick.net/~a/5W-pZocu4vIhtj66V86zWogEHC4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/5W-pZocu4vIhtj66V86zWogEHC4/1/da"><img src="http://feedads.g.doubleclick.net/~a/5W-pZocu4vIhtj66V86zWogEHC4/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/Mv0UpSMxbao" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/06/engine-ix-cargando-el-tileset/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Engine VIII: La clase Mapa II</title>
		<link>http://razonartificial.com/2010/06/engine-viii-la-clase-mapa-ii/</link>
		<comments>http://razonartificial.com/2010/06/engine-viii-la-clase-mapa-ii/#comments</comments>
		<pubDate>Fri, 11 Jun 2010 21:35:15 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RPG]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=367</guid>
		<description><![CDATA[Por ahora hemos conseguido tener una forma de hacer mapas y extraer su información del archivo XML para poder manejarla con Python, en el anterior tutorial quizás no quedo claro como almecenamos los tiles del mapa y en este tutorial quiero dejar claro como lo hacemos pues es clave para entender la representación del mapa. [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" title="engine" width="190" height="150" class="alignright size-full wp-image-292" /></p>
<p>Por ahora hemos conseguido tener una forma de hacer mapas y extraer su información del archivo XML para poder manejarla con Python, en el anterior tutorial quizás no quedo claro como almecenamos los tiles del mapa y en este tutorial quiero dejar claro como lo hacemos pues es clave para entender la representación del mapa.</p>
<p>A través del método cargar_mapa hemos extraído muchos valores de nuestro XML, que podemos visualizar con unos cuantos prints, pero el más importante de  ellos es el valor de self.capas que es un array tridimensional, es una lista que en su interior contiene todas las listas de las capas de nuestro mapa por orden, es decir, primero la de más abajo, luego la siguiente y así hasta la superior. Esta variable no contiene las listas de objetos, ojo, solo las de tilesets. Si imprimimos el tamaño de nuestra lista veremos que el valor devuelto es 3 porque nuestro mapa esta compuesto de 3 capas.</p>
<p><span id="more-367"></span></p>
<pre class="brush: python;">
def main():
	mapa = Mapa(&quot;bosque.tmx&quot;)
	print len(mapa.capas)
	return 0
</pre>
<p>cada una de estas 3 listas esta a su ve compuesta en un array bidimensional de filas y columnas, que representan a todo nuestro mapa y a los tileset que hay en esa posición, veamos.</p>
<pre class="brush: python;">
def main():
	mapa = Mapa(&quot;bosque.tmx&quot;)
	print mapa.capas[0]
	return 0
</pre>
<p>como ves si imprimimos el primer valor de la lista nos muestra un array bidimensional que contiene unos valores enteros, si miráis vuestro tileset veréis que ese valor se corresponde corresponde con el cuadro de tile de nuestro tileset. por ejemplo, si estás usando el tileset que he subido y tengo toda mi capa inferior cubierta de hierba veremos que nuestra lista arroja una gran capa de 9 y si miramos nuestro tileset veremos que el tile hierba ocupa la posición 9.</p>
<p>Observemos que el tileset se almacena en un array unidimensional, una lista de tiles que es nuestra paleta. En el siguiente tutorial crearemos esa paleta a partir de nuestro tileset.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/" title="Engine XI: Creando al héroe">Engine XI: Creando al héroe</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li><li><a href="http://razonartificial.com/2010/04/haciendo-un-engine-para-juegos-con-python-y-pygame/" title="Haciendo un engine para juegos">Haciendo un engine para juegos</a></li><li><a href="http://razonartificial.com/2010/07/video-con-los-avances-del-nuevo-engine/" title="Video con los avances del nuevo engine">Video con los avances del nuevo engine</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/9Ve9hNJws4VxaXk75tKRAZW5QlI/0/da"><img src="http://feedads.g.doubleclick.net/~a/9Ve9hNJws4VxaXk75tKRAZW5QlI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/9Ve9hNJws4VxaXk75tKRAZW5QlI/1/da"><img src="http://feedads.g.doubleclick.net/~a/9Ve9hNJws4VxaXk75tKRAZW5QlI/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/e2MqYheXzFY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/06/engine-viii-la-clase-mapa-ii/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Opiniones sobre división</title>
		<link>http://razonartificial.com/2010/06/opiniones-sobre-division/</link>
		<comments>http://razonartificial.com/2010/06/opiniones-sobre-division/#comments</comments>
		<pubDate>Fri, 11 Jun 2010 20:03:11 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=365</guid>
		<description><![CDATA[Últimamente me he sorprendido a mi mismo escribiendo demasiado acerca de creación de videojuegos, pygame, engines, rpg, etc. Y aunque tiene parte de relación, no son los temas para los que tenía pensado el blog en un principio. Se que muchos de ustedes me siguen por los temas de Inteligencia Artificial y muchos otros por [...]]]></description>
			<content:encoded><![CDATA[<p>Últimamente me he sorprendido a mi mismo escribiendo demasiado acerca de creación de videojuegos, pygame, engines, rpg, etc. Y aunque tiene parte de relación, no son los temas para los que tenía pensado el blog en un principio. Se que muchos de ustedes me siguen por los temas de Inteligencia Artificial y muchos otros por los temas de Pygame y los videojuegos.</p>
<p>Como este segundo tema también me gusta, había pensado en separarlo de este blog y hacer uno dedicado a la creación y desarrollo de videojuegos y dejar este para lo que era en un principio, la IA, la robótica y demás temas. ¿Qué opinan ustedes? Mejor la división, mejor todo aquí. Se que tengo gente que me lee, pero nunca comenta este es el momento que pido que opinen, muchas gracias.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/repositorio-en-github-para-el-engine-rpg/" title="Repositorio en github para el Engine-RPG">Repositorio en github para el Engine-RPG</a></li><li><a href="http://razonartificial.com/2010/07/futuro-del-engine-y-los-tutoriales/" title="Futuro del Engine y los tutoriales">Futuro del Engine y los tutoriales</a></li><li><a href="http://razonartificial.com/2010/07/destacamos-del-foro/" title="Destacamos del foro">Destacamos del foro</a></li><li><a href="http://razonartificial.com/2010/07/razon-artificial-crece/" title="Razón Artificial Crece">Razón Artificial Crece</a></li><li><a href="http://razonartificial.com/2010/07/%c2%bfuna-comunidad/" title="¿Una comunidad?">¿Una comunidad?</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/_wBG-W-UiObn0HgVkr8ERsk3joQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/_wBG-W-UiObn0HgVkr8ERsk3joQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/_wBG-W-UiObn0HgVkr8ERsk3joQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/_wBG-W-UiObn0HgVkr8ERsk3joQ/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/LX-KymwAnlM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/06/opiniones-sobre-division/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Engine VII: La clase Mapa I</title>
		<link>http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/</link>
		<comments>http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 15:07:41 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Map Editor]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RPG]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=354</guid>
		<description><![CDATA[Bien ya tenemos generado nuestro mapa de pruebas, ahora necesitamos cargarlo en Python, los próximos artículos van dedicados a interpretar los datos en Python y la manera de almacenar el mapa. Para empezar vamos a hacer una copia de nuestra plantilla con el nombre de maps.py que es el archivo que va a contener todo [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" title="engine" width="190" height="150" class="alignright size-full wp-image-292" /></p>
<p>Bien ya tenemos generado nuestro mapa de pruebas, ahora necesitamos cargarlo en Python, los próximos artículos van dedicados a interpretar los datos en Python y la manera de almacenar el mapa.</p>
<p>Para empezar vamos a hacer una copia de nuestra <a href="http://razonartificial.com/wp-content/uploads/2010/03/plantilla.zip">plantilla</a> con el nombre de maps.py que es el archivo que va a contener todo lo relacionado con la carga y creación de los mapas de nuestro engine.</p>
<p>A modo de repaso en mi carpeta engine ahora mismo tengo dos carpetas una llamada <strong>graphics</strong> que contiene una carpeta <strong>tilesets</strong> que contiene nuestro tileset de ejemplo, y otra <strong>maps</strong> que contiene un mapa de prueba. Luego tengo el ejecutable del programa <strong>tiled</strong> y luego 3 scripts de Python <strong>plantilla.py</strong>, <strong>engine.py</strong> y <strong>maps.py</strong>. Eso es lo que deberían de tener todos si hemos seguido los artículos.</p>
<h2>Cargando un mapa</h2>
<p>Antes de ponernos a escribir código nos preguntamos, ¿Como representamos un mapa? La técnica ya la explique en el <a href="http://razonartificial.com/2010/04/engine-iii-juegos-basados-en-tiles/">capítulo 3</a>, lo que vamos es crear una clase Mapa que contenga toda la información de este en simple variables, el ancho, el alto, el tamaño de los tiles y lo más importante, una array bidimensional que contenga que tile del tileset va en cada lugar.</p>
<p>Te preguntarás, que como hacemos esto si el tileset que tenemos es una simple imagen png, bien tranquilo, lo que haremos será desde Python coger esa imagen y partirla en &#8220;cachitos&#8221; (los tiles) y almacenarla en una array, cada tile del array tendrá un índice que, oh sorpresa, se corresponderá con los valores de nuestro array bidimensional del mapa. Todo esto puede parecer lioso, pero ya veremos que no lo es.</p>
<p>Bueno pues aclaradas un par de cosas vamos a empezar a escribir nuestra clase mapas, en un principio solo tendrá un par de métodos de inicialización y carga, pero esta clase crecerá a medida que avanza el engine.</p>
<p><span id="more-354"></span></p>
<p>Una última cosa, vamos a trabajar con ficheros XML en Python, es un temga largo y tendido que no cabe dentro de estos artículo, pero os dejo <a href="http://sites.google.com/site/sbassi/leyendoxmlenpython:dom2">este tutorial</a> donde explica muy bien como tratar estos archivos con Python y extraer la información, de todas maneras yo pondré aquí como extraer la información de nuestro mapa para nuestro engine.</p>
<h2>La clase Mapa</h2>
<p>Lo primero que necesitamos es inicializar la clase y crear un método que lea nuestro fichero XML y extraiga los datos. Todo esto es muy difícil verlo fuera de conjunto así que voy a poner como va el fichero maps.py entero por ahora y lo comentamos paso a paso.</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
from xml.dom import minidom, Node
import base64
import gzip
import StringIO

# Clases
# ---------------------------------------------------------------------

class Mapa:
	def __init__(self, nombre):
		self.nombre = nombre
		self.capas = []

		self.cargar_mapa() # Inicializa los valores desde el xml.

	# Extrae valores mapa desde XML.
	def cargar_mapa(self):
		xmlMap = minidom.parse(&quot;maps/&quot;+self.nombre)
		nPrincipal = xmlMap.childNodes[0]

		# Tamaño mapa
		self.width = int(nPrincipal.attributes.get(&quot;width&quot;).value)
		self.height = int(nPrincipal.attributes.get(&quot;height&quot;).value)

		for i in range(len(nPrincipal.childNodes)):
			if nPrincipal.childNodes[i].nodeType == 1:
				if nPrincipal.childNodes[i].nodeName == &quot;tileset&quot;:
					if nPrincipal.childNodes[i].attributes.get(&quot;name&quot;).value != &quot;config&quot;:
						width = nPrincipal.childNodes[i].attributes.get(&quot;tilewidth&quot;).value
						height = nPrincipal.childNodes[i].attributes.get(&quot;tileheight&quot;).value
						nombre = nPrincipal.childNodes[i].childNodes[1].attributes.get(&quot;source&quot;).value
						nombre = extraer_nombre(nombre)
						self.tileset = nombre
					self.tam_tiles = (int(width), int(height))
				if nPrincipal.childNodes[i].nodeName == &quot;layer&quot;:
					if  nPrincipal.childNodes[i].attributes.get(&quot;name&quot;).value != &quot;colisiones&quot;:
						layer = nPrincipal.childNodes[i].childNodes[1].childNodes[0].data.replace(&quot;\n&quot;, &quot;&quot;).replace(&quot; &quot;, &quot;&quot;)
						layer = decodificar(layer) # Decodifica la lista
						layer = convertir(layer, self.width) # Convierta en array bidimensional
						self.capas.append(layer)
				if nPrincipal.childNodes[i].nodeName == &quot;objectgroup&quot;:
					x = nPrincipal.childNodes[i].childNodes[1].attributes.get(&quot;x&quot;).value
					y = nPrincipal.childNodes[i].childNodes[1].attributes.get(&quot;y&quot;).value
					self.start = (int(x), int(y))

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

# Convierta una array unidimensional en una bidimensional.
def convertir(lista, col):
	nueva = []
	for i in range(0, len(lista), col):
		nueva.append(lista[i:i+col])
	return nueva

# Decodifica y descomprime un mapa.
def decodificar(cadena):
	# Decodificar.
	cadena = base64.decodestring(cadena)

	# Descomprimir.
	copmressed_stream = StringIO.StringIO(cadena)
	gzipper = gzip.GzipFile(fileobj=copmressed_stream)
	cadena = gzipper.read()

	# Convertir.
	salida = []
	for idx in xrange(0, len(cadena), 4):
		val = ord(str(cadena[idx])) | (ord(str(cadena[idx + 1])) &lt;&lt; 8) | \
		(ord(str(cadena[idx + 2])) &lt;&lt; 16) | (ord(str(cadena[idx + 3])) &lt;&lt; 24)
		salida.append(val)

	return salida

# Extra el nombre de un archivo de una ruta.
def extraer_nombre(ruta):
	a = -1
	for i in range(len(ruta)):
		if ruta[i] == &quot;/&quot; or ruta[i] == &quot;\\&quot;:
			a = i
	if a == -1:
		return ruta
	return ruta[a+1:]

# ---------------------------------------------------------------------

def main():
	mapa = Mapa(&quot;bosque.tmx&quot;)
	print mapa.tileset
	return 0

if __name__ == '__main__':
	main()
</pre>
<p>En primer lugar importamos todos los módulos que vamos a necesitar: trabajar con XML, descodificar y descomprimir con base64 y gzip y StringIO que nos hace falta también para la descompresión.</p>
<p>Luego creamos la clase Mapa que como vemos de momento tiene dos métodos, el método __init__ que la inicializa, toma como parámetros self (como todas las clases) y nombre, que es el nombre del mapa que queremos cargar. Ojo, que solo le debemos pasar una cadena con el nombre y la extensión tipo &#8220;mi_mapa.tmx&#8221; ya que más abajo he supuesto que lo busque siempre dentro de la carpeta maps que es donde estarán nuestros mapas.</p>
<p>Luego crea la variables nombre y capas. Esta segunda sera un array que contendrá a su vez varios arrays bidimensionales que representan a cada capa. Más abajo explico como mostrarla y se entenderá mejor.</p>
<p>Por último hacemos una llamada al método cargar_mapa() que hemos definido debajo y que es el que se encarga de extraer los datos del mapa. Vamos con ella.</p>
<p>Recuerda leer el artículo que puse más arriba acerca de como trabajar con XML y mirando el código del método más o menos lo entenderás, cargamos el mapa y extraemos el nodo principal, luego vamos recorriendo los nodos hijos y comprobando que tipo de nodos es (repito, leer el tutorial de XML) y extrayendo la información del árbol XML de nuestro archivo.</p>
<p>Especial atención a la línea 36 donde hace uso de una función que hemos definido más abajo para extraer el nombre del tileset de la ruta completa que se guarda en el archivo. ¿Por qué esto? Pues porque el archivo guarda la ruta absoluta y a nosotros solo nos interesa el nombre del tileset que está usando porque ya nuestro engine sabe en que carpeta buscar los tileset.</p>
<p>Bien llega la línea 41 que es la que obtiene la larga secuencia codificada que teníamos en nuestro archivo, como vemos simplemente cogemos la cadena, le quitamos los saltos de línea y los espacios y la almacenamos en una variable de la clase, luego esa variable la decodificamos y descomprimimos con la función que está más abajo. Explicar esa función sería extendernos demasiado porque es algo complicada, de todas maneras si alguien tiene dudas o interés dejad un comentario y escribiré un artículo sobre ella.</p>
<p>Después de decodificarla y descomprimirla la tenemos almacenada en una array unidimensional, para nuestro mapa mejor la pasamos a una bidimensional con el tamaño del mapa, más abajo está la función que hace esto, nada complicado.</p>
<p>por último, una parte que se tiene que desarrollar, la que obtiene los datos de la capa evento solo esta puesto ahí para sacar el evento que definimos que es el de  la posición inicias, esto (y parte de lo de arriba) se ampliará cuando avance el engine.</p>
<p>Por último en la función main() (Para esto es para que la definimos en un módulo) podemos probar creando un objeto mapa con nuestro mapa de ejemplo y podemos probar a imprimir en pantalla los distintos valores que hemos sacado.</p>
<p>Probad a ir paso a paso por el método cargar_mapa y viendo todos los valores que hemos sacado (todos los que son self.algo, son valores del mapa). En el código de arriba he puesto como ejemplo que imprima el nombre del tileset.</p>
<p>Bien con esto ya tenemos algunos datos de nuestro mapa cargados en Python, ahora hay que empezar a trabajar con el tileset y pasar estos datos a Pygame.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/" title="Engine XI: Creando al héroe">Engine XI: Creando al héroe</a></li><li><a href="http://razonartificial.com/2010/04/haciendo-un-engine-para-juegos-con-python-y-pygame/" title="Haciendo un engine para juegos">Haciendo un engine para juegos</a></li><li><a href="http://razonartificial.com/2010/06/engine-x-la-clase-mapa-iii/" title="Engine X: La clase mapa III">Engine X: La clase mapa III</a></li><li><a href="http://razonartificial.com/2010/06/engine-ix-cargando-el-tileset/" title="Engine IX: Cargando el tileset">Engine IX: Cargando el tileset</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/WBF72sc4VNIB-17RjELi9kaeeL0/0/da"><img src="http://feedads.g.doubleclick.net/~a/WBF72sc4VNIB-17RjELi9kaeeL0/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/WBF72sc4VNIB-17RjELi9kaeeL0/1/da"><img src="http://feedads.g.doubleclick.net/~a/WBF72sc4VNIB-17RjELi9kaeeL0/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/JPc3ZUKKmIY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Engine VI: El formato TMX</title>
		<link>http://razonartificial.com/2010/06/engine-vi-formato-tmx/</link>
		<comments>http://razonartificial.com/2010/06/engine-vi-formato-tmx/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 21:43:47 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Map Editor]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[RPG]]></category>
		<category><![CDATA[Teoría]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=339</guid>
		<description><![CDATA[En este artículo vamos a analizar el archivo que nos ha generado el Tiled Map Editor, un fichero con extensión .tmx que hemos guardado en la carpeta maps. Es un archivo XML, para el que no sepa lo que es, es un lenguaje de marcas que guarda información mediante etiquetas (a grandes rasgos, podéis buscar [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" title="engine" width="190" height="150" class="alignright size-full wp-image-292" /></p>
<p>En este artículo vamos a analizar el archivo que nos ha generado el Tiled Map Editor, un fichero con extensión .tmx que hemos guardado en la carpeta maps. Es un archivo XML, para el que no sepa lo que es, es un lenguaje de marcas que guarda información mediante etiquetas (a grandes rasgos, podéis buscar más en la red). Pues bien al ser simple texto plano lo podemos abrir con cualquier editor de textos (El geany que utilizo yo me resalta las etiquetas). Vamos a analizarlo:</p>
<pre class="brush: xml;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;map version=&quot;1.0&quot; orientation=&quot;orthogonal&quot; width=&quot;35&quot; height=&quot;25&quot; tilewidth=&quot;40&quot; tileheight=&quot;40&quot;&gt;
 &lt;tileset firstgid=&quot;1&quot; name=&quot;tile_bosque&quot; tilewidth=&quot;40&quot; tileheight=&quot;40&quot;&gt;
  &lt;image source=&quot;../graphics/tilesets/tile_bosque.png&quot; trans=&quot;#ff00ff&quot;/&gt;
 &lt;/tileset&gt;
 &lt;layer name=&quot;Base&quot; width=&quot;35&quot; height=&quot;25&quot;&gt;
  &lt;data encoding=&quot;base64&quot; compression=&quot;gzip&quot;&gt;
   H4sIAAAAAAAAA+2Tuw6AIAxFWRl9DaiL+v//KAtJc5NaEismeoczQdtTwo0hh...
  &lt;/data&gt;
 &lt;/layer&gt;
 &lt;layer name=&quot;Montañas&quot; width=&quot;35&quot; height=&quot;25&quot;&gt;
  &lt;data encoding=&quot;base64&quot; compression=&quot;gzip&quot;&gt;
   H4sIAAAAAAAAA+2W2UpDQQyG+...
  &lt;/data&gt;
 &lt;/layer&gt;
 &lt;layer name=&quot;New Layer&quot; width=&quot;35&quot; height=&quot;25&quot;&gt;
  &lt;data encoding=&quot;base64&quot; compression=&quot;gzip&quot;&gt;
   H4sIAAAAAAAAA2NgGHrAH4gDSFC/EYg3AfFmKN+DinaHA3EEEfqQ7dwFxLup4AZ0u...
  &lt;/data&gt;
 &lt;/layer&gt;
 &lt;objectgroup name=&quot;Eventos&quot; width=&quot;35&quot; height=&quot;25&quot;&gt;
  &lt;object name=&quot;heroe&quot; x=&quot;625&quot; y=&quot;544&quot;/&gt;
 &lt;/objectgroup&gt;
&lt;/map&gt;
</pre>
<p><span id="more-339"></span><br />
La primera línea está en todos los documentos XML e indica que tipo de documentos es y la codificación. Luego comienza el árbol de nuestro mapa, la primera etiqueta &#8220;map&#8221; contiene la orienteción, los tiles de ancho y largo de nuestro mapa y el tamaño de los tileset. Todos los que definimos cuando creamos el mapa.</p>
<p>A continuación viene la información de los tilesets. Nos indica el número de tileset que es &#8220;firstgid&#8221; (un mapa puede tener varios tilesets a la vez. Luego el tamaño de los tiles del tilesets y dentro contiene una etiqueta con la dirección de la imagen del tileset y el color transparente (si hemos definido uno).</p>
<p>Luego carga las diferentes capas nos da el nombre, el ancho, dentro contiene una etiqueta data muy extraña. Esta etiqueta data tiene dos atributos encoding=&#8221;base64&#8243; y compression=&#8221;gzip&#8221; esto quiere decir que la cadena que contiene esta codificada en base64 y comprimida con gzip ¿Por qué esto? Pues porque contiene la etiqueta data es una lista de etiquetas por cada uno de los tiles de nuestro mapa que contiene el número de tile del tileset que está usando (y esta lista es enorme) por lo que para que los ficheros de mapa no ocupen tanto se codifican y se comprimen. En el próximo tutorial veremos como decodificarlo y descomprimirlo con Python.</p>
<p>Por último está la capa objectgroup. Esta son las capas de &#8220;eventos&#8221;, vemos que contiene el nombre que hemos puesto &#8220;Eventos&#8221; y el ancho y el alto (por defecto como todas es igual al tamaño del mapa). Dentro contiene  un solo evento, porque solo uno creamos. Los eventos se llaman object y vemos que contiene el nombre que le pusimos y la posición x e y.</p>
<p>Hay más datos que se guardan que en este mapa no aparecen porque no hemos puesto, pero creo que se capta la idea de como guarda la información de nuestro mapa el archivo tmx. En el siguiente artículo veremos como leer esta información con Python para cargar los mapas.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li><li><a href="http://razonartificial.com/2010/06/engine-v-usando-el-tiled-map-editor/" title="Engine V: Usando el Tiled Map Editor">Engine V: Usando el Tiled Map Editor</a></li><li><a href="http://razonartificial.com/2010/04/engine-iii-juegos-basados-en-tiles/" title="Engine III: Juegos basados en tiles">Engine III: Juegos basados en tiles</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/08/tilemapping-juegos-basados-en-tiles/" title="Tilemapping – Juegos basados en tiles">Tilemapping – Juegos basados en tiles</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/mv4fDkxxtvmht7Sg-k-lzr8uftY/0/da"><img src="http://feedads.g.doubleclick.net/~a/mv4fDkxxtvmht7Sg-k-lzr8uftY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/mv4fDkxxtvmht7Sg-k-lzr8uftY/1/da"><img src="http://feedads.g.doubleclick.net/~a/mv4fDkxxtvmht7Sg-k-lzr8uftY/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/I2lTSQOjocs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/06/engine-vi-formato-tmx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Síguenos en Twitter</title>
		<link>http://razonartificial.com/2010/06/siguenos-en-twitter/</link>
		<comments>http://razonartificial.com/2010/06/siguenos-en-twitter/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 00:20:59 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=333</guid>
		<description><![CDATA[Bueno, en un intento de socializar el blog nos unimos a la moda de Twitter, a partir de ahora nos podéis seguir desde allí, intentaré poner todo lo relacionado con el blog que no tiene cabida en un post y cosas interesantes que encoentre relacionadas con la inteligencia artificial, la robótica o los videojuegos. Nuestro Twitter [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-thumbnail wp-image-335" title="twitter-logo" src="http://razonartificial.com/wp-content/uploads/2010/06/twitter-logo-150x150.png" alt="" width="150" height="150" />Bueno, en un intento de socializar el blog nos unimos a la moda de Twitter, a partir de ahora nos podéis seguir desde allí, intentaré poner todo lo relacionado con el blog que no tiene cabida en un post y cosas interesantes que encoentre relacionadas con la inteligencia artificial, la robótica o los videojuegos. Nuestro Twitter es el siguiente:</p>
<h2 style="text-align: center;"><a href="https://twitter.com/razonartificial">https://twitter.com/razonartificial</a></h2>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li>No hay entradas relacionadas.</li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/QEcil-yfdKUxxszKgq1XOWuspdc/0/da"><img src="http://feedads.g.doubleclick.net/~a/QEcil-yfdKUxxszKgq1XOWuspdc/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/QEcil-yfdKUxxszKgq1XOWuspdc/1/da"><img src="http://feedads.g.doubleclick.net/~a/QEcil-yfdKUxxszKgq1XOWuspdc/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/dGIROxb1kn0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/06/siguenos-en-twitter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Engine V: Usando el Tiled Map Editor</title>
		<link>http://razonartificial.com/2010/06/engine-v-usando-el-tiled-map-editor/</link>
		<comments>http://razonartificial.com/2010/06/engine-v-usando-el-tiled-map-editor/#comments</comments>
		<pubDate>Mon, 31 May 2010 23:48:29 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Map Editor]]></category>
		<category><![CDATA[RPG]]></category>
		<category><![CDATA[Teoría]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=322</guid>
		<description><![CDATA[Lo primero que debemos hacer es situar el programa dentro de nuestra carpeta principal (llamada engine) para que no haya problemas con las rutas. Luego para hacer mapas basados en tilesets necesitamos, como no, un tileset. Para estos artículos yo voy a utilizar uno que he hecho con recursos libres, son tiles de 40&#215;40, lo [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg"><img class="alignright size-full wp-image-292" title="engine" src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" width="190" height="150" /></a>Lo primero que debemos hacer es situar el programa dentro de nuestra carpeta principal (llamada engine) para que no haya problemas con las rutas. Luego para hacer mapas basados en tilesets necesitamos, como no, un tileset. Para estos artículos yo voy a utilizar uno que he hecho con recursos libres, son tiles de 40&#215;40, lo más habituales son de 32&#215;32, pero haremos nuestro engine sea independiente del tamaño de los tiles. Si no entiendes esto, quiere decir que cada cuadrito que compone el tileset, cada tile, es de 40 pixeles de ancho y 40 de alto. <a href="http://razonartificial.com/wp-content/uploads/2010/06/tile_bosque.png">Descargar tileset</a>.</p>
<p>Una vez descargado dentro de la carpeta graphics creamos una llamada tilesets y lo guardamos dentro. Ahora abrimos el Tiled Map Editor (TME a partir de ahora) y creamos un nuevo mapa le damos un tamaño de por ejemplo 50 tiles de ancho por 50 de alto y muy importante aquí, debemos decirle que los tiles de nuestro mapa serán de 40&#215;40 (por defecto viene 32&#215;32). La orientación la dejamos en ortogonal ya que no vamos a hacer juegos isométricos (de momento).<span id="more-322"></span></p>
<p><a href="http://razonartificial.com/wp-content/uploads/2010/06/New-Map_002.png"><img class="aligncenter size-full wp-image-324" title="New Map_002" src="http://razonartificial.com/wp-content/uploads/2010/06/New-Map_002.png" alt="" width="282" height="237" /></a></p>
<p>Lo siguiente que necesitamos es cargar nuestro tileset, elegimos la ruta, podemos poner un color que queramos que sea transparente, esto es opcional, el programa ya lee las transparencias de los archivos png. Y recordamos establecer que los tiles son de 40&#215;40.</p>
<p><a href="http://razonartificial.com/wp-content/uploads/2010/06/New-Tileset_001.png"><img class="aligncenter size-full wp-image-325" title="New Tileset_001" src="http://razonartificial.com/wp-content/uploads/2010/06/New-Tileset_001.png" alt="" width="298" height="300" /></a>Investigad un poco y lo entenderéis enseguida, podéis crear tantas capas como querais y algo muy útil que veremos mas adelante, capas de eventos. Por ahora para seguir los artículos crear una capa de eventos arriba del todo (da igual cuantas capas de tiles tengáis) llamada Eventos y colocar un evento cerca del centro del mapa y ponerle el nombre de heroe (click derecho en el evento y le das propiedades). Click en la imagen para ver a tamaño completo.</p>
<p><a href="http://razonartificial.com/wp-content/uploads/2010/06/bosque.tmx-Tiled_004.png"><img class="aligncenter size-medium wp-image-327" title="bosque.tmx* - Tiled_004" src="http://razonartificial.com/wp-content/uploads/2010/06/bosque.tmx-Tiled_004-300x208.png" alt="" width="300" height="208" /></a></p>
<p>Por último guardar en la carpeta maps con la extensión .tmx (esto es muy importante para que lo reconozca el TME.</p>
<p><a href="http://razonartificial.com/wp-content/uploads/2010/06/Ventana-sin-título_003.png"><img class="aligncenter size-full wp-image-328" title="Ventana sin título_003" src="http://razonartificial.com/wp-content/uploads/2010/06/Ventana-sin-título_003.png" alt="" width="556" height="415" /></a>En el siguiente tutorial analizaremos en fichero que hemos obtenido y aprenderemos a extraer la información.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/06/engine-vi-formato-tmx/" title="Engine VI: El formato TMX">Engine VI: El formato TMX</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li><li><a href="http://razonartificial.com/2010/04/engine-iv-tiled-map-editor/" title="Engine IV: Tiled Map Editor">Engine IV: Tiled Map Editor</a></li><li><a href="http://razonartificial.com/2010/04/engine-iii-juegos-basados-en-tiles/" title="Engine III: Juegos basados en tiles">Engine III: Juegos basados en tiles</a></li><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/GFKA46SoJl0MofHqtijtRkglVDA/0/da"><img src="http://feedads.g.doubleclick.net/~a/GFKA46SoJl0MofHqtijtRkglVDA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/GFKA46SoJl0MofHqtijtRkglVDA/1/da"><img src="http://feedads.g.doubleclick.net/~a/GFKA46SoJl0MofHqtijtRkglVDA/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/MOW6ZgUHLz8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/06/engine-v-usando-el-tiled-map-editor/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Volvemos a las andadas</title>
		<link>http://razonartificial.com/2010/05/volvemos-a-las-andadas/</link>
		<comments>http://razonartificial.com/2010/05/volvemos-a-las-andadas/#comments</comments>
		<pubDate>Mon, 31 May 2010 17:30:09 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=318</guid>
		<description><![CDATA[Después de un mes de Mayo de lo más complicado y lleno de obligaciones que me han mantenido alejado del blog y de cualquier tema sobre la inteligencia artificial, la robótica o los juegos, ahora por fin llega Junio y el verano. Ahora dispondré de tiempo para dedicarle a los temas que deje a medias [...]]]></description>
			<content:encoded><![CDATA[<p>Después de un mes de Mayo de lo más complicado y lleno de obligaciones que me han mantenido alejado del blog y de cualquier tema sobre la inteligencia artificial, la robótica o los juegos, ahora por fin llega Junio y el verano. Ahora dispondré de tiempo para dedicarle a los temas que deje a medias y a nuevos temas igual de interesantes. Por supuesto espero seguir publicando aquí todas mis experiencias y apuntes que puedan servir, espero que los viejos lectores no me hayan abandonado y que se unan muchos más.</p>
<p>En esta nueva etapa espero por fin empezar a publicar algo sobre robótica (sigo buscando a alguien que me ayude con esta sección) y seguir publicando tutoriales y artículos que sean útiles para vosotros, recuerdo que la filosofía del blog es publicar artículos útiles, para noticias y avances ya hay periódicos y otros blogs.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/repositorio-en-github-para-el-engine-rpg/" title="Repositorio en github para el Engine-RPG">Repositorio en github para el Engine-RPG</a></li><li><a href="http://razonartificial.com/2010/07/futuro-del-engine-y-los-tutoriales/" title="Futuro del Engine y los tutoriales">Futuro del Engine y los tutoriales</a></li><li><a href="http://razonartificial.com/2010/07/destacamos-del-foro/" title="Destacamos del foro">Destacamos del foro</a></li><li><a href="http://razonartificial.com/2010/07/razon-artificial-crece/" title="Razón Artificial Crece">Razón Artificial Crece</a></li><li><a href="http://razonartificial.com/2010/07/%c2%bfuna-comunidad/" title="¿Una comunidad?">¿Una comunidad?</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/ANoGWN9Y177o_hK_q6w_fB_Akwk/0/da"><img src="http://feedads.g.doubleclick.net/~a/ANoGWN9Y177o_hK_q6w_fB_Akwk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ANoGWN9Y177o_hK_q6w_fB_Akwk/1/da"><img src="http://feedads.g.doubleclick.net/~a/ANoGWN9Y177o_hK_q6w_fB_Akwk/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/o4ekyM2_OoI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/05/volvemos-a-las-andadas/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Engine IV: Tiled Map Editor</title>
		<link>http://razonartificial.com/2010/04/engine-iv-tiled-map-editor/</link>
		<comments>http://razonartificial.com/2010/04/engine-iv-tiled-map-editor/#comments</comments>
		<pubDate>Thu, 08 Apr 2010 12:21:04 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Map Editor]]></category>
		<category><![CDATA[Teoría]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=311</guid>
		<description><![CDATA[En el anterior artículo explicamos la forma de almacenar un mapa y de como se representa este mapa, obviamente no vamos a rellenar el array que representa nuestro mapa a base de crear el array en el programa esto sería una tarea titánica. Se podría crear un archivo con los valores y cargarlo, pero seguiría [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-292" title="engine" src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" width="190" height="150" /></p>
<p>En el anterior artículo explicamos la forma de almacenar un mapa y de como se representa este mapa, obviamente no vamos a rellenar el array que representa nuestro mapa a base de crear el array en el programa esto sería una tarea titánica. Se podría crear un archivo con los valores y cargarlo, pero seguiría siendo muy complicado</p>
<p>Es por eso que vamos a usar un Editor de mapas, el <a href="http://mapeditor.org/">Tiled Map Editor</a>, es un editor de mapas que está bastante bien. Tiene soporte de Capas, de eventos, propiedades para capas y para tileset con valores configurables, etc. Pero lo más importante es que guarda los mapas en formato XML que hacen que sean muy fáciles de leer con Python y extraer la información.</p>
<p style="text-align: center;"><a href="http://razonartificial.com/wp-content/uploads/2010/04/bosque.tmx-Tiled_001.png"><img class="aligncenter size-large wp-image-312 imageborder" title="bosque.tmx - Tiled_001" src="http://razonartificial.com/wp-content/uploads/2010/04/bosque.tmx-Tiled_001-1024x700.png" alt="" width="659" height="400" /></a></p>
<p>Como vemos tiene una interfaz sencilla e intuitiva, puedes descargarlo de su página Web, es multiplataforma, hay versiones tanto para Windows, MacOS X y Linux, para este último hay que compilarlo, pero no es nada complicado y si tenéis duda dejadme un comentario y os lo explico.<span id="more-311"></span></p>
<h2>El archivo TMX</h2>
<p>El guardar el mapa se genera un archivo tmx que no es mas que un documeno XML que tiene el siguiente formato:</p>
<pre class="brush: xml;">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;map version=&quot;1.0&quot; orientation=&quot;orthogonal&quot; width=&quot;35&quot; height=&quot;30&quot; tilewidth=&quot;40&quot; tileheight=&quot;40&quot;&gt;
 &lt;tileset firstgid=&quot;1&quot; name=&quot;bosque&quot; tilewidth=&quot;40&quot; tileheight=&quot;40&quot;&gt;
  &lt;image source=&quot;../../engine/graphics/tilesets/tile_bosque.png&quot;/&gt;
 &lt;/tileset&gt;
 &lt;layer name=&quot;Layer 1&quot; width=&quot;35&quot; height=&quot;30&quot;&gt;
  &lt;data encoding=&quot;base64&quot; compression=&quot;gzip&quot;&gt;
   H4sIAAAAAAAAA81WQQ6DMAzrlSNsO2zAYfD...
 &lt;/data&gt;
 &lt;/layer&gt;
 &lt;layer name=&quot;Layer 2&quot; width=&quot;35&quot; height=&quot;30&quot;&gt;
  &lt;data encoding=&quot;base64&quot; compression=&quot;gzip&quot;&gt;
   H4sIAAAAAAAAA9WXh07DMBRF/TvQQhlhRuyC...
  &lt;/data&gt;
 &lt;/layer&gt;
 &lt;layer name=&quot;Layer 3&quot; width=&quot;35&quot; height=&quot;30&quot;&gt;
  &lt;data encoding=&quot;base64&quot; compression=&quot;gzip&quot;&gt;
   H4sIAAAAAAAAA+WWsQ7CMAxE/RWFiTIBG2yw0Q022...
  &lt;/data&gt;
 &lt;/layer&gt;
 &lt;objectgroup name=&quot;Eventos&quot; width=&quot;35&quot; height=&quot;30&quot;&gt;
  &lt;object name=&quot;&quot; x=&quot;700&quot; y=&quot;495&quot;/&gt;
 &lt;/objectgroup&gt;
&lt;/map&gt;
</pre>
<p>Como ves almacena gran cantidad de información como el tamaño del mapa, el tamaño de los tiles que utliza, la ruta del tileset, etc. Luego almacena las capas en un formato bastante raro:</p>
<pre class="brush: xml;">
&lt;data encoding=&quot;base64&quot; compression=&quot;gzip&quot;&gt;
    H4sIAAAAAAAAA81WQQ6DMAzrlSNsO2zAYfD...
&lt;/data&gt;
</pre>
<p>La cadena entre las etiquetas  en realidad es mucho más larga solo que yo la he acortado con puntos suspensivos para que cupiera y esto es lo que contiene nuestra array con la pos del tiled que utiliza, solo que viene cifrado en base64 y comprimido con gzip, pero ya veremos una forma muy fácil de decodificarlo y descomprimirlo con python.</p>
<p>Por ahora trata de hacer pruebas con el Tiled y ver en que va cambiendo el archivo XML generado y que datos va almacenando, en el siguiente tutorial aprenderemos a leer estos datos con Python.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/06/engine-vi-formato-tmx/" title="Engine VI: El formato TMX">Engine VI: El formato TMX</a></li><li><a href="http://razonartificial.com/2010/06/engine-v-usando-el-tiled-map-editor/" title="Engine V: Usando el Tiled Map Editor">Engine V: Usando el Tiled Map Editor</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li><li><a href="http://razonartificial.com/2010/04/engine-iii-juegos-basados-en-tiles/" title="Engine III: Juegos basados en tiles">Engine III: Juegos basados en tiles</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/3jSuwUMaRDVpVMw_dxIRfyUtvPA/0/da"><img src="http://feedads.g.doubleclick.net/~a/3jSuwUMaRDVpVMw_dxIRfyUtvPA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/3jSuwUMaRDVpVMw_dxIRfyUtvPA/1/da"><img src="http://feedads.g.doubleclick.net/~a/3jSuwUMaRDVpVMw_dxIRfyUtvPA/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/o5-wLJfId7A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/04/engine-iv-tiled-map-editor/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Engine III: Juegos basados en tiles</title>
		<link>http://razonartificial.com/2010/04/engine-iii-juegos-basados-en-tiles/</link>
		<comments>http://razonartificial.com/2010/04/engine-iii-juegos-basados-en-tiles/#comments</comments>
		<pubDate>Thu, 08 Apr 2010 11:03:20 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[RPG]]></category>
		<category><![CDATA[Teoría]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=305</guid>
		<description><![CDATA[Nuestro engine va a hacer programado para juegos basados en la técnica del tilemapping, supongo que muchos ya sabrás en que consiste esta técnica, pero este artículo es para el que no lo sepa y para explicar que tipo de &#8220;tiles&#8221; vamos a usar. El tilemapping consiste en dividir los mapas de nuestro juego en [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-292" title="engine" src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" width="190" height="150" /></p>
<p>Nuestro engine va a hacer programado para juegos basados en la técnica del tilemapping, supongo que muchos ya sabrás en que consiste esta técnica, pero este artículo es para el que no lo sepa y para explicar que tipo de &#8220;tiles&#8221; vamos a usar.</p>
<p>El tilemapping consiste en dividir los mapas de nuestro juego en pequeños &#8220;tiles&#8221; (casillas) todas iguales, cada casilla puede tener un gráfico distinto y a partir de unir estas casillas se obtiene un mapa complejo.</p>
<p>Un ejemplo: Hundir la Flota. En este juego, el mapa es una cuadrícula de casillas. Cada casilla puede tener varios estados (agua, barco, barco tocado, barco hundido, etc&#8230;). Y cada uno de estos estados se representan en pantalla cambiando el color de la casilla, o usando una imagen distinta.<span id="more-305"></span></p>
<h2><img class="aligncenter size-full wp-image-306" title="mud-tile-example" src="http://razonartificial.com/wp-content/uploads/2010/04/mud-tile-example.png" alt="" width="463" height="320" />Tileset</h2>
<p>Un tileset es una imagen que contiene los gráficos de todos los &#8220;tiles&#8221; (cuadritos de gráficos) que contiene nuestro mapa, en la imagen superior podemos ver un pequeño ejemplo de mapa a la izquierda y como esta formado usando los &#8220;tiles&#8221; del tileser de la derecha.</p>
<p>Esta técnica hace que con pocos gráficos podamos tener un mapa muy complejo y detallado y que además son altamente modificables, imagina tener que dibujar los mapas todos entero, sería eterno.</p>
<h2>La técnica</h2>
<p>La técnica consiste en que nuestro mapa es una simple matriz bidimensional de números enteros cada numero estará asociado a un tile en particular del mapa, por ejemplo el 1 representa a un tile de tierra, el 2 de agua y así sucesivamente.</p>
<p><img class="aligncenter size-full wp-image-307" title="map-representation" src="http://razonartificial.com/wp-content/uploads/2010/04/map-representation.png" alt="" width="481" height="306" /></p>
<p>En la imagen se ve claramente como las casillas con valor 2 son rellenadas de azul, las de 1 con amarillo y las de valor 0 son ignoradas.</p>
<p>Hay diferentes tipos de tilemapping, nosotros vamos a hacer es el más simple que es el ortogonal (visto desde arriba), luego hay otros como el isométrico que crea una sensación de 3D.</p>
<p>Bueno espero haber aclarado el concepto de tile para el que no lo conociera, si hay alguna duda tenéis los comentarios para preguntar.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/06/engine-vi-formato-tmx/" title="Engine VI: El formato TMX">Engine VI: El formato TMX</a></li><li><a href="http://razonartificial.com/2010/06/engine-v-usando-el-tiled-map-editor/" title="Engine V: Usando el Tiled Map Editor">Engine V: Usando el Tiled Map Editor</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/08/tilemapping-juegos-basados-en-tiles/" title="Tilemapping – Juegos basados en tiles">Tilemapping – Juegos basados en tiles</a></li><li><a href="http://razonartificial.com/2010/08/introduccion-a-la-programacion-grafica-2d-iii/" title="Introducción a la programación gráfica 2D (III)">Introducción a la programación gráfica 2D (III)</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/9JS3jx_ETaSxa-IdC4_cX0pdpzY/0/da"><img src="http://feedads.g.doubleclick.net/~a/9JS3jx_ETaSxa-IdC4_cX0pdpzY/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/9JS3jx_ETaSxa-IdC4_cX0pdpzY/1/da"><img src="http://feedads.g.doubleclick.net/~a/9JS3jx_ETaSxa-IdC4_cX0pdpzY/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/oE6vx-PttMc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/04/engine-iii-juegos-basados-en-tiles/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Engine II: El archivo principal</title>
		<link>http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/</link>
		<comments>http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/#comments</comments>
		<pubDate>Thu, 08 Apr 2010 02:10:08 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RPG]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=299</guid>
		<description><![CDATA[Bien lo primero que necesitamos es crear un archivo de entrada, es decir, un archivo que nos permita ejecutar el motor y hacerlo funcionar. Se encargue de crear la venta y de hacer el loop de Pygame, todo esto son conceptos básicos de Pygame que ya explique en el tutorial de pygame. Nuestra forma de [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-292 alignright" title="engine" src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" width="190" height="150" />Bien lo primero que necesitamos es crear un archivo de entrada, es decir, un archivo que nos permita ejecutar el motor y hacerlo funcionar. Se encargue de crear la venta y de hacer el loop de Pygame, todo esto son conceptos básicos de Pygame que ya explique en el <a href="http://razonartificial.com/tutoriales-pygame/">tutorial de pygame</a>.</p>
<p>Nuestra forma de trabajar va a ser que los nuevos archivos se crea a partir de la plantilla que ya puse en los tutoriales y en el anterior artículo. Hacemos una copia de esta y la llamamos <strong>engine.py</strong>, este sera nuestro archivo de entrada y el que usaremos para ejecutar nuestro motor.</p>
<p>Definimos una resolucióm, creamos una función que compruebe si se quiere salir y hacemos el loop de Pygame, repito que si no sabes hacer todo esto puedes mirar el link a los tutoriales de pygame que puse más arriba. En definitiva nuestro <strong>engine.py</strong> nos queda así:<span id="more-299"></span></p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def salir():
	keys = pygame.key.get_pressed()
	for eventos in pygame.event.get():
		if eventos.type == QUIT:
			sys.exit(0)
		if keys[K_ESCAPE]:
			sys.exit(0)

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Engine RPG&quot;)

	clock = pygame.time.Clock()

	while True:
		time = clock.tick(60)
		salir()

		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/" title="Engine XI: Creando al héroe">Engine XI: Creando al héroe</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/B_6ycKjIhMVNg0KmpHL_IDswrXU/0/da"><img src="http://feedads.g.doubleclick.net/~a/B_6ycKjIhMVNg0KmpHL_IDswrXU/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/B_6ycKjIhMVNg0KmpHL_IDswrXU/1/da"><img src="http://feedads.g.doubleclick.net/~a/B_6ycKjIhMVNg0KmpHL_IDswrXU/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/N7enTb5jM80" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Engine I: Preparándonos para trabajar</title>
		<link>http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/</link>
		<comments>http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/#comments</comments>
		<pubDate>Thu, 08 Apr 2010 01:46:52 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RPG]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=291</guid>
		<description><![CDATA[Para un proyecto de tal magnitud lo primero que necesitamos es organizarnos bien y planificarlo todo, porque si no luego a medida que el programa crece todo se complica y se vuelve lioso, en esta primer artículo vamos a ver las herramientas que necesitaremos, crear un directorio base y archivos necesarios. Antes de empezar Yo [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-292" title="engine" src="http://razonartificial.com/wp-content/uploads/2010/04/engine.jpg" alt="" width="190" height="150" />Para un proyecto de tal magnitud lo primero que necesitamos es organizarnos bien y planificarlo todo, porque si no luego a medida que el programa crece todo se complica y se vuelve lioso, en esta primer artículo vamos a ver las herramientas que necesitaremos, crear un directorio base y archivos necesarios.</p>
<h2>Antes de empezar</h2>
<p>Yo voy a programar nuestro engine en un entorno Linux, todo lo aquí explicable puede ser perfectamente aplicable a otros Sistemas Operativos, pero en un principio cosa como las rutas a archivos estarán escritas para sistemas Unix, porque prefiero trabajar así y luego usar el módulo OS para generalizarla pasa todos los SO, tú puedes generalizarlas directamente o usar el sistema de rutas de tu sistema (esto es para los que trabajen con Windows sobre todo que usa la barra invertida (\) para los directorios).<span id="more-291"></span></p>
<h2>Herramientas Necesarias</h2>
<ul>
<li><strong>Python</strong>. Yo voy a trabajar con la versión 2.6.x de Python, pero pasarlo todo a Python 3.x no creo que sea muy complicado para el que lo conozca.</li>
<li><strong>Pygame</strong>. Obviamente, será nuestra biblioteca gráfica.</li>
<li><strong>Geany</strong>. Este es el IDE que yo voy a usar, tú usa con el que te sientas más a gusto.</li>
<li>Usaremos más herramientas, pero las iremos viendo a lo largo de los artículos y a medida que avancemos.</li>
</ul>
<h2>Creando un espacio de trabajo</h2>
<p>Vamos a necesitar crear un directorio específico para nuestro proyecto donde meteremos todas nuestras carpetas y archivos ordenadamente. Yo he creado un directorio base llamado engine y dentro por el momento tengo dos carpetas: <strong>graphics</strong> y <strong>maps</strong>, y también tengo mi archivo <a href="http://razonartificial.com/wp-content/uploads/2010/03/plantilla.zip">plantilla.py</a> para crear nuevos archivos al vuelo con solo copiar y pegar. por tanto mi carpeta base queda de la siguiente manera:</p>
<ul>
<li>engine
<ul>
<li>graphics</li>
<li>maps</li>
<li><a href="http://razonartificial.com/wp-content/uploads/2010/03/plantilla.zip">plantilla.py</a></li>
</ul>
</li>
</ul>
<p>A medida que nuestro proyecto crezca iremos añadiendo carpetas y archivos que debemos siempre mantener organizado para saber en que lugar está cada cosa.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/" title="Engine XI: Creando al héroe">Engine XI: Creando al héroe</a></li><li><a href="http://razonartificial.com/2010/06/engine-x-la-clase-mapa-iii/" title="Engine X: La clase mapa III">Engine X: La clase mapa III</a></li><li><a href="http://razonartificial.com/2010/06/engine-ix-cargando-el-tileset/" title="Engine IX: Cargando el tileset">Engine IX: Cargando el tileset</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/f8onhJDtqhVbDtK6OAABZkB94m4/0/da"><img src="http://feedads.g.doubleclick.net/~a/f8onhJDtqhVbDtK6OAABZkB94m4/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/f8onhJDtqhVbDtK6OAABZkB94m4/1/da"><img src="http://feedads.g.doubleclick.net/~a/f8onhJDtqhVbDtK6OAABZkB94m4/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/V2j7q39XLS4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Haciendo un engine para juegos</title>
		<link>http://razonartificial.com/2010/04/haciendo-un-engine-para-juegos-con-python-y-pygame/</link>
		<comments>http://razonartificial.com/2010/04/haciendo-un-engine-para-juegos-con-python-y-pygame/#comments</comments>
		<pubDate>Thu, 08 Apr 2010 01:05:55 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Engine]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RPG]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=287</guid>
		<description><![CDATA[Estos días he estado programando una especie de engine para juegos con Python y Pygame, me pareció una buena idea escribir aquí una serie de artículos dedicado a lo que voy haciendo y las dificultades con las que me voy encontrando. Digo desde ya que yo no tengo experiencia programando este tipo de cosas y [...]]]></description>
			<content:encoded><![CDATA[<p>Estos días he estado programando una especie de engine para juegos con Python y Pygame, me pareció una buena idea escribir aquí una serie de artículos dedicado a lo que voy haciendo y las dificultades con las que me voy encontrando. Digo desde ya que yo no tengo experiencia programando este tipo de cosas y que lo que voy a exponer aquí posiblemente no sea la mejor forma de hacerlo, por eso espero que con estos artículos a través de los comentarios podamos ayudarnos entre todos a mejorarlo y a aprender cosas nuevas.</p>
<h2>Creando un engine</h2>
<p>Un engine es lo que llamamos el motor del juego, es decir, lo que controla los aspectos más básicos del mismo para sobre él crear nuestro juego. Controla cosas como el dibujado de la pantalla, la gestión del sonido, la entradas que hay por teclado, etc. Es decir, es lo que hace que luego programar el juego resulte muy sencillo sobre este motor.</p>
<p>Python no es creo que sea el lenguaje más adecuado para programar un motor de videojuegos, aunque este sea 2D, C++ sería mucho mas apropiado para este propósito y luego ya si se podría usar Python para escribir el juego sobre este, pero como esto lo hacemos por diversión y por aprender las bases, no es cuestión de complicarse la vida con C++ y vamos a hacerlo con Python y Pygame, que con los ordenadores de hoy en día y siendo un juego en 2D las diferencia de rendimiendo no se notarán, además todo lo que aprenderemos aquí en cuanto a técnicas es totalmente aplicable a C++ y una biblioteca como SDL (Pygame solo es un port de SDL a Python).</p>
<h2>¿Qué tipo de juego?</h2>
<p>Es importante definir para que tipo de juego va a ser nuestro motor, para a partir de ahí enfocar lo que necesitamos. Yo lo que voy a crear es un engine para hacer un RPG (juegos de rol), pero también me interesaba crear uno para RTS (juegos de estrategia) por curiosidad, así que aunque el engine sea para RPG en ocasiones escribiré artículos dedicado a hacer ciertas rutinas para RTS.</p>
<p>Nuestro Engine será para los tipicos juegos RPG en 2D que podemos ver para consolas portátiles y en los famosos <a href="http://i44.tinypic.com/2h51eae.gif">RPG Makers</a>, es decir, juegos basados en tiles visto desde arriba con proyección ortogonal.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/avances-del-engine-rpg-anadido-el-scroll/" title="Avances del Engine RPG: Añadido el Scroll">Avances del Engine RPG: Añadido el Scroll</a></li><li><a href="http://razonartificial.com/2010/06/engine-xi-creando-al-heroe/" title="Engine XI: Creando al héroe">Engine XI: Creando al héroe</a></li><li><a href="http://razonartificial.com/2010/06/engine-vii-la-clase-mapa-i/" title="Engine VII: La clase Mapa I">Engine VII: La clase Mapa I</a></li><li><a href="http://razonartificial.com/2010/06/engine-x-la-clase-mapa-iii/" title="Engine X: La clase mapa III">Engine X: La clase mapa III</a></li><li><a href="http://razonartificial.com/2010/06/engine-ix-cargando-el-tileset/" title="Engine IX: Cargando el tileset">Engine IX: Cargando el tileset</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/9T1D2-9hfLCe6gGT9yk8tT2UTkI/0/da"><img src="http://feedads.g.doubleclick.net/~a/9T1D2-9hfLCe6gGT9yk8tT2UTkI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/9T1D2-9hfLCe6gGT9yk8tT2UTkI/1/da"><img src="http://feedads.g.doubleclick.net/~a/9T1D2-9hfLCe6gGT9yk8tT2UTkI/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/4L_V8RvWUWc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/04/haciendo-un-engine-para-juegos-con-python-y-pygame/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Usando Pilas Binarias en Pathfinding A*</title>
		<link>http://razonartificial.com/2010/04/usando-pilas-binarias-en-un-pathfinding-a/</link>
		<comments>http://razonartificial.com/2010/04/usando-pilas-binarias-en-un-pathfinding-a/#comments</comments>
		<pubDate>Sat, 03 Apr 2010 05:43:32 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[A*]]></category>
		<category><![CDATA[Búsqueda]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Pathfinding]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=269</guid>
		<description><![CDATA[Este artículo es un anexo al artículo principal, “A* Pathfinding. Camino óptimo” . Deberías leer ese artículo, o comprender el A* a fondo, antes de leer este artículo. Una de las partes más lentas del algoritmo A*, es encontrar el cuadro o nodo de la lista abierta con la menor puntación F. Dependiendo del tamaño [...]]]></description>
			<content:encoded><![CDATA[<p>Este artículo es un anexo al artículo principal, <em>“<a href="http://razonartificial.com/2010/03/a-pathfinding-camino-optimo/">A* Pathfinding. Camino óptimo</a>” . Deberías leer ese artículo, o comprender el A* a fondo, antes de leer este artículo. </em></p>
<p>Una de las partes más lentas del algoritmo A*, es encontrar el cuadro o nodo de la lista abierta con la menor puntación F. Dependiendo del tamaño de tu mapa, podrías tener docenas, cientos o incluso miles de nodos donde buscar en cualquier momento mientras usas el A*. No necesito decir, que buscar repetidamente en una lista que sea grande puede enlentecer mucho las cosas. Sin embargo, la cantidad de tiempo que lleva hacer esto puede ser influenciada por la forma en la que elijas salvar los elementos de tu lista abierta.<span id="more-269"></span></p>
<h2>Listas abiertas Ordenas y Desordenadas: Una Simple Aproximación</h2>
<p>Una forma realmente fácil de almacenar la lista abierta es guardar cada elemento cuando se necesite, y recorrer la lista completa cada vez que necesites sacar algo de la lista buscando el elemento de coste menor. Esto proporciona rápidas inserciones en la lista, pero será posiblemente más lento de quitar ya que necesitas comprobar todos los elementos de la lista para asegurarte de que tienes el elemento de coste F más bajo.</p>
<p>Normalmente puedes mejorar la ejecución de tu programa manteniendo lista ordenada. Lleva un poco más de trabajo; porque cada vez que añades un elemento a la lista, necesitas insertarlo en el lugar adecuado. Sin embargo, eliminar elementos es rápido. Solo sacas el primer elemento que es el que tiene el coste más bajo posible.</p>
<p>Hay muchas formas de mantener tus datos ordenados (selection sorts, bubble sorts, quick sorts, etc.) y puedes encontrar artículos en internet acerca del tema, simplemente incluyendo los términos en tu buscador favorito. De todas formas puede que al menos captes unas ideas aquí. Un enfoque realmente simple sería empezar al principio de tu lista cada vez que necesites añadir un nuevo elemento, y luego comparar sucesivamente el coste F del nodo actual que estás añadiendo a la lista con cada elemento que ya esté en ella. Una vez que hayas encontrado un nodo en la lista con un coste F igual o mayor, podrías insertar el nuevo elemento antes de ese que has encontrado. Dependiendo del lenguaje que estés usando, las listadas enlazadas usando clases o las estructuras (tipos en darkbasic y blitz), son probablemente las mejores opciones.</p>
<p>Este enfoque podría mejorarse  manteniendo la pista del coste F medio de los elementos que ya están en la lista, y usando eso para decidir si empezar al principio de la lista (como se describe más abajo) o empezar al final de la lista y seguir hasta el principio de la lista. En general, las inserciones de nuevos elementos con menor coste que la F media, deberían empezar al principio de la lista y avanzar, mientras que elementos nuevos con una F sobre la media deberían ir al final e ir retrocediendo. Este enfoque acorta el tiempo de búsqueda a la mitad.</p>
<p>Más complicado pero más rápido sería llevando esa idea al siguiente nivel, usando una quick sort (clasificación rápida), que básicamente empieza comparando el coste F del nuevo elemento con el elemento de la mitad de la lista. Si el nuevo elemento tiene un coste menor, deberías compararlo con el elemento que esté a 1/4 de la longitud de la lista, si es menor a 1/8, y así sucesivamente hasta que encuentres el lugar adecuado</p>
<h2>Pilas Binarias (Binary  Heaps   )</h2>
<p>Los pilas binarios son muy similares al método quick sort que acabamos de describir, y frecuentemente los usan personas que desean mantener sus funciones A*, tan rápidas como sea posible. En mi experiencia, usar un pila binario ha acelerado la búsqueda de 2 a 3 veces de media, y más aún en mapas mayores con muchos nodos (me refiero a un mapa de 100 x 100 nodos o más). No obstante, he de decir que los pilas binarios son un poco complicados y no deberían ser un dolor de cabeza a menos que estés usando un mapa con muchos nodos, donde ganar velocidad es crucial.</p>
<p>El resto de este artículo se dedica a explicar pilas binarios y su uso en A*. Hay también una sección de Más Información al final de esta página la cual te dará perspectivas adicionales, si la mía te ha dejado totalmente desconcertado.</p>
<p>¿Aún estás interesado? De acuerdo, allá vamos&#8230;</p>
<p>En una lista ordenada, cada elemento de la lista está en el orden correcto, de menor a mayor o de mayor a menor. Esto es útil, pero ahora es más de lo que necesitamos realmente. En estos momentos no nos importa si el número 127 es menor que el 128 de la lista. Lo verdaderamente importante es que tengamos el elemento con el coste F menor, al principio de la lista. El resto de la lista puede ser un revoltijo sin sentido. Mantener el resto de la lista debidamente ordenado es solo trabajo innecesario hasta que, por supuesto, necesitemos el siguiente elemento con la F más baja.</p>
<p>Básicamente, lo que andamos buscando es algo llamado &#8220;pila&#8221; o, más específicamente, una pila binaria. Una pila binaria es un conjunto de elementos donde el elemento menor o el mayor (dependiendo de lo que quieras) está al principio de la pila. Cuando estemos buscando el elemento con el coste F más bajo, lo pondremos en lo más alto de nuestra pila. Este elemento tiene dos hijos, cada uno de los cuales tiene un coste F igual  o un poco mayor que él, y cada uno de esos hijos tienen a su vez dos hijos que tienen un coste igual o un poco mayor que ellos&#8230; y así hasta el final. Aquí hay algo que podría ser una pila:</p>
<p><img class="aligncenter size-full wp-image-278" title="binary1" src="http://razonartificial.com/wp-content/uploads/2010/04/binary1.gif" alt="" width="116" height="57" /></p>
<p>Observa que el el elemento menor de la lista (10) está en todo lo alto y el segundo menor (20) es uno de sus hijos. En esta particular pila binaria, el tercer elemento con el coste menor de la lista es el 24, el cual está a dos pasos del principio y es menor que 30, el cual está solo a un paso del 10 y situado a su izquierda. No importa el valor de los otros elementos de la pila, cada elemento individual, solo necesita ser igual o mayor que su padre, e igual o menor que sus dos hijos. Estas condiciones representan una pila binaria válida.</p>
<p>Llegados a este punto, probablemente estés pensando en el modesto interés de todo esto. ¿Cómo vas a usar esos conceptos de una manera práctica? Una de las cosas interesantes sobre pilas es que puedes guardarlas en matriz unidimensional.</p>
<p>En esta matriz, el elemento al principio de la pila estaría en la primera posición de la matriz (posición 1, no posición 0 cosa posible en una matriz). Sus dos hijos deberían estar en las posiciones 2 y 3. Los 4 hijos de esos 2 elementos estarían en las posiciones 4-7.</p>
<p><img class="aligncenter size-full wp-image-279" title="binary2" src="http://razonartificial.com/wp-content/uploads/2010/04/binary2.jpg" alt="" width="203" height="108" /></p>
<p>En resumen, los dos hijos de cualquier elemento de la pila, pueden localizarse en la matriz, multiplicando la posición del elemento actual en la matriz por dos (para encontrar al primer hijo) y por dos mas uno (para encontrar al segundo). Así, por ejemplo, los 2 hijos del tercer elemento de nuestra pila (con un valor de 20), se encuentran en las posiciones 2&#215;3 = 6, y 2&#215;3 +1=7 de la matriz. En este caso, los números de esas posiciones son 30 y 24 respectivamente, cosa que cobra sentido cuando miras la pila.</p>
<p>Con 7 elementos, se llena completamente cada fila de una pila de 3 niveles. Sin embargo, esto no es obligatorio. Para que nuestra pila sea válida, lo único que necesitamos es llenar cada fila que haya sobre el último nivel. Podemos tener cualquier número de elementos en el nivel inferior y los nuevos elementos se irán añadiendo en ese nivel de izquierda a derecha. El método descrito en este artículo hace esto, así que no necesitas preocuparte por esto.</p>
<h2>Añadiendo Elementos Al Montón</h2>
<p>Necesitaremos considerar algunas cosas antes de que podamos usar una pila en un pathfinding, pero por ahora solo vamos a aprender lo básico de su uso. Te sugeriría que hojeases esta parte para comprender los principios. Más tarde, te daré una fórmula que te librará de todo esto, pero aún es importante que comprendas como funcionan las cosas.</p>
<p>En general, para añadir elementos a la pila, los colocamos al final de la matriz. Después los comparamos a sus padres, quienes están en la posición (elementos en la pila)/2 redondeando la parte fraccional hacia abajo. Si el coste F del nuevo elemento es menor, no saltamos esos 2 elementos. Luego comparamos el nuevo elemento con su padre que está en la posición (posición actual en la pila)/2, redondeando hacia abajo. Si su valor F es menor, los saltamos de nuevo. Repetimos este proceso hasta que el elemento no se menor que su padre, o hasta que el elemento haya rebasado el principio de la pila, lo que representa la posición 1 de la matriz.</p>
<p>Supongamos que añadimos un elemento con una F de 17 a nuestra pila. En este momento tenemos 7 elementos en ella, así que el nuevo elemento debería situarse en la posición número 8. Así queda la pila; el nuevo elemento está subrayado:</p>
<p>10 30 20 34 38 30 24 <span style="text-decoration: underline;">17</span></p>
<p>Luego comparamos este elemento con su padre, el cual esta en la posición 8/2 = posición 4. El valor F del elemento que ahora mismo está en la posición 4 es 34. Ya que 17 es menor que 34 intercambiamos sus respectivas posiciones.</p>
<p>10 30 20 <span style="text-decoration: underline;">17</span> 38 30 24 34</p>
<p>Después lo comparamos con su nuevo padre. Como está en la posición 4 lo comparamos con el elemento en la posición 2 (4/2=2). Ese elemento tiene una puntuación F de 30. Ya que 17 es menor que 30, y ahora nuestra pila sería así:</p>
<p>10 <span style="text-decoration: underline;">17</span> 20 30 38 30 24 34</p>
<p>Luego lo comparamos con su nuevo padre. Ahora que está en la posición 2, lo comparamos con la posición 1 (2/2), que es la posición del primer elemento de la pila. En este caso, 17, no es menor que 10, así que nos paramos y dejamos la pila como está.</p>
<h2>Quitando Elementos de la Pila</h2>
<p>Eliminar elementos de la pila, implica un proceso similar, pero en orden inverso. Primero, quitamos el elemento del hueco 1, que ahora se quedaría vacío. Luego cogemos el último elemento de la pila y lo llevamos al hueco 1. Tomando como ejemplo la pila anterior, ahora tenemos que el que antes fue el último elemento de la pila ahora está subrayado:</p>
<p><span style="text-decoration: underline;">34</span> 17 20 30 38 30 24</p>
<p>Lo siguiente es comparar el elemento con cada uno de sus hijos, los cuales están en las posiciones (posición actual x 2) y (posición actual x 2+1). Si tiene una puntuación menor que sus 2 hijos, se queda donde está. Si no, intercambiamos su posición con el menor de sus hijos. Así que, en este caso, los dos hijos del elemento en la posición 1, están en la posición 1&#215;2=2 y 1&#215;2+1=3. Ya que 34 no es menor que sus hijos lo intercambiamos por el menor de ellos, en este caso el 17. La cosa queda así:</p>
<p>17 <span style="text-decoration: underline;">34</span> 20 30 38 30 24</p>
<p>Ahora comparamos el elemento con sus 2 hijos, que están en la posición 2&#215;2=4, y 2&#215;2+1=5. Como 34 no es menor que sus hijos lo intercambiamos por el menor (el 30 en la posición 4). Ahora nos sale esto:</p>
<p>17 30 20 <span style="text-decoration: underline;">34</span> 38 30 24</p>
<p>Por último comparamos el elemento con su nuevo hijo. Como ya sabes, están en las posiciones 4&#215;2=8 y 4&#215;2+1=9. Sin embargo, no hay ningún hijo en esas posiciones, esto se debe a que la lista no es tan larga. Hemos alcanzado el último nivel de la pila, así que paramos.</p>
<h2>¿Porqué una Pila Binaria es tan Rápida?</h2>
<p>Ahora que sabes los principios de la inserción y borrado en una pila, deberías empezar a ver por qué es mucho más rápido, que por ejemplo, un insertion sort. Imagina que tienes una lista abierta con 1000 nodos, cosa que no es imposible en un mapa respetable con muchos nodos (recuerda que un mapa de solo 100 x 100 nodos, tiene 10000). Si hicieses un simple insertion sort, empezarías al principio de la lista, y procederías hasta encontrar la posición adecuada para insertar el nuevo elemento, tendrías que hacer una media de 500 comparaciones antes de insertarlo en el lugar adecuado.</p>
<p>Usando una pila binaria, solo necesitas hacer una media de 1-3 comparaciones para insertarlo en el lugar correcto, empezando desde el final. También necesitarías hacer una media de 9 comparaciones para eliminar de la lista abierta y reordenar la pila apropiadamente. En un A*, normalmente eliminas un nodo en cada paso (el elemento con el coste F más bajo), y usualmente añades en cualquier lugar de 0 a 5 nodos (usando el enfoque 2D descrito en el artículo principal). Esto puede alcanzar más o menos el 1% del tiempo que lleva hacer una insertion sort con el mismo número de nodos. La diferencia se hará geométricamente más importante en mapas mayores (con más nodos). En comparación, mapas más pequeños, ganan paulatinamente menos ventaja, cosa que se debe a que las pilas binarias pierden su importancia cuanto más pequeño sea el mapa y su número de nodos sea menor.</p>
<p>De todas formas, solo porque vayas a usar una pila binaria, no significa que tu algoritmo vaya a ser 100 más rápido (o lo que sea). En un algoritmo A*, hay muchas cosas más importantes que ordenar solamente la lista abierta. Sin embargo, mi experiencia me dice que usar pilas binarias hace que tu algoritmo pathfinding sea en muchos casos, 2 o 3 veces más rápido, tal vez incluso más en caminos largos.</p>
<h2>Creando una Lista Abierta</h2>
<p>Ahora que sabemos lo que es una pila, ¿Cómo vamos a usarla? Lo primero que necesitamos hacer es dimensionar nuestra matriz mono-dimensional apropiadamente. Para hacer esto, lo primero que necesitamos es hacernos una idea de como será posiblemente de grande. Por norma, la lista no puede ser mayor que el número total de nodos de nuestro mapa (asumiendo en el peor de los casos, un escenario donde el camino se busque teniendo en cuenta todo el mapa). En un cuadrado mapa bidimensional como el que describí en el artículo principal, no tendremos más de <em>AnchoMapa</em> x <em>AltoMapa</em> nodos. Es una indicación de que tan grande será nuestra matriz unidimensional. Por el bien de este ejemplo, nosotros llamaremos a esta matriz l<em>istaAbierta()</em>. El elemento superior se guardará en <em>listaAbierta(1)</em>, el segundo en la pila estará en <em>listaAbierta(2)</em>, y así.</p>
<h2>Usando Punteros</h2>
<p>Ahora que tenemos una pila/matriz unidimensional con el tamaño adecuado, estamos casi listos para empezar a usarlo para un pathfinding. Antes de que vayamos más lejos, vamos a echar de nuevo un vistazo a nuestra pila original antes de añadir o quitar nada.</p>
<p><img class="aligncenter size-full wp-image-280" title="binary3" src="http://razonartificial.com/wp-content/uploads/2010/04/binary3.jpg" alt="" width="203" height="108" /></p>
<p>Ahora mismo, es solo una lista de valores de F organizados debidamente. Pero olvidamos un elemento importante. Claro que tenemos un grupo de valores F organizados por orden en una pila binaria, pero no tenemos pistas de a que cuadros pertenecen. Básicamente, lo único que sabemos ahora mismo, es que el 10 es el menor valor de la pila. Pero, ¿a qué cuadrado de nuestro mapa hace referencia?</p>
<p>Para solucionar este problema, necesitamos cambiar los valores de los elementos de la matriz. En vez de guardar el valor F en la matriz, necesitamos guardar un único número identificador que nos indique a qué cuadro se refiere. Mi idea es crear un único ID (número identificador) asociado con cada nuevo elemento añadido a la pila, llamado <em>cuadrosComprobados.</em> Cada vez que añadimos un elemento a la lista abierta, incrementamos <em>cuadrosComprobados</em> en uno y lo usamos como único ID para los nuevos elementos añadidos a la lista abierta. El primer elemento añadido es el elemento 1, el segundo el 2,&#8230;</p>
<p>Por último, necesitamos guardar el coste actual de ese cuadro en una tabla unidimensional a parte, a la que llamo <em>costeF()</em>. Al igual que la matriz listaAbierta, el tamaño será el mismo,  <em>AnchoMapa</em> x <em>AltoMapa. </em>También guardaremos las coordenadas x e y del nodo en el mapa, en matrices unidimensionales similares, que llamaré <em>abiertoX()</em> y <em>abiertoY()</em>. Se parecería a la siguiente ilustración:</p>
<p><img class="aligncenter size-full wp-image-281" title="binary4" src="http://razonartificial.com/wp-content/uploads/2010/04/binary4.jpg" alt="" width="308" height="182" /></p>
<p>Aunque esto parezca un poco más complicado, es la misma pila que la anterior. La diferencia está en que ahora tenemos mucha más información.</p>
<p>El elemento 5 (con el costeF menor &#8211; 10) aún sigue al principio de la pila y en la primera columna de nuestra matriz unidimensional. Pero ahora estamos guardando un ID único de 5 en vez de su coste F en la pila. En otras palabras,  <em>listaAbierta(1)</em> = 5. Este número único se usa luego, para mirar el costeF del elemento y su localización X e Y en el mapa. El costeF de este elemento es costeF(5)=10, su localización en el mapa es,  abiertoX(5)=12 y abiertoY(5)=22.</p>
<p>El elemento superior de la pila tiene 2 hijos, los elementos con el número 2 y el 6, tienen un costeF de 30 y 20 respectivamente y están en las posiciones 2 y 3 de la <em>listaAbierta()</em>, y así hasta el final. En resumen, tenemos exactamente la misma pila que teníamos al principio, solo que con mucha más información, ahora sabemos donde está el elemento en el mapa y su costeF.</p>
<h2>Añadiendo Nuevos Elementos a la Pila (Parte 2)</h2>
<p>Ahora vamos a aplicar esta técnica para ordenar nuestra lista de una forma que sea útil en un algoritmo de un pathfinding A*. Usaremos exactamente las mismas técnicas explicadas anteriormente.</p>
<p>El primer elemento que añadamos a la lista abierta, es normalmente el nodo principal y se le asigna un ID único, en este caso 1. Luego lo ponemos en la posición 1 de la lista abierta. En otras palabras, listaAbierta(1)=1. También mantenemos un seguimiento al número de elementos de nuestra lista, que es 1 por ahora. Guardamos este número en una variable llamada <em>numeroDeElementosEnListaAbierta.</em></p>
<p>Así que, añadimos nuevos nodos a la lista abierta, calculando sus puntuaciones G, H y F, como está descrito en el artículo principal. Después los añadimos a la pila binaria como está señalado más arriba.</p>
<p>Primero asignamos el nuevo elemento a un ID único para la variable <em>cuadrosComprobados</em>. Le sumamos 1 cada vez que añadamos un nuevo nodo, y asignamos este número al nuevo nodo. Luego sumamos 1 a <em>numeroDeElementosEnListaAbierta,</em> y después lo añadimos al final de la lista abierta. Todo lo anterior se traduce en lo siguiente:</p>
<pre>cuadrosComprobados = cuadrosComprobados +1
numeroDeElementosEnListaAbierta= numeroDeElementosEnListaAbierta+1
listaAbierta(numeroDeElementosEnListaAbierta) = cuadrosComprobados</pre>
<p>Después hacemos sucesivas comparaciones con su padre hasta que alcance su lugar apropiado en la pila. Aquí hay algún código que lo hace:</p>
<pre>m = numeroDeElementosEnListaAbierta
While m &lt;&gt; 1 ;Mientras que el elemento no ha alcanzado el principio(m=1)

	;Comprueba si el hijo es &lt;= padre. Si es así los intercambia.
	If costF(listaAbierta(m)) &lt;= costF(listaAbierta(m/2)) Then
		temp = listaAbierta(m/2)
		listaAbierta(m/2) = listaAbierta(m)
		listaAbierta(m) = temp
		m = m/2
	Else
		Exit ;sale del bucle while/wend
	End If
Wend</pre>
<h2>Borrando Elementos de la Pila (Parte 2)</h2>
<p>Por supuesto, no solo construimos una pila, también necesitamos borrar elementos de ella cuando ya no los vayamos a utilizar de nuevo. Específicamente en el pathfinding A*, necesitamos borrar el elemento con el coste F menor del principio de la lista después de haberlo comprobado y pasado a la lista cerrada.</p>
<p>Antes describimos como se empieza moviendo el <em>ultimo</em> elemento de la pila hasta la primera posición, y luego reducimos el número de elementos de la lista en uno. En pseudocódigo sería así:</p>
<pre>listaAbierta(1) = listaAbierta(numeroDeElementosEnListaAbierta)
numeroDeElementosEnListaAbierta = numeroDeElementosEnListaAbierta - 1</pre>
<p>Lo siguiente que necesitamos hacer es sucesivas comparaciones entre este valor y sus dos hijos. Si tiene una puntuación F mayor que alguno de ellos, intercambiaremos su posición con el menor. Luego comparamos el elemento con sus 2 nuevos hijos (ahora que está más abajo en la pila). Si tiene su F es mayor que cualquiera de sus hijos, lo intercambiamos por el menor. Repetimos este proceso hasta que el elemento encuentre su lugar correcto, que podría ser el final de la pila, pero no necesariamente. Aquí tienes el pseudocódigo de lo dicho:</p>
<pre>;Repite lo siguiente hasta que el elemento encaje en su lugar adecuado en la pila.
Repeat
	u = v
	If 2*u+1 &lt;= numeroDeElementosEnListaAbierta ;si ambos hijos existen 		;Selecciona el menor hijo de los 2. 		If costF(listaAbierta(u)) &gt;= costF(listaAbierta(2*u)) then v = 2*u ;VER NOTA MÁS ABAJO
		If costF(listaAbierta(v)) &gt;= costF(listaAbierta(2*u+1)) then v = 2*u+1 ;VER NOTA MÁS ABAJO

	Else If 2*u &lt;= numeroDeElementosEnListaAbierta ;si solo el hijo 1 existe 		;Comprueba si el coste F es mayorque el del hijo 		If costF(listaAbierta(u)) &gt;= costF(listaAbierta(2*u)) then v = 2*u
	End If

	If u &lt;&gt; v then ; Si el F del padre &gt; al de uno o al de los dos hijos, los intercambia
		temp = listaAbierta(u)
		listaAbierta(u) = listaAbierta(v)
		listaAbierta(v) = temp
	Else
		Exit ;si el elemento &lt;= que ambos hijos, sale del bucle repeat/forever
	End if
Forever ;Repetir siempre</pre>
<p>Por favor, observa en el código, la u y la v en negrita (en rojo) . En la segunda línea, quieres usar v, no u, cosa que podría no ser inmediatamente obvia. Esto te asegura que acabes intercambiando con el menor de los 2 hijos. Fallar haciendo esto, te dará una pila errónea, y joderá tu pathfinding completamente.</p>
<h2>Reordenando un Elemento Existente en una Lista Abierta</h2>
<p>Tal y como se describió en el artículo principal, llegará un momento en el que te des cuenta que la puntuación F de una lista puede cambiar. Cuando eso ocurre, no necesitas sacar el elemento de la lista y empezar todo de nuevo. Simplemente empiezas en su posición actual, y lo comparas con su padre usando su nueva (y menor) puntuación F. En general, usamos el mismo código descrito en la sección &#8220;Añadiendo un Elemento a la Pila&#8221;  con la siguiente consideración adicional:</p>
<p>Desafortunadamente, debido a que tus datos son una enorme y aparentemente desordenada pila, necesitas recorrerla por completo para encontrar un elemento en su interior. Básicamente estarás buscando el cuadro con las coordenadas x e y correctas, como se indica en abiertoX(listaAbierta()) y  abiertoY(listaAbierta()). Sin embargo, después de encontrarlo, puedes proceder normalmente haciendo las comparaciones necesarias y empezando los intercambios desde su posición dentro de la pila.</p>
<h2>Notas Finales</h2>
<p>Tengo la esperanza de que si has llegado hasta aquí y aún estás leyendo , significa que no estás totalmente confundido. Si no te sientes intimidado, y quieres codificar tu propia pila binaria para tu propio algoritmo de pathfinding, entonces esto es lo que te sugiero:</p>
<p>Primero, olvida las pilas binarias por un momento. Concéntrate en conseguir que tu algoritmo A* funcione correctamente y que esté libre de errores usando un método simple para ordenar. Al principio solo necesitas que funcione, no que vaya rápido.</p>
<p>Segundo, antes de que añadas una pila binaria al código, intenta codificar una pila binaria aparte que haga lo que tu quieras, añadiendo y substrayendo elementos de la pila de una forma correcta. Asegúrate de escribir el programa de forma que puedas reconocer qué función realiza cada paso del proceso, quizá imprimiendo los resultados en la pantalla conforme lo vayas ejecutando. Deberías incluir alguna tecla de escape en el programa que te permita salir si fuera necesario, es muy fácil quedar atrapado en un bucle sin fin si no has escrito la pila binaria correctamente.</p>
<p>Una vez que confíes en que ambos programas funcionan perfectamente, guarda una copia de los 2, y luego empieza a trabajar en unirlos. Amenos que seas mucho más listo que yo, probablemente tendrás problemas al principio. Signos de tus errores serán extraños mensaje de error y misteriosos caminos ilógicos. No desesperes, al final lo conseguirás.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/04/pathfinding-a-de-2-niveles/" title="Pathfinding A* de 2 niveles">Pathfinding A* de 2 niveles</a></li><li><a href="http://razonartificial.com/2010/04/heuristica-para-el-pathfinding-a-star/" title="Heurística para el Pathfinding A*">Heurística para el Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/" title="Pathfinding A* en Python. Parte III">Pathfinding A* en Python. Parte III</a></li><li><a href="http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/" title="Pathfinding A* en Python. Parte I">Pathfinding A* en Python. Parte I</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-ii/" title="Pathfinding A* en Python. Parte II">Pathfinding A* en Python. Parte II</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/6KmdI2U7WuSlP8_P_t_B5XSz32U/0/da"><img src="http://feedads.g.doubleclick.net/~a/6KmdI2U7WuSlP8_P_t_B5XSz32U/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/6KmdI2U7WuSlP8_P_t_B5XSz32U/1/da"><img src="http://feedads.g.doubleclick.net/~a/6KmdI2U7WuSlP8_P_t_B5XSz32U/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/dzPrxZghz68" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/04/usando-pilas-binarias-en-un-pathfinding-a/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Pathfinding A* de 2 niveles</title>
		<link>http://razonartificial.com/2010/04/pathfinding-a-de-2-niveles/</link>
		<comments>http://razonartificial.com/2010/04/pathfinding-a-de-2-niveles/#comments</comments>
		<pubDate>Sat, 03 Apr 2010 05:13:44 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[A*]]></category>
		<category><![CDATA[Búsqueda]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Pathfinding]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=262</guid>
		<description><![CDATA[En mi artículo principal de A* Pathfinding, describí el A* en términos generales, también describí cómo crear una única función de uso general. Sin embargo, crear solo una función de pathfinding puede ser innecesariamente limitado. Considera la siguiente situación en un RPG, donde un guerrero quiere encontrar el camino tras el muro cercano: Con esta [...]]]></description>
			<content:encoded><![CDATA[<p>En mi artículo <a href="http://razonartificial.com/2010/03/a-pathfinding-camino-optimo/">principal de </a><em><a href="http://razonartificial.com/2010/03/a-pathfinding-camino-optimo/">A* Pathfinding</a></em>, describí el A* en términos generales, también describí cómo crear una única función de uso general. Sin embargo, crear solo una función de pathfinding puede ser innecesariamente limitado.</p>
<p>Considera la siguiente situación en un RPG, donde un guerrero quiere encontrar el camino tras el muro cercano:<br />
<img class="aligncenter size-full wp-image-263 imageborder" title="noNodes" src="http://razonartificial.com/wp-content/uploads/2010/04/noNodes.jpg" alt="" width="256" height="182" /><br />
Con esta clase de mapa, podrías situar los nodos de muchas maneras, y usar también, cantidad de densidades. En este ejemplo, vamos a usar una red de nodos de densidad alta, tal y como se muestra en la siguiente imagen:<span id="more-262"></span><br />
<img class="aligncenter size-full wp-image-264 imageborder" title="microPathNodes1" src="http://razonartificial.com/wp-content/uploads/2010/04/microPathNodes1.jpg" alt="" width="266" height="172" /></p>
<p>En este gráfico, los nodos blancos son transitables. Las áreas donde no hay nodos son intransitables. También hemos hecho las cosas de manera un poco diferente; este ejemplo  te permite rodear esquinas alrededor de cuadros intransitables. Además, los &#8220;cuadros&#8221; en sí mismos no existen; debido a que esto es un ejemplo isométrico. Por ello hemos agrupado el doble de nodos en el eje Y (el eje vertical) que en el eje x (horizontal). Esto permite caminos isométricos más apropiados.</p>
<p>Puedes ver que usando esta red de nodos tan densamente comprimida, podemos no solo rodear muros cercanos sino que además podemos pasar entre el muro y el barril en el proceso. Nuestra densa red de nodos también permite rodear la antorcha, donde el nodo de su base es intransitable. Esto es, en suma, un pathfinding preciso.</p>
<p>Eso está bastante bien en situaciones de distancias cortas, pero, ¿qué haremos si necesitamos encontrar el camino a través del todo el mapa? Usar una red de nodos tan densa, podría fácilmente dejarte con una búsqueda de más de 10.000 nodos en un sólo y único paso a través del bucle del A*. Lo más seguro es que ante esta situación, cualquier ordenador tuviese que detenerse a calcularlo.</p>
<p>Veamos una alternativa. ¿Qué ocurre si elegimos crear una red mucho menos densa como la que tenemos abajo?<br />
<img class="aligncenter size-full wp-image-265 imageborder" title="macroNodes" src="http://razonartificial.com/wp-content/uploads/2010/04/macroNodes.jpg" alt="" width="364" height="245" /></p>
<p>En este ejemplo, los nodos están en el centro de grandes diamantes isométricos. Los datos sobre transitabilidad entre diamantes son almacenados en la misma matriz a lo largo de los bordes, y están representados en este gráfico con pequeñas manchas rojas. Para moverse desde una baldosa isométrica a una de sus 8 macro-baldosas adyacentes, la baldosa adyacente debe ser transitable, y el camino entre ambas no debe estar bloqueado.</p>
<p>Esta red de nodos es 72 veces menos densa que la anterior. En vez de manejar más de 10.000 nodos en cada momento, aquí solo manejas el 1/72 de eso, es decir, menos de 200. Nuestro ordenador, puede definitivamente manejar eso. Encontrar el camino a través del mapa ya no es un problema.</p>
<h2>Uniendo los dos.</h2>
<p>Así pues, ¿qué método elegimos? &#8230;.Ambos.</p>
<p>En cualquier búsqueda, deberías primero encontrar el camino que atraviesa el mapa usando el macro-buscador. Despues cambiarías al micro-buscador y buscarías un camino desde la localización inicial hasta dos macro-nodos más allá según el camino obtenido con el macro-buscador. Una vez que has entrado en cada nuevo macro-diamante, usarías el micro-buscador para encontrar el camino que llegue hasta el segundo de los 2 macro-nodos siguientes. Esto acaba por desechar la segunda mitad de cada micro-camino, pero necesitas hacer esto para asegurarte de que está correcto &#8211; además, tampoco se desecha mucho desde el momento que el micro-buscador atraviesa distancias relativamente cortas. Una vez que llegues a una distancia de 2 o 3 nodos del destino, deberías cambiar definitivamente al micro-buscador, y encontrar el destino final.</p>
<p>Usando esta aproximación, conseguirás mayor velocidad para cruzar el mapa completo,  <strong><span style="text-decoration: underline;">y</span> </strong>serás capaz de rodear esquinas, barriles, etc. con un camino realístico, como en el ejemplo anterior del micro-buscador.</p>
<p>Y si eres realmente ambicioso y tuviese un mapa gigantesco, podrías desarrollar 3 buscadores ; uno en un macro-nivel, otro en uno medio y otro en uno micro. Los profesionales han hecho esto para juegos como Age of Empires. Esto solo depende de lo que necesites hacer.</p>
<p>Traducido por Elthan, con el permiso de Patrick.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/04/usando-pilas-binarias-en-un-pathfinding-a/" title="Usando Pilas Binarias en Pathfinding A*">Usando Pilas Binarias en Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/heuristica-para-el-pathfinding-a-star/" title="Heurística para el Pathfinding A*">Heurística para el Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/" title="Pathfinding A* en Python. Parte III">Pathfinding A* en Python. Parte III</a></li><li><a href="http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/" title="Pathfinding A* en Python. Parte I">Pathfinding A* en Python. Parte I</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-ii/" title="Pathfinding A* en Python. Parte II">Pathfinding A* en Python. Parte II</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/dcH9s0NCP1PANCGqA-xLr92n-AA/0/da"><img src="http://feedads.g.doubleclick.net/~a/dcH9s0NCP1PANCGqA-xLr92n-AA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/dcH9s0NCP1PANCGqA-xLr92n-AA/1/da"><img src="http://feedads.g.doubleclick.net/~a/dcH9s0NCP1PANCGqA-xLr92n-AA/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/zfKVCjCRfXE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/04/pathfinding-a-de-2-niveles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Heurística para el Pathfinding A*</title>
		<link>http://razonartificial.com/2010/04/heuristica-para-el-pathfinding-a-star/</link>
		<comments>http://razonartificial.com/2010/04/heuristica-para-el-pathfinding-a-star/#comments</comments>
		<pubDate>Sat, 03 Apr 2010 04:54:38 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[A*]]></category>
		<category><![CDATA[Búsqueda]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Pathfinding]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=253</guid>
		<description><![CDATA[Como habrás visto en el artículo de Pathfinding, hay varias maneras en las que puedes calcular la heurística en A*. Se describen unas pocas aquí. También deberías leer el enlace que aparece al final. Método Manhattan Este es el método usado en el artículo principal. Su principal ventaja es que normalmente alcanzas el objetivo más [...]]]></description>
			<content:encoded><![CDATA[<p>Como habrás visto en el <a href="http://razonartificial.com/2010/03/a-pathfinding-camino-optimo/">artículo de Pathfinding</a>, hay varias maneras en las que puedes calcular la heurística en A*. Se describen unas pocas aquí. También deberías leer el enlace que aparece al final.</p>
<h2>Método Manhattan</h2>
<p>Este es el método usado en el artículo principal. Su principal ventaja es que normalmente alcanzas el objetivo más rápido que en la mayoría de alternativas. Su mayor inconveniente es que está sobrecargado en comparación con G y por lo tanto reducirá cualquier pequeño modificador que intentes añadir al cálculo, es decir, una penalización de giro o un modificador tipo mapa de influencia. Si no vas a tener en cuenta estas cosas, este método es probablemente tu mejor opción. La ecuación, donde abs= valor absoluto, es:</p>
<pre class="brush: python;">
H = 10*(abs(Xactual-Xdestino) + abs(Yactual-Ydestino))
</pre>
<h2>Atajo Diagonal</h2>
<p>Este método equilibra H y G. Su principal ventaja es esa, ya que al estar equilibrado, es completamente capaz de considerar pequeños modificadores como penalización de giro o un modificador de mapa de influencia. Es un poco más lento que el método anterior. La ecuación, donde abs= valor absoluto, es:</p>
<pre class="brush: python;">
xDistancia = abs(abs(Xactual-Xdestino)
yDistancia = abs(Yactual-Ydestino)
if xDistancia &gt; yDistancia:
	H = 14*yDistancia + 10*(xDistancia -yDistancia)
else:
	H = 14*xDistancia + 10*(yDistancia -xDistancia)
</pre>
<p>Hay muchos otros métodos de calcular H, aunque estos sean probablemente de los más comúnmente utilizados. En general, la estimación más cercana es la distancia actual hasta el objetivo, el A* más rápido encontrará esa meta. Si sobreestimas H con respecto a la distancia actual, A* no te garantizará el mejor camino (en el argot del pathfinding, a esto se llama una &#8220;heurística inadmisible&#8221;). Por lo tanto, el truco consiste en aproximarte tanto a la distancia actual como te sea posible sin sobreestimarlo. Ambos métodos son admisibles.</p>
<p>Para más información: <a href="http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html">Amit&#8217;s Notes on A* Heuristics</a></p>
<p>Traducido por Elthan, con el permiso de Patrick Lester.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/04/usando-pilas-binarias-en-un-pathfinding-a/" title="Usando Pilas Binarias en Pathfinding A*">Usando Pilas Binarias en Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-de-2-niveles/" title="Pathfinding A* de 2 niveles">Pathfinding A* de 2 niveles</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/" title="Pathfinding A* en Python. Parte III">Pathfinding A* en Python. Parte III</a></li><li><a href="http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/" title="Pathfinding A* en Python. Parte I">Pathfinding A* en Python. Parte I</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-ii/" title="Pathfinding A* en Python. Parte II">Pathfinding A* en Python. Parte II</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/ea7mLcZdO851bdHS4upjFXKl988/0/da"><img src="http://feedads.g.doubleclick.net/~a/ea7mLcZdO851bdHS4upjFXKl988/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ea7mLcZdO851bdHS4upjFXKl988/1/da"><img src="http://feedads.g.doubleclick.net/~a/ea7mLcZdO851bdHS4upjFXKl988/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/STAdIhhml7U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/04/heuristica-para-el-pathfinding-a-star/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pathfinding A* en Python. Parte III</title>
		<link>http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/</link>
		<comments>http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/#comments</comments>
		<pubDate>Fri, 02 Apr 2010 01:46:54 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[A*]]></category>
		<category><![CDATA[Búsqueda]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Pathfinding]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=244</guid>
		<description><![CDATA[Aquí está la ultima parte del Pathfinding con Python, después de hacer nuestro algoritmo le he hecho una interfaz gráfica en Pygame. Es un juego que es una mezcla de RPG y estrategia. RPG porque tienes los gráficos, movimientos y estilo de este y de Estrategia porque la mecánica es la que utilizaría un juego [...]]]></description>
			<content:encoded><![CDATA[<p>Aquí está la ultima parte del Pathfinding con Python, después de hacer nuestro algoritmo le he hecho una interfaz gráfica en Pygame. Es un juego que es una mezcla de RPG y estrategia. RPG porque tienes los gráficos, movimientos y estilo de este y de Estrategia porque la mecánica es la que utilizaría un juego de estos.</p>
<p>El juego ha sido hecho usando el algoritmo que preparamos en la parte 1 y 2, se puede ver como funciona perfectamente y encuentra todos los caminos al instante, dejo un vídeo de demostración.</p>
<p style="text-align: center;">[There is a video that cannot be displayed in this feed. <a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/">Visit the blog entry to see the video.]</a></p>
<p>La mecánica es sencilla, se usa el click izquierdo para crear  y borrar muros (en el ejemplo troncos) y click derecho para mover el personaje a un punto determinado. El ejemplo no es perfecto y tiene algunos fallos porque la intención no era mostrar Pygame sino que el algoritmo funciona con un ejemplo más real.</p>
<p>No comento el código porque todo lo nuevo es Pygame puro y duro, que ya haré más tutoriales para mostrar como crear ejemplos de rpg y estrategia.</p>
<ul>
<li><a href="http://razonartificial.com/wp-content/uploads/2010/04/buscador.zip">Descargar el ejemplo</a></li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/" title="Pathfinding A* en Python. Parte I">Pathfinding A* en Python. Parte I</a></li><li><a href="http://razonartificial.com/2010/04/usando-pilas-binarias-en-un-pathfinding-a/" title="Usando Pilas Binarias en Pathfinding A*">Usando Pilas Binarias en Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-de-2-niveles/" title="Pathfinding A* de 2 niveles">Pathfinding A* de 2 niveles</a></li><li><a href="http://razonartificial.com/2010/04/heuristica-para-el-pathfinding-a-star/" title="Heurística para el Pathfinding A*">Heurística para el Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-ii/" title="Pathfinding A* en Python. Parte II">Pathfinding A* en Python. Parte II</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/KmpQ0SupurQ3-1CzzYnzP1S_Dx0/0/da"><img src="http://feedads.g.doubleclick.net/~a/KmpQ0SupurQ3-1CzzYnzP1S_Dx0/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/KmpQ0SupurQ3-1CzzYnzP1S_Dx0/1/da"><img src="http://feedads.g.doubleclick.net/~a/KmpQ0SupurQ3-1CzzYnzP1S_Dx0/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/6sBy6vhIMUE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Pathfinding A* en Python. Parte II</title>
		<link>http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-ii/</link>
		<comments>http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-ii/#comments</comments>
		<pubDate>Thu, 01 Apr 2010 01:43:06 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[A*]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Pathfinding]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=237</guid>
		<description><![CDATA[En el anterior artículo creamos un mapa y lo convertimos en una array. En este artículo crearemos la parte del código que encuentra el camino más corto entre los dos puntos. La clase Nodo Lo primero que necesitamos siguiendo la teoría es tener la forma de crear un nodo. Cada nodo debe de contener la [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://razonartificial.com/wp-content/uploads/2010/03/a_estrella.png"><img class="alignright size-thumbnail wp-image-203 imageborder" title="a_estrella" src="http://razonartificial.com/wp-content/uploads/2010/03/a_estrella-150x150.png" alt="" width="150" height="150" /></a>En el <a href="http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/">anterior artículo</a> creamos un mapa y lo convertimos en una array. En este artículo crearemos la parte del código que encuentra el camino más corto entre los dos puntos.</p>
<h2>La clase Nodo</h2>
<p>Lo primero que necesitamos siguiendo la teoría es tener la forma de crear un nodo. Cada nodo debe de contener la siguiente información.</p>
<ul>
<li>Posición &#8211; Coordenadas del nodo.</li>
<li>Padre. Almacena el nodo padre.</li>
<li>Valor de H. Distancia con el punto objetico.</li>
<li>Valor de G. Distancia recorrida hasta ese nodo.</li>
<li>Valor de F. Suma de G más H.</li>
</ul>
<p>Eso son los datos que contiene un nodo, por lo que la mejor manera de almacenarlos en Python en creando una clase que cree esos datos automáticamente.<span id="more-237"></span></p>
<pre class="brush: python;">
class Nodo:
	def __init__(self, pos=[0, 0], padre=None):
		self.pos = pos
		self.padre = padre
		self.h = distancia(self.pos, pos_f)

		if self.padre == None:
			self.g = 0
		else:
			self.g = self.padre.g + 1
		self.f = self.g + self.h
</pre>
<p>Como vemos recibe dos parámetros la posición y el nodo padre. A partir de ellos obtiene la G que si no tiene padre valdrá 0 y sino le añadirá 1 a la G de su padre. La F la obtiene de la suma de G y H. Dejo la H para el final porque para calcularla usa la siguiente función:</p>
<pre class="brush: python;">
# Distancia entre dos puntos.
def distancia(a, b):
	return abs(a[0] - b[0]) + abs(a[1] - b[1]) #Valor absoluto.
</pre>
<p>Como ves usa matemáticas básicas para obtener la distancia entre dos puntos, ojo al dato de que la devuelve en valor absoluto, las distancias negativas no existen. Cabe destacar que el punto b (pos_f) es la posición final y es una variable declarada global.</p>
<p>La calcula usando la siguiente función:</p>
<pre class="brush: python;">
def buscarPos(x, mapa):
	for f in range(mapa.fil):
		for c in range(mapa.col):
			if mapa.mapa[f][c] == x:
				return [f, c]
	return 0
</pre>
<h2>La Clase AEstrella</h2>
<p>Aquí viene la chicha del algoritmo, la clase que dará nuestro camino a seguir, la dejo entera y la comentamos.</p>
<pre class="brush: python;">
class AEstrella:
	def __init__(self, mapa):
		self.mapa = mapa

		# Nodos de inicio y fin.
		self.inicio = Nodo(buscarPos(2, mapa))
		self.fin = Nodo(buscarPos(3, mapa))

		# Crea las listas abierta y cerrada.
		self.abierta = []
		self.cerrada = []

		# Añade el nodo inicial a la lista cerrada.
		self.cerrada.append(self.inicio)

		# Añade vecinos a la lista abierta
		self.abierta += self.vecinos(self.inicio)

		# Buscar mientras objetivo no este en la lista cerrada.
		while self.objetivo():
			self.buscar()

		self.camino = self.camino()

	# Devuelve una lista con los nodos vecinos transitables.
	def vecinos(self, nodo):
		vecinos = []
		if self.mapa.mapa[nodo.pos[0]+1][nodo.pos[1]] != 1:
			vecinos.append(Nodo([nodo.pos[0]+1, nodo.pos[1]], nodo))
		if self.mapa.mapa[nodo.pos[0]-1][nodo.pos[1]] != 1:
			vecinos.append(Nodo([nodo.pos[0]-1, nodo.pos[1]], nodo))
		if self.mapa.mapa[nodo.pos[0]][nodo.pos[1]-1] != 1:
			vecinos.append(Nodo([nodo.pos[0], nodo.pos[1]-1], nodo))
		if self.mapa.mapa[nodo.pos[0]][nodo.pos[1]+1] != 1:
			vecinos.append(Nodo([nodo.pos[0], nodo.pos[1]+1], nodo))
		return vecinos

	# Pasa el elemento de f menor de la lista abierta a la cerrada.
	def f_menor(self):
		a = self.abierta[0]
		n = 0
		for i in range(1, len(self.abierta)):
			if self.abierta[i].f &lt; a.f:
				a = self.abierta[i]
				n = i
		self.cerrada.append(self.abierta[n])
		del self.abierta[n]

	# Comprueba si un nodo está en una lista.
	def en_lista(self, nodo, lista):
		for i in range(len(lista)):
			if nodo.pos == lista[i].pos:
				return 1
		return 0

	# Gestiona los vecinos del nodo seleccionado.
	def ruta(self):
		for i in range(len(self.nodos)):
			if self.en_lista(self.nodos[i], self.cerrada):
				continue
			elif not self.en_lista(self.nodos[i], self.abierta):
				self.abierta.append(self.nodos[i])
			else:
				if self.select.g+1 &lt; self.nodos[i].g:
					for j in range(len(self.abierta)):
						if self.nodos[i].pos == self.abierta[j].pos:
							del self.abierta[j]
							self.abierta.append(self.nodos[i])
							break

	# Analiza el último elemento de la lista cerrada.
	def buscar(self):
		self.f_menor()
		self.select = self.cerrada[-1]
		self.nodos = self.vecinos(self.select)
		self.ruta()

	# Comprueba si el objetivo objetivo está en la lista abierta.
	def objetivo(self):
		for i in range(len(self.abierta)):
			if self.fin.pos == self.abierta[i].pos:
				return 0
		return 1

	# Retorna una lista con las posiciones del camino a seguir.
	def camino(self):
		for i in range(len(self.abierta)):
			if self.fin.pos == self.abierta[i].pos:
				objetivo = self.abierta[i]

		camino = []
		while objetivo.padre != None:
			camino.append(objetivo.pos)
			objetivo = objetivo.padre
		camino.reverse()
		return camino
</pre>
<p>Si la estudias un poco puedes ver que sigue las directrices de la teoría, se crean las listas abierta y cerrada, se mete la posición inicial en la lista cerrada y sus vecinos a la abierta. A partir de aquí empieza un bucle que irá haciendo esto con cada uno de los vecinos, eligiendo siempre al de menor coste hasta que el Nodo objetivo sea añadido a la lista abierta, en este momento sale del bucle y llama al método camino. Que a partir del nodo objetivo añadido a la lista puede ir sacando su nodo padre hasta el que no tenga nodo padre que es el nodo inicial. Con esto tenemos un camino inverso entre el nodo objetivo y el nodo inicial.</p>
<p>Ahora si queréis probarlo basta con crear un objeto AEstrella pasandole nuestro mapa como parámetro e invocar a objeto.camino que es la variable que contiene la array con el camino. Si te resulta lioso no te preocupes te dejo el programa entero como va hasta ahora con algunas modificaciones para que muestre el camino a seguir.</p>
<ul>
<li><a href="http://razonartificial.com/wp-content/uploads/2010/04/pathfinding.zip">Descargar Pathfinding</a></li>
</ul>
<p>Cualquier duda tienes los comentarios para preguntar, en el proximo tutorial haremos una interfaz gráfica en pygame que use el algoritmo.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/" title="Pathfinding A* en Python. Parte III">Pathfinding A* en Python. Parte III</a></li><li><a href="http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/" title="Pathfinding A* en Python. Parte I">Pathfinding A* en Python. Parte I</a></li><li><a href="http://razonartificial.com/2010/04/usando-pilas-binarias-en-un-pathfinding-a/" title="Usando Pilas Binarias en Pathfinding A*">Usando Pilas Binarias en Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-de-2-niveles/" title="Pathfinding A* de 2 niveles">Pathfinding A* de 2 niveles</a></li><li><a href="http://razonartificial.com/2010/04/heuristica-para-el-pathfinding-a-star/" title="Heurística para el Pathfinding A*">Heurística para el Pathfinding A*</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/I-455Y14PcsFZyJtKFIEQa5W31M/0/da"><img src="http://feedads.g.doubleclick.net/~a/I-455Y14PcsFZyJtKFIEQa5W31M/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/I-455Y14PcsFZyJtKFIEQa5W31M/1/da"><img src="http://feedads.g.doubleclick.net/~a/I-455Y14PcsFZyJtKFIEQa5W31M/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/99s_XyiNx1g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-ii/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Pathfinding A* en Python. Parte I</title>
		<link>http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/</link>
		<comments>http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 17:59:39 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[A*]]></category>
		<category><![CDATA[Búsqueda]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Juegos]]></category>
		<category><![CDATA[Pathfinding]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=226</guid>
		<description><![CDATA[Voy a explicar como implementar un algoritmo de búsqueda del camino mas corto en Python, el Pathfinding es muy usado y es una de las técnicas básicas de la inteligencia artificial. Consiste en encontrar el camino más corto entre dos puntos superando obstáculos. Remarco lo de superando obstáculos porque obviamente el camino más corto entre [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://razonartificial.com/wp-content/uploads/2010/03/a_estrella.png"><img class="alignright size-thumbnail wp-image-203 imageborder" title="a_estrella" src="http://razonartificial.com/wp-content/uploads/2010/03/a_estrella-150x150.png" alt="" width="150" height="150" /></a>Voy a explicar como implementar un algoritmo de búsqueda del camino mas corto en Python, el Pathfinding es muy usado y es una de las técnicas básicas de la inteligencia artificial. Consiste en encontrar el camino más corto entre dos puntos <strong>superando obstáculos</strong>. Remarco lo de superando obstáculos porque obviamente el camino más corto entre dos puntos es la línea recta.</p>
<p>Esta técnica es muy usada en videojuegos de estrategia y en general en todos los videojuegos en donde se trata que la inteligencia artificial encuentre el camino más corto entre dos puntos. También es aplicable a la robótica para controlar los movimientos de un robot y que este supere obstáculos.</p>
<p>Antes de empezar es impresindible leer el artículo <a title="Permanent Link to A* Pathfinding. Camino óptimo" rel="bookmark" href="http://razonartificial.com/2010/03/a-pathfinding-camino-optimo/">A* Pathfinding. Camino óptimo</a> y entenderlo donde se explica el algoritmo, en este artículo usaré esas ideas para implementarlo en Python. He dividido el artículo en tres partes esta primera tratará de la creación de un entorno donde aplicar el algoritmo, la segunda parte es la creación del pathfinding en sí, el buscador del camino óptimo y por último en la tercera parte haré una interfaz gráfica en Pygame donde aplicarlo.<span id="more-226"></span></p>
<h2>Creando un Mapa</h2>
<p>Lo primero que necesitamos es un mapa donde probarlo. Para no complicarnos la vida usaremos un archivo de texto plano, un txt. A continuación un ejemplo:</p>
<pre># # # # # # # # # # # # # # # # #
# T . . . . . . . . . # . # . . #
# # # # # . # # # . . . . # . # #
# . . . . . . . . . # . . . . . #
# . # # # . # . # . # . # . # . #
# . # . # . # . # . # . # . # . #
# . # . # . # . # . . # # . # . #
# . # . . . # . # # . # . # . . #
# . . . # # # . . # . . . . . # #
# . . . . . . . # # . # # . . . #
# # # # . # . . . # . # . . # . #
# . . . . # . # . . . # # . # . #
# . # # . # . # . # . . . . . . #
# # # # # # # # # # # # # # # S #</pre>
<p>He usado caracteres que faciliten visualmente el diseño del mapa, en este sencillo ejemplo hay 4 tipos de datos:</p>
<ul>
<li><strong>Las almohadillas(#)</strong> &#8211; Representan los muros, son las zonas no atravesables.</li>
<li><strong>Los puntos(.)</strong> &#8211; Son los caminos, la zonas transitables por las que nos podemos mover.</li>
<li><strong>La T</strong> &#8211; Representa la posición inicial del jugador.</li>
<li><strong>La S</strong> &#8211; Representa el destino, el punto al que ha de llegar.</li>
</ul>
<p>Con esto ya tenemos un mapa base en el que poder probar nuestro algorimo, lo guardamos en un archivo con el nombre mapa.txt y lo ponemos en el directorio de trabajo. Es hora de empezar con el código.</p>
<h3>Leyendo el Mapa</h3>
<p>Creamos el archivo principal del proyecto yo lo he llamado buscador.py, puedes llamorlo como quiera y he cargado mi <a href="http://razonartificial.com/wp-content/uploads/2010/03/plantilla.zip">plantilla base</a>.</p>
<p>Lo primero que necesitamos es un método de leer el txt y convertirlo en algo que podamos manejar con Python. Yo lo he convertido en una lista bidimensional que contiene las filas y columnas del mapa y a cada tipo de carácter/bloque le he asignado un valor. Las siguientes tres funciones Hacen todo esto.</p>
<pre class="brush: python;">
# Quita el ultimo caracter de una lista.
def quitarUltimo(lista):
	for i in range(len(lista)):
		lista[i] = lista[i][:-1]
	return lista

# Covierte una cadena en una lista.
def listarCadena(cadena):
	lista = []
	for i in range(len(cadena)):
		if cadena[i] == &quot;.&quot;:
			lista.append(0)
		if cadena[i] == &quot;#&quot;:
			lista.append(1)
		if cadena[i] == &quot;T&quot;:
			lista.append(2)
		if cadena[i] == &quot;S&quot;:
			lista.append(3)
	return lista

# Lee un archivo de texto y lo convierte en una lista.
def leerMapa(archivo):
	mapa = open(archivo, &quot;r&quot;)
	mapa = mapa.readlines()
	mapa = quitarUltimo(mapa)
	for i in range(len(mapa)):
		mapa[i] = listarCadena(mapa[i])
	return mapa
</pre>
<p>Como puedes ver he asignado diferentes valores según el carácter quedando la relación así:</p>
<ul>
<li>Caminos &#8211; 0</li>
<li>Paredes &#8211; 1</li>
<li>Jugador &#8211; 2</li>
<li>Salida &#8211; 3</li>
</ul>
<h3>La clase Mapa:</h3>
<p>A continuación creamos una clase que represente el mapa, en principio solo va a tener dos métodos, el constructor y el str que nos servirá para probar que funciona correctamente, la clase es la siguiente:</p>
<pre class="brush: python;">
class Mapa:
	def __init__(self, archivo=&quot;mapa.txt&quot;):
		self.mapa = leerMapa(archivo)
		self.fil = len(self.mapa)
		self.col = len(self.mapa[0])

	def __str__(self):
		salida = &quot;&quot;
		for f in range(self.fil):
			for c in range(self.col):
				if self.mapa[f][c] == 0:
					salida += &quot;.&quot;
				if self.mapa[f][c] == 1:
					salida += &quot;# &quot;
				if self.mapa[f][c] == 2:
					salida += &quot;T &quot;
				if self.mapa[f][c] == 3:
					salida += &quot;S &quot;
			salida += &quot;\n&quot;
		return salida
</pre>
<p>Como ves el constructor llama a la funcion leerMapa() que hicimos antes y también almacena el tamaño del mapa en filas y columnas. El método __str__ nos sirve para sustituir a print y ver una representación del mapa.</p>
<p>Por último creamos un mapa dentro de la función main() y lo imprimimos a ver como queda:</p>
<pre class="brush: python;">
def main():
	mapa = Mapa()
	print mapa
	return 0
</pre>
<p>Con esto ya tenemos todo listo para aplicar el algoritmo pathfinding A* y encontrar el camino más corto entre T y S que veremos en el siguiente artículo.</p>
<p>Si algo no funciona o quieres probarlo directamente puedes <a href="http://razonartificial.com/wp-content/uploads/2010/03/pathfinding.zip">descargarlo aquí</a>.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/" title="Pathfinding A* en Python. Parte III">Pathfinding A* en Python. Parte III</a></li><li><a href="http://razonartificial.com/2010/04/usando-pilas-binarias-en-un-pathfinding-a/" title="Usando Pilas Binarias en Pathfinding A*">Usando Pilas Binarias en Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-de-2-niveles/" title="Pathfinding A* de 2 niveles">Pathfinding A* de 2 niveles</a></li><li><a href="http://razonartificial.com/2010/04/heuristica-para-el-pathfinding-a-star/" title="Heurística para el Pathfinding A*">Heurística para el Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-ii/" title="Pathfinding A* en Python. Parte II">Pathfinding A* en Python. Parte II</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/VCdvSh_gRDEs3tQBXNqMIM71CcI/0/da"><img src="http://feedads.g.doubleclick.net/~a/VCdvSh_gRDEs3tQBXNqMIM71CcI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/VCdvSh_gRDEs3tQBXNqMIM71CcI/1/da"><img src="http://feedads.g.doubleclick.net/~a/VCdvSh_gRDEs3tQBXNqMIM71CcI/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/18bxvIDe6Pw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Razón Artificial estrena diseño</title>
		<link>http://razonartificial.com/2010/03/razon-artificial-estrena-diseno/</link>
		<comments>http://razonartificial.com/2010/03/razon-artificial-estrena-diseno/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 06:02:18 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=221</guid>
		<description><![CDATA[Hago un inciso para comentar que estrenamos diseño, con el pretendo que la web sea más clara y accesible para todos a parte de intentar dar al sitio un aspecto único y elegante. El nuevo diseño combina blancos y negros con un toque de azul que hace un constraste muy elegante. Otro cambio importante es [...]]]></description>
			<content:encoded><![CDATA[<p>Hago un inciso para comentar que estrenamos diseño, con el pretendo que la web sea más clara y accesible para todos a parte de intentar dar al sitio un aspecto único y elegante.</p>
<p>El nuevo diseño combina blancos y negros con un toque de azul que hace un constraste muy elegante. Otro cambio importante es en la tipografía, en esta nueva versión se usarán tipografías con serifas, que creo facilitan la lectura.</p>
<p>Como es normal cuando se modifica una web puede a ver fallos, si encuentras algo que este mal o que crees que quedaría mejor de otro manera, por fovor usa los comentarios y comunícamelo, me gustaría saber tu opinión.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/repositorio-en-github-para-el-engine-rpg/" title="Repositorio en github para el Engine-RPG">Repositorio en github para el Engine-RPG</a></li><li><a href="http://razonartificial.com/2010/07/futuro-del-engine-y-los-tutoriales/" title="Futuro del Engine y los tutoriales">Futuro del Engine y los tutoriales</a></li><li><a href="http://razonartificial.com/2010/07/destacamos-del-foro/" title="Destacamos del foro">Destacamos del foro</a></li><li><a href="http://razonartificial.com/2010/07/razon-artificial-crece/" title="Razón Artificial Crece">Razón Artificial Crece</a></li><li><a href="http://razonartificial.com/2010/07/%c2%bfuna-comunidad/" title="¿Una comunidad?">¿Una comunidad?</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/E_TOFemtDvG1YVD9rM-TyERFMmI/0/da"><img src="http://feedads.g.doubleclick.net/~a/E_TOFemtDvG1YVD9rM-TyERFMmI/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/E_TOFemtDvG1YVD9rM-TyERFMmI/1/da"><img src="http://feedads.g.doubleclick.net/~a/E_TOFemtDvG1YVD9rM-TyERFMmI/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/uRn7f9joeok" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/03/razon-artificial-estrena-diseno/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>A* Pathfinding. Camino óptimo</title>
		<link>http://razonartificial.com/2010/03/a-pathfinding-camino-optimo/</link>
		<comments>http://razonartificial.com/2010/03/a-pathfinding-camino-optimo/#comments</comments>
		<pubDate>Sat, 27 Mar 2010 23:56:21 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[I. Artificial]]></category>
		<category><![CDATA[A*]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Pathfinding]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Teoría]]></category>
		<category><![CDATA[Tutoriales]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=198</guid>
		<description><![CDATA[Aunque es bastante fácil una vez que consigues manejarlo, el algoritmo A* (pronunciado A-star) puede ser complicado para los principiantes. Hay un gran número de artículos por la web que explican el A*, pero la mayoría están escritos por gente que ya sabe los fundamentos de este tema. Este artículo no es específico de un [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-thumbnail wp-image-203 alignleft imageborder" title="a_estrella" src="http://razonartificial.com/wp-content/uploads/2010/03/a_estrella-150x150.png" alt="" width="150" height="150" />Aunque es bastante fácil una vez que consigues manejarlo, el algoritmo A* (pronunciado A-star) puede ser complicado para los principiantes. Hay un gran número de artículos por la web que explican el A*, pero la mayoría están escritos por gente que ya sabe los fundamentos de este tema.</p>
<p>Este artículo no es específico de un lenguaje de programación, así que deberías ser capaz de adaptarlo a cualquier lenguaje ordenador. De todas maneras, pretendo facilitar el código escrito en Python para que lo puedas probar.</p>
<p>De acuerdo, empecemos.<span id="more-198"></span></p>
<h2>Introducción: El Área de Búsqueda</h2>
<p>Vamos a asumir que tenemos a alguien que quiere ir desde el punto A hasta el punto B. Asumamos también que un muro separa estos dos puntos. El ejemplo queda ilustrado en el gráfico siguiente, donde el recuadro verde es el punto de inicio A, el rojo es el punto de destino B y la zona azul el muro que hay entre ambos.</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-270" title="fig1" src="http://razonartificial.com/wp-content/uploads/2010/03/fig1.jpg" alt="" width="362" height="256" /></p>
<p>Lo primero que deberías advertir es que hemos dividido nuestro área de búsqueda en una rejilla cuadrada. Simplificar el área, tal y como hemos hecho, es el primer paso en un pathfinding. Este particular método reduce nuestro área de búsqueda a una simple matriz bidimensional. Cada elemento de la matriz representa uno de los cuadrados de la rejilla, y su estado se almacena como transitable o intransitable. El camino se elige calculando qué cuadros deberíamos pisar para ir desde A hasta B. Una vez que el camino haya sido encontrado, el personaje de nuestro juego (o lo que sea) se moverá desde el centro de un cuadrado hacia el centro del siguiente hasta que el objetivo haya sido alcanzado.</p>
<p>A esos puntos centrales se les llama &#8220;nodos&#8221;. Cuando leas en cualquier otro sitio sobre pathfinding, a menudo verás a gente hablando sobre nodos. ¿Acaso no es más fácil referirse a ellos como cuadrados? Esto se debe a que es posible dividir nuestro área en otras cosas aparte de cuadrados. Podrían ser rectangulares, hexagonales, o de cualquier otra forma; y podrían situarse en cualquier lugar dentro de esas formas &#8211; en el centro, por los bordes, o en cualquier lugar. Nosotros usamos este sistema porque es el más simple.</p>
<h2>Iniciando la Búsqueda</h2>
<p>Una vez que hemos simplificado nuestro área de búsqueda en un número de nodos asequible, tal y como hemos hecho con la rejilla de la figura anterior, el siguiente paso es dirigir una búsqueda para encontrar el camino más corto. En el pathfinding A*, lo hacemos empezando desde el punto A, comprobando los cuadros adyacentes y generalmente buscando hacia fuera hasta que encontremos nuestro destino.</p>
<p>Empezamos la búsqueda haciendo lo siguiente:</p>
<p><strong>1)</strong> Empieza en el punto inicial A y añádelo a una &#8220;lista abierta&#8221; de cuadrados a tener en cuenta. La lista abierta es como una lista de la compra. Ahora mismo solo tenemos un elemento en la lista, pero más tarde tendremos más. La lista contiene los cuadrados que podrían formar parte del camino que queremos tomar, pero que quizás no lo hagan. Básicamente, esta es una lista de los cuadrados que necesitan ser comprobados.</p>
<p><strong>2)</strong> Mira en todos los cuadrados alcanzables o transitables adyacentes al punto de inicio, ignorando cuadrados con muros, agua u otros terrenos prohibidos. Añádelos a la lista abierta también. Por cada uno de esos cuadrados, guarda el punto A como su &#8220;cuadrado padre&#8221;. El cuadrado padre es muy importante para trazar nuestro camino. Lo explicaré más tarde.</p>
<p><strong>3)</strong> Saca el cuadro inicial A desde tu lista abierta y añádelo a una &#8220;lista cerrada&#8221; de cuadrados que no necesitan, por ahora, ser mirados de nuevo.</p>
<p>En este punto, deberías tener algo como la siguiente ilustración. En este diagrama, el cuadrado verde oscuro del centro es tu cuadrado de inicio. Esta bordeado el azul claro para indicar que el cuadrado ha sido añadido a la lista cerrada. Todos los cuadros adyacentes están ahora en la lista abierta para ser comprobados, están bordeados con verde claro. Cada uno tiene un puntero gris que señala a su padre, el cual es el cuadro inicial.</p>
<p><img class="aligncenter size-full wp-image-271" title="fig2" src="http://razonartificial.com/wp-content/uploads/2010/03/fig2.jpg" alt="" width="151" height="150" /></p>
<p>Después, elegimos uno de los cuadrados adyacentes de la lista abierta y más o menos repetimos el proceso anterior como se describe un poco más abajo. Pero, ¿cual cuadro debemos elegir? Aquel que tenga el coste F más bajo.</p>
<h2>Puntuando el camino</h2>
<p>La clave para determinar que cuadrados usaremos para resolver el camino está en la siguiente ecuación:</p>
<p>F = G + H</p>
<p>Donde:</p>
<ul>
<li> G = el coste de movimiento para ir desde el punto inicial A a un cierto cuadro de la rejilla, siguiendo el camino generado para llegar allí.</li>
<li>H= el coste de movimiento estimado para ir desde ese cuadro de la rejilla hasta el destino final, el punto B. Esto es a menudo nombrado como la heurística, la cual puede ser un poco confusa. La razón por la cual es llamada así, se debe a que es una suposición. Realmente no sabemos la distancia actual hasta que encontramos el camino, ya que toda clase de cosas pueden estar en nuestro camino (muros, agua, etc.) En este tutorial, estás viendo una forma de calcular H, pero hay muchas otras que puedes encontrar en otros artículos de la red.</li>
</ul>
<p>Nuestro camino se genera por ir repetidamente a través de nuestra lista abierta y eligiendo el cuadrado con la puntuación F más baja. Este proceso se describirá con más detalle un poco más adelante. Primero veamos más de cerca cómo calculamos la ecuación.</p>
<p>Tal y como está descrito más arriba, G es el coste de movimiento para ir desde el punto de inicio a un cierto cuadro usando el camino generado para llegar allí. En este ejemplo asignaremos un coste de 10 a cada cuadro vertical u horizontal hacia el que nos movamos, y un coste de 14 para un movimiento diagonal. Usamos estos números porque la distancia actual para mover diagonalmente es el cuadrado de la raíz de 2 ( no temas), o mas o menos 1,414 veces el coste del movimiento horizontal o vertical. Usamos 10 y 14 con el fin de simplificar. El rango es bastante bueno, y así nos libramos de tener que calcular raíces cuadradas y sus decimales. Esto no es solo porque seamos idiotas y no nos gusten las matemáticas; usar números enteros  también es mucho más rápido para el ordenador. Pronto descubrirás que el pathfinding puede ser muy lento si no usas atajos como este.</p>
<p>Ahora que hemos calculado el coste G mediante un camino específico hasta cierto cuadrado, la forma de resolver el coste G del cuadrado es coger el coste G de su padre, y luego añadirle  10 o 14 dependiendo de si está en diagonal u ortogonal (no diagonal) con respecto a ese cuadro padre. Este método se hará más claro cuando llevemos este ejemplo un poco más allá y nos alejemos un cuadro del inicial.</p>
<p>H puede ser estimado de diferentes maneras. El método que hemos usado aquí se llama el método Manhattan, donde calculas el número total de cuadros movidos horizontalmente y verticalmente para alcanzar el cuadrado destino desde el cuadro actual, sin hacer uso de movimientos diagonales. Luego multiplicamos el total por 10. Se llama método Manhattan porque es como calcular el número de manzanas que hay desde un lugar a otro, donde no puedes acortar atravesando en diagonal una manzana. Cabe señalar que cuando calculamos H, ignoramos cualquier obstáculo que intervenga. Es una estimación de la distancia que queda, no de la distancia actual, es por eso que se llama heurística.</p>
<p>F se calcula sumando G y H. El resultado del primer paso en nuestra búsqueda puede ver se en la ilustración inferior. Las puntuaciones F, G y H están escritas en cada cuadrado. En el cuadro inmediatamente a la derecha de cuadro inicial, la F está impresa arriba a la izquierda, la G abajo a la izquierda y la H abajo la derecha.</p>
<p><img class="aligncenter size-full wp-image-272" title="fig3" src="http://razonartificial.com/wp-content/uploads/2010/03/fig3.jpg" alt="" width="362" height="255" /></p>
<p>Así pues, vamos a mirar algunos ejemplos de estos cuadros. En el cuadrado con letras, G =10. Esto es debido a que está solo a un cuadro del cuadrado inicial en dirección horizontal. Los cuadrados inmediatamente encima, abajo y a la izquierda del cuadrado inicial; tienen todos el mismo valor G de 10. Los cuadros diagonales tienen un valor G de 14.</p>
<p>Las puntuaciones H se calculan estimando la distancia Manhattan hasta el cuadrado rojo objetivo, moviéndose solo horizontal y verticalmente e ignorando el muro que está en el camino. Usando este método, el cuadro de la derecha del inicial, está a 3 cuadros del cuadrado rojo con una puntuación H de 30. El cuadrado está a solo 4 cuadros de distancia (recuerda que solo nos movemos en horizontal y vertical) con una puntuación H de 40. Probablemente comprendas como se calculan las puntuaciones H para los demás cuadros.</p>
<p>De nuevo, la puntuación F de cada cuadro se calcula simplemente sumando G y H.</p>
<h2>Continuando la búsqueda</h2>
<p>Para continuar la búsqueda, simplemente elegimos la puntuación F más baja de todos aquellos que estén en la lista abierta. Después hacemos lo siguiente con el cuadro seleccionado:</p>
<p><strong>4) </strong>Sácalo de la lista abierta y añádelo a la lista cerrada.</p>
<p><strong>5)</strong> Comprueba todos los cuadrados adyacentes, ignorando aquellos que estén en la lista cerrada o que sean intransitables terrenos con muros, agua, o cualquier terreno prohibido), añade los cuadros a la lista abierta si no están ya en esa lista. Haz al cuadro seleccionado el &#8220;padre&#8221; de los nuevos cuadros.<br />
<strong><br />
6)</strong> Si el cuadro adyacente ya está en la lista abierta, comprueba si el camino a ese cuadro es mejor que este. En otras palabras, comprueba que la G de ese cuadro sea más baja que la del que estamos usando para ir allí. Si no es así, no hagas nada. Por otro lado, si el coste G del nuevo camino es más bajo, cambia el padre del cuadro adyacente al cuadro seleccionado (en el diagrama superior, cambia la dirección del puntero para que señale al cuadro seleccionado). Finalmente, recalcula la F y la G de ese cuadrado. Si esto te parece confuso, podrás verlo ilustrado más abajo.</p>
<p>Ahora vamos a ver como funciona. De nuestros 9 cuadros iniciales, dejamos 8 en la lista abierta después de que el cuadrado inicial fuera incluido en la lista cerrada. De estos, el que tiene el coste F más bajo es el de inmediatamente a la derecha del cuadro inicial, con una F de 40. Así que seleccionamos este cuadrado como nuestro siguiente cuadrado. Está resaltado en azul en la siguiente ilustración.</p>
<p><img class="aligncenter size-full wp-image-273" title="fig4" src="http://razonartificial.com/wp-content/uploads/2010/03/fig4.jpg" alt="" width="357" height="256" /></p>
<p>Primero, lo sacamos de nuestra lista abierta y lo añadimos a nuestra lista cerrada (por que ahora está resaltado en azul). Luego comprobamos los cuadros adyacentes. Todos los que hay a la derecha son cuadros de muro, así que no los tenemos en cuenta. El de la izquierda es el cuadrado inicial; ese está en la lista cerrada, así que lo ignoramos también.</p>
<p>Los otros 4 cuadrados ya están en la lista abierta, así que necesitamos comprobar si alguno de los caminos hasta esos cuadros es mejor que el del cuadrado actual hasta ellos. Para eso usaremos la puntuación G como punto de referencia. Miremos debajo de nuestro cuadrado seleccionado; su G actual es 14. Si fuésemos a través del cuadro actual hasta allí, la G sería igual a 20 (10, la G del cuadro actual, más 10 de un movimiento vertical hacia el cuadro superior). Una G de 20 es mayor que una de 14, así que no es un buen camino. Todo eso debería cobrar sentido si miras el diagrama. Es más directo llegar a ese cuadro desde el cuadro inicial moviéndote un cuadro en diagonal, que moverte horizontalmente un cuadro y luego verticalmente otro.</p>
<p>Cuando repetimos este proceso para los otros 4 cuadros adyacentes que ya están en la lista abierta, descubrimos que ninguno de los caminos ha mejorado por ir a través del cuadro actual (el de la derecha bordeado de azul), así que pasamos de él. Ahora que hemos mirado en todos los cuadros adyacentes y ya nos hemos hecho con este nuevo cuadro, estamos listos para movernos al siguiente cuadrado.</p>
<p>Recorremos el grupo de cuadros de nuestra lista abierta, ahora ha bajado a 7 cuadrados, cogemos el que tenga el coste F más bajo. Interesante&#8230;, en este caso hay dos cuadros que tienen una puntuación de 54. Así que, ¿cual elegimos? La verdad es que no importa. Para propósitos de velocidad, puede ser más rápido elegir el último que añadimos a la lista abierta. Esto influencia a la búsqueda en favor de cuadros que fueron encontrados más tarde justo cuando estés más cerca de alcanzar tu objetivo. De todas formas no es verdaderamente importante.</p>
<p>Así pues, y ya que lo elegimos anteriormente, escogemos el cuadro justo debajo del cuadrado que desechamos antes. La siguiente ilustración lo aclara:</p>
<p><img class="aligncenter size-full wp-image-274" title="fig5" src="http://razonartificial.com/wp-content/uploads/2010/03/fig5.jpg" alt="" width="357" height="254" /></p>
<p>Esta vez, cuando comprobamos los cuadrados adyacentes encontramos que el de la izquierda y el superior a este son cuadros de muro así que los ignoramos. Tampoco tenemos en cuenta el cuadro que está debajo del muro. ¿Por qué? Porque no puedes llegar a ese cuadrado sin que tu personaje se raspe el hombro con la esquina al intentar pasar en diagonal; lo mejor es dar un pequeño rodeo, primero bajando y luego yendo hacia la derecha. (Nota: Esta regla de bordear esquinas es opcional. Su uso depende de como estén situados tus nodos.)</p>
<p>Eso nos deja otros 5 cuadros. Los otros 2 cuadros bajo el actual no están en la lista abierta así que los añadimos y el cuadro actual se convierte en su padre. De esos otros 3 cuadros, 2 ya están en la lista cerrada (el cuadro inicial, y el cuadro que hay encima del actual, ambos resaltados en azul en el diagrama) así que los ignoramos. El último cuadro, el de la izquierda del cuadro actual, se comprueba para ver si el coste G hasta él desde el cuadro actual, es menor que llegando directamente desde el cuadro inicial. Lo hacemos y no hay suerte,  así que ya estamos listos para comprobar el siguiente cuadro de nuestra lista abierta.</p>
<p>Repetimos este proceso hasta que añadimos el cuadro objetivo a la lista abierta, en ese momento parecería algo como la ilustración inferior:</p>
<p style="text-align: center;"><img class="aligncenter size-full wp-image-275" title="fig6" src="http://razonartificial.com/wp-content/uploads/2010/03/fig6.jpg" alt="" width="404" height="307" /></p>
<p>Observa que el cuadro padre para el cuadrado dos cuadros por debajo del cuadro inicial ha cambiado desde la ilustración anterior. Antes tenía un coste G de 28 y apuntaba al cuadrado encima suya y a la derecha. Ahora tiene una puntuación de 20 y apunta al cuadrado encima suya. Esto ocurrió en algún momento por la forma en la que se ejecuta nuestra búsqueda, donde la puntuación G fue comprobada y devuelta más baja usando un nuevo camino &#8211; el padre cambió y G y F fueron recalculadas. A pesar de que este cambio no parece demasiado importante en este ejemplo, hay muchas posibles situaciones donde este constante control significará la diferencia en la determinación del mejor camino hasta tu objetivo.</p>
<p>Pero, ¿cómo determinamos el camino actual en si mismo? Fácil, sólo empiezas desde el cuadro objetivo rojo, y vas hacia atrás de un cuadrado a su padre, siguiendo las flechas. Eso te llevará de vuelta al cuadrado inicial y tus movimientos serán el camino a seguir. Debería parecerse a la siguiente ilustración. Moverse desde el cuadro inicial A hasta el cuadro destino B es solo cuestión de ir moviéndose desde el centro de un cuadro (el nodo) al siguiente hasta alcanzar el objetivo. Sencillo!</p>
<p><img class="aligncenter size-full wp-image-276" title="fig7" src="http://razonartificial.com/wp-content/uploads/2010/03/fig7.jpg" alt="" width="411" height="308" /></p>
<h2>Sumario del Método A*</h2>
<p>Ahora que has leído la explicación, vamos a resumir el método paso a aso:</p>
<ol>
<li>Añade el cuadro inicial a la lista abierta.</li>
<li>Repite lo siguiente:
<ol>
<li>Busca el cuadro con el coste F más bajo en la lista abierta. Nos referimos a este como el cuadro actual.</li>
<li>Cámbialo a la lista cerrada.</li>
<li>Para cada uno de los 8 cuadros adyacentes al cuadro actual &#8230;
<ul>
<li>Si no es transitable o si está en la lista cerrada, ignóralo. En cualquier otro caso haz lo siguiente.</li>
<li>Si no está en la lista abierta, añádelo a la lista abierta. Haz que el cuadro actual sea el padre de este cuadro. Almacena los costes F, G y H del cuadro.</li>
<li>Si ya está en la lista abierta, comprueba si el camino para ese es mejor usando el coste G como baremo. Un coste G menor significa que este es un mejor camino. Si es así, cambia el padre del cuadrado al cuadro actual y recalcula G y F del cuadro. Si estás manteniendo la lista abierta por orden de puntuación F, podrías necesitar reordenar la lista para llevar cuenta del cambio.</li>
</ul>
</li>
<li>Para cuando:
<ul>
<li>añadas el cuadro objetivo a la lista abierta en cuyo caso el camino ha sido encontrado, o</li>
<li>falles en encontrar el cuadro objetivo y la lista abierta esté vacía. En este caso no hay camino.</li>
</ul>
</li>
</ol>
</li>
<li>Guarda el camino. Muévete hacia atrás desde el cuadro objetivo, ve desde cada cuadro a su padre hasta que alcances el cuadro inicial. El camino seguido es el que buscas.</li>
</ol>
<h2>Un poco de charlatanería</h2>
<p>Perdóname por divagar pero es importante señalar que cuando leas varias discusiones sobre el pathfinding A* en la web y en diferentes foros, alguna vez verás que alguien se refiere a cierto código como A* cuando en realidad no lo es. Para el método A* necesitas incluir los elementos que hemos explicado arriba &#8211; específicamente listas cerradas y abiertas y puntuación del camino usando F,G y H. Hay muchos otros algoritmos de pathfinding, pero esos otros métodos no son A*, el cual es generalmente considerado como el mejor. Bryan Stout habla sobre muchos de ellos en el artículo al que se hace referencia al final de este, incluyendo algunos de sus pros y contras. Algunas veces las alternativas son mejores bajo determinadas circunstancias, pero deberías comprender en lo que te estás metiendo. Bueno, suficiente rollo por hoy, volvamos al artículo.</p>
<p>Traducido por <strong>Elthan</strong>, con el permiso de <strong>Patrick Lester</strong>.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/04/usando-pilas-binarias-en-un-pathfinding-a/" title="Usando Pilas Binarias en Pathfinding A*">Usando Pilas Binarias en Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-de-2-niveles/" title="Pathfinding A* de 2 niveles">Pathfinding A* de 2 niveles</a></li><li><a href="http://razonartificial.com/2010/04/heuristica-para-el-pathfinding-a-star/" title="Heurística para el Pathfinding A*">Heurística para el Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/" title="Pathfinding A* en Python. Parte III">Pathfinding A* en Python. Parte III</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-ii/" title="Pathfinding A* en Python. Parte II">Pathfinding A* en Python. Parte II</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/80IIiqWTIaQJlBfShULHi6mUSKA/0/da"><img src="http://feedads.g.doubleclick.net/~a/80IIiqWTIaQJlBfShULHi6mUSKA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/80IIiqWTIaQJlBfShULHi6mUSKA/1/da"><img src="http://feedads.g.doubleclick.net/~a/80IIiqWTIaQJlBfShULHi6mUSKA/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/OeS6HNFPnKQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/03/a-pathfinding-camino-optimo/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Pygame X: Fuentes tipográficas</title>
		<link>http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/</link>
		<comments>http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 15:35:31 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=190</guid>
		<description><![CDATA[Continuamos con lo que dejamos a medias, en el tutorial anterior creamos un sistema de puntos, ahora vamos a ver como mostrarlo en pantalla mediante textos con Pygame. Cargando tipografías Pygame puede cargar las tipografías del sistema en el que se está ejecutando y si no la encuentra cargar la tipografía por defecto, yo prefiero [...]]]></description>
			<content:encoded><![CDATA[<p>Continuamos con lo que dejamos a medias, en el tutorial anterior creamos un sistema de puntos, ahora vamos a ver como mostrarlo en pantalla mediante textos con Pygame.</p>
<h3>Cargando tipografías</h3>
<p>Pygame puede cargar las tipografías del sistema en el que se está ejecutando y si no la encuentra cargar la tipografía por defecto, yo prefiero proporcionar incluir mi propia fuente en el juego y así me aseguro de que todo se ve como quiero.</p>
<p>Para este juego usaré la tipografía <a href="http://razonartificial.com/wp-content/uploads/2010/02/DroidSans.ttf_.zip">DroidSans.ttf</a> descargarla y meterla en la carpeta <strong>images</strong>. No es una imagen propiamente dicha, pero para una sola fuente no voy a crear una carpeta llamada fonts.</p>
<p>Hay que tener en cuenta cuando se trabaja con textos en Pygame es que este a última instancia trata a todos los textos como Sprites, una vez puesto se pueden manipular como si de una Sprite más se tratara, esto tiene muchas ventajas como veremos.</p>
<p>Lo primero que vamos a hacer es crear una función que nos facilite el trabajar con textos y nos automatice el proceso.<span id="more-190"></span></p>
<pre class="brush: python;">
def texto(texto, posx, posy, color=(255, 255, 255)):
	fuente = pygame.font.Font(&amp;quot;images/DroidSans.ttf&amp;quot;, 25)
	salida = pygame.font.Font.render(fuente, texto, 1, color)
	salida_rect = salida.get_rect()
	salida_rect.centerx = posx
	salida_rect.centery = posy
	return salida, salida_rect
</pre>
<p>En la <strong>línea 1</strong> creamos la función, vemos que recibe 4 parámetros: <strong>texto</strong> que debe ser una <strong>string</strong>, <strong>posx</strong> y <strong>posy</strong> que serán las coordenadas del centro de nuestro texto y color que es una tupla con los valores <strong>RGB</strong>, color es opcional y si no se define, por defecto será blanco.</p>
<p>La <strong>línea 2</strong> asigna una tipografía a la variable fuente como vemos lo hacemos con <em>pygame.font.Font()</em> al que le pasamos como primer parámetro la ruta de la tipografía que queremos usar y como segundo el tamaño de la tipografía.</p>
<p>En la <strong>linea 3</strong> creamos la variable salida asignandole <em>pygame.font.Font.render()</em> este método lo que hace es convertir un texto en un Sprite, como vemos como primer parámetro recibe una <strong>fuente</strong> tipográfica, le pasamos la creada en la línea anterior, como segundo recibe el <strong>texto</strong> a mostrar, el tercer parámetro es el <strong>antialias</strong> y puede ser verdadero o falso (con o sin antialias), por último recibe el <strong>color</strong>.</p>
<p>En la <strong>línea 4</strong> obtenemos el rect como si de un Sprite más se tratare y lo almacenamos en <strong>salida_rect</strong>.</p>
<p>Las <strong>líneas 5 y 6</strong> modifican el centro del Sprite en función de los valores <strong>posx</strong> y <strong>posy</strong>.</p>
<p>Por último la <strong>línea 7</strong> retorna una tupla con el Sprite y su correspondiente rect. Ojo a la ahora de utlizarla, recordad que retorna dos valores y no uno.</p>
<p>Con esta función poner texto es muy fácil, vamos a utilizarla para mostrar nuestras puntuaciones, añadimos las siguientes líneas en el bucle del juego:</p>
<pre class="brush: python;">
p_jug, p_jug_rect = texto(str(puntos[0]), WIDTH/4, 40)
p_cpu, p_cpu_rect = texto(str(puntos[1]), WIDTH-WIDTH/4, 40)
</pre>
<p>Esto nos crea dos <strong>Sprites</strong> con sus respectivos <strong>rects</strong>. El primero recibe como texto <strong>puntos[0]</strong>, es decir los puntos del jugador (ojo con la conversión str(), recodad que debe de ser una <strong>string</strong>), como parámetro <strong>posx</strong> recibe WIDTH/4 es decir la WIDTH/2/2 que es la mitad de la mitad de la pantalla (para centrarlo en el campo del jugador) y como parámetro <strong>posy</strong> he situado a 40px del norde superior.</p>
<p>El otro <strong>Sprite</strong> exactamente lo mismo, pero para los puntos de la CPU y centrado en el campo de la CPU el posx (WIDTH-WIDTH/4).</p>
<p>por último solo debemos actualizarlo en pantalla como hacemos siempre.</p>
<pre class="brush: python;">
screen.blit(p_jug, p_jug_rect)
screen.blit(p_cpu, p_cpu_rect)
</pre>
<p>Yo recomiendo ponerlas justo después del blit del fondo, porque si los ponemos al final la pelota pasara por &#8220;debajo&#8221; de los marcadores y eso queda algo feo.</p>
<p>El juego nos queda de la siguiente manera:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

class Bola(pygame.sprite.Sprite):
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&amp;quot;images/ball.png&amp;quot;, True)
		self.rect = self.image.get_rect()
		self.rect.centerx = WIDTH / 2
		self.rect.centery = HEIGHT / 2
		self.speed = [0.5, -0.5]

	def actualizar(self, time, pala_jug, pala_cpu, puntos):
		self.rect.centerx += self.speed[0] * time
		self.rect.centery += self.speed[1] * time

		if self.rect.left &amp;lt;= 0:
			puntos[1] += 1
		if self.rect.right &amp;gt;= WIDTH:
			puntos[0] += 1

		if self.rect.left &amp;lt;= 0 or self.rect.right &amp;gt;= WIDTH:
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time
		if self.rect.top &amp;lt;= 0 or self.rect.bottom &amp;gt;= HEIGHT:
			self.speed[1] = -self.speed[1]
			self.rect.centery += self.speed[1] * time

		if pygame.sprite.collide_rect(self, pala_jug):
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time

		if pygame.sprite.collide_rect(self, pala_cpu):
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time

		return puntos

class Pala(pygame.sprite.Sprite):
	def __init__(self, x):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&amp;quot;images/pala.png&amp;quot;)
		self.rect = self.image.get_rect()
		self.rect.centerx = x
		self.rect.centery = HEIGHT / 2
		self.speed = 0.5

	def mover(self, time, keys):
		if self.rect.top &amp;gt;= 0:
			if keys[K_UP]:
				self.rect.centery -= self.speed * time
		if self.rect.bottom &amp;lt;= HEIGHT:
			if keys[K_DOWN]:
				self.rect.centery += self.speed * time

	def ia(self, time, ball):
		if ball.speed[0] &amp;gt;= 0 and ball.rect.centerx &amp;gt;= WIDTH/2:
			if self.rect.centery &amp;lt; ball.rect.centery:
				self.rect.centery += self.speed * time
			if self.rect.centery &amp;gt; ball.rect.centery:
				self.rect.centery -= self.speed * time

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

def texto(texto, posx, posy, color=(255, 255, 255)):
	fuente = pygame.font.Font(&amp;quot;images/DroidSans.ttf&amp;quot;, 25)
	salida = pygame.font.Font.render(fuente, texto, 1, color)
	salida_rect = salida.get_rect()
	salida_rect.centerx = posx
	salida_rect.centery = posy
	return salida, salida_rect

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&amp;quot;Pruebas Pygame&amp;quot;)

	background_image = load_image('images/fondo_pong.png')
	bola = Bola()
	pala_jug = Pala(30)
	pala_cpu = Pala(WIDTH - 30)

	clock = pygame.time.Clock()

	puntos = [0, 0]

	while True:
		time = clock.tick(60)
		keys = pygame.key.get_pressed()
		for eventos in pygame.event.get():
			if eventos.type == QUIT:
				sys.exit(0)

		puntos = bola.actualizar(time, pala_jug, pala_cpu, puntos)
		pala_jug.mover(time, keys)
		pala_cpu.ia(time, bola)

		p_jug, p_jug_rect = texto(str(puntos[0]), WIDTH/4, 40)
		p_cpu, p_cpu_rect = texto(str(puntos[1]), WIDTH-WIDTH/4, 40)

		screen.blit(background_image, (0, 0))
		screen.blit(p_jug, p_jug_rect)
		screen.blit(p_cpu, p_cpu_rect)
		screen.blit(bola.image, bola.rect)
		screen.blit(pala_jug.image, pala_jug.rect)
		screen.blit(pala_cpu.image, pala_cpu.rect)
		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>Ya tenemos nuestros marcadores, pero el juego ni se inmuta cuando marcas un punto, lo solucionaremos en próximas entregas.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/" title="Pygame IX: Sistema de puntuación">Pygame IX: Sistema de puntuación</a></li><li><a href="http://razonartificial.com/2010/02/pygame-8-inteligencia/" title="Pygame VIII: Inteligencia artificial">Pygame VIII: Inteligencia artificial</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/2OfJkQMNl-HgZME9_FJFy1Ggbbo/0/da"><img src="http://feedads.g.doubleclick.net/~a/2OfJkQMNl-HgZME9_FJFy1Ggbbo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/2OfJkQMNl-HgZME9_FJFy1Ggbbo/1/da"><img src="http://feedads.g.doubleclick.net/~a/2OfJkQMNl-HgZME9_FJFy1Ggbbo/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/caqB34nK3ac" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Pygame IX: Sistema de puntuación</title>
		<link>http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/</link>
		<comments>http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 14:46:12 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=184</guid>
		<description><![CDATA[En este tutorial y el próximo vamos a aprender a manejar fuentes tipográficas en Pygame. Crearemos un sistema de puntuación para nuestro Pong, consistirá en dos marcadores para cada jugador que si consigues meter un punto al rival aumenta en uno. ¿Sencillo no? Vamos allá Creando un sistema de puntuación Lo primero es crear un [...]]]></description>
			<content:encoded><![CDATA[<p>En este tutorial y el próximo vamos a aprender a manejar fuentes tipográficas en Pygame. Crearemos un sistema de puntuación para nuestro Pong, consistirá en dos marcadores para cada jugador que si consigues meter un punto al rival aumenta en uno. ¿Sencillo no? Vamos allá</p>
<h3>Creando un sistema de puntuación</h3>
<p>Lo primero es crear un sistema que controle los puntos, es decir, comprobar si la bola traspasa las palas y toca el borde de la ventana que tiene detrás. Esto lo controlará como siempre la bola y su método <strong>actualizar</strong>.<span id="more-184"></span></p>
<pre class="brush: python;">
def update(self, time, pala_jug, pala_cpu, puntos):
	self.rect.centerx += self.speed[0] * time
	self.rect.centery += self.speed[1] * time

	if self.rect.left &lt;= 0:
		puntos[1] += 1
	if self.rect.right &gt;= WIDTH:
		puntos[0] += 1

	if self.rect.left &lt;= 0 or self.rect.right &gt;= WIDTH:
		self.speed[0] = -self.speed[0]
		self.rect.centerx += self.speed[0] * time
	if self.rect.top &lt;= 0 or self.rect.bottom &gt;= HEIGHT:
		self.speed[1] = -self.speed[1]
		self.rect.centery += self.speed[1] * time

	if pygame.sprite.collide_rect(self, pala_jug):
		self.speed[0] = -self.speed[0]
		self.rect.centerx += self.speed[0] * time

	if pygame.sprite.collide_rect(self, pala_cpu):
		self.speed[0] = -self.speed[0]
		self.rect.centerx += self.speed[0] * time

	return puntos
</pre>
<p>Como vemos le añadimos un nuevo parámetro llamado puntos, puntos es una lista que contiene los puntos de los dos jugadores en el el puntos[0] los puntos del jugador y en el puntos[1] los puntos de la cpu.</p>
<p>Luego añadimos las <strong>líneas de la 5 a la 8</strong> que controlan si la parte izquierda de la pelota (<strong>línea 5</strong>) toca el el borde izquierdo de la ventana en cuyo caso aumenta puntos[1] (el marcador de la cpu) en 1 (<strong>línea 6</strong>). La <strong>líneas 7 y 8</strong> hacen lo mismo, pero a la inversa.</p>
<p>Por último al final del método se <strong>retorna puntos</strong>, necesario para almacenarla en una variable.</p>
<p>Ahora debemos crear la lista puntos en nuestra función principal, yo la he creado justo antes de entrar en el bucle del juego:</p>
<pre class="brush: python;">
puntos = [0, 0]
</pre>
<p>Ahora tenemos que modificar la llamada a <strong>bola.actualizar</strong> dentro del bucle del juego para pasarle nuestra lista puntos y recuperarla de nuevo con los posibles nuevos valores.</p>
<pre class="brush: python;">
puntos = bola.actualizar(time, pala_jug, pala_cpu, puntos)
</pre>
<p>Por lo que el código nos queda así:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

class Bola(pygame.sprite.Sprite):
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/ball.png&quot;, True)
		self.rect = self.image.get_rect()
		self.rect.centerx = WIDTH / 2
		self.rect.centery = HEIGHT / 2
		self.speed = [0.5, -0.5]

	def actualizar(self, time, pala_jug, pala_cpu, puntos):
		self.rect.centerx += self.speed[0] * time
		self.rect.centery += self.speed[1] * time

		if self.rect.left &lt;= 0:
			puntos[1] += 1
		if self.rect.right &gt;= WIDTH:
			puntos[0] += 1

		if self.rect.left &lt;= 0 or self.rect.right &gt;= WIDTH:
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time
		if self.rect.top &lt;= 0 or self.rect.bottom &gt;= HEIGHT:
			self.speed[1] = -self.speed[1]
			self.rect.centery += self.speed[1] * time

		if pygame.sprite.collide_rect(self, pala_jug):
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time

		if pygame.sprite.collide_rect(self, pala_cpu):
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time

		return puntos

class Pala(pygame.sprite.Sprite):
	def __init__(self, x):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/pala.png&quot;)
		self.rect = self.image.get_rect()
		self.rect.centerx = x
		self.rect.centery = HEIGHT / 2
		self.speed = 0.5

	def mover(self, time, keys):
		if self.rect.top &gt;= 0:
			if keys[K_UP]:
				self.rect.centery -= self.speed * time
		if self.rect.bottom &lt;= HEIGHT:
			if keys[K_DOWN]:
				self.rect.centery += self.speed * time

	def ia(self, time, ball):
		if ball.speed[0] &gt;= 0 and ball.rect.centerx &gt;= WIDTH/2:
			if self.rect.centery &lt; ball.rect.centery:
				self.rect.centery += self.speed * time
			if self.rect.centery &gt; ball.rect.centery:
				self.rect.centery -= self.speed * time

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)

	background_image = load_image('images/fondo_pong.png')
	bola = Bola()
	pala_jug = Pala(30)
	pala_cpu = Pala(WIDTH - 30)

	clock = pygame.time.Clock()

	puntos = [0, 0]

	while True:
		time = clock.tick(60)
		keys = pygame.key.get_pressed()
		for eventos in pygame.event.get():
			if eventos.type == QUIT:
				sys.exit(0)

		puntos = bola.actualizar(time, pala_jug, pala_cpu, puntos)
		pala_jug.mover(time, keys)
		pala_cpu.ia(time, bola)
		screen.blit(background_image, (0, 0))
		screen.blit(bola.image, bola.rect)
		screen.blit(pala_jug.image, pala_jug.rect)
		screen.blit(pala_cpu.image, pala_cpu.rect)
		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>Esto como vemos no hace &#8220;nada&#8221; en el juego, ahora tenemos que buscar la manera de mostrar los puntos en nuestro juego. En el próximo tutorial trataremos con Fuentes tipográficas.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/" title="Pygame X: Fuentes tipográficas">Pygame X: Fuentes tipográficas</a></li><li><a href="http://razonartificial.com/2010/02/pygame-8-inteligencia/" title="Pygame VIII: Inteligencia artificial">Pygame VIII: Inteligencia artificial</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/W5WXcGthVADX_ZZX7kAp73difgM/0/da"><img src="http://feedads.g.doubleclick.net/~a/W5WXcGthVADX_ZZX7kAp73difgM/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/W5WXcGthVADX_ZZX7kAp73difgM/1/da"><img src="http://feedads.g.doubleclick.net/~a/W5WXcGthVADX_ZZX7kAp73difgM/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/5cIlTXvfPdo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Pygame VIII: Inteligencia artificial</title>
		<link>http://razonartificial.com/2010/02/pygame-8-inteligencia/</link>
		<comments>http://razonartificial.com/2010/02/pygame-8-inteligencia/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 22:58:47 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=179</guid>
		<description><![CDATA[En el siguiente tema no introduciremos ningún concepto nuevo de Pygame, pero si usaremos un poco de todo lo usado en los anteriores tutoriales para crear la pala que controlará el ordenador, se podría decir que es una Inteligencia Artificial muy básica. Creando la pala de la CPU Esto se hace igual que como creamos [...]]]></description>
			<content:encoded><![CDATA[<p>En el siguiente tema no introduciremos ningún concepto nuevo de Pygame, pero si usaremos un poco de todo lo usado en los anteriores tutoriales para crear la pala que controlará el ordenador, se podría decir que es una Inteligencia Artificial muy básica.</p>
<h3>Creando la pala de la CPU</h3>
<p>Esto se hace igual que como creamos la <strong>pala_jug</strong> o la <strong>bola</strong>, ponemos la siguiente línea en la función principal debajo de <strong>pala_jug</strong>.<span id="more-179"></span></p>
<pre class="brush: python;">
pala_cpu = Pala(WIDTH - 30)
</pre>
<p>En su momento pala_jug le pasamos como parámetro el valor 30 que quería decir que el centerx estaba a 30 píxeles de el borde izquierdo, ahora le pasamos WIDTH &#8211; 30, es decir a 30 píxeles del borde derecho.</p>
<p>También debemos añadir la línea:</p>
<pre class="brush: python;">
screen.blit(pala_cpu.image, pala_cpu.rect)
</pre>
<p>En el bucle principal, debajo de los demas blit, como siempre. Con esto ya tenemos nuestro Sprite puesto en pantalla.</p>
<p>Ahora vamos a hacer que detecte también las colisiones, para ello volvemos a actualizar el método actualizar de la clase Bola:</p>
<pre class="brush: python;">
def actualizar(self, time, pala_jug, pala_cpu):
	self.rect.centerx += self.speed[0] * time
	self.rect.centery += self.speed[1] * time
	if self.rect.left &lt;= 0 or self.rect.right &gt;= WIDTH:
		self.speed[0] = -self.speed[0]
		self.rect.centerx += self.speed[0] * time
	if self.rect.top &lt;= 0 or self.rect.bottom &gt;= HEIGHT:
		self.speed[1] = -self.speed[1]
		self.rect.centery += self.speed[1] * time

	if pygame.sprite.collide_rect(self, pala_jug):
		self.speed[0] = -self.speed[0]
		self.rect.centerx += self.speed[0] * time

	if pygame.sprite.collide_rect(self, pala_cpu):
		self.speed[0] = -self.speed[0]
		self.rect.centerx += self.speed[0] * time
</pre>
<p>Como podemos ver añadimos otro párametro al método <strong>pala_cpu</strong> que servirá para añadirle el Sprite <strong>pala_cpu</strong> como hicimos con <strong>pala_jug</strong> y añadimos las tres últimas líneas que son idénticas a las anteriores salvo que ahora para <strong>pala_cpu</strong>.</p>
<p>Recordad pasarle el parametro nuevo a la línea que llama a la función actualizar de la bola en el bucle del juego. Así:</p>
<pre class="brush: python;">
ball.update(time, pala_jug, pala_cpu)
</pre>
<p>Dotando de Inteligencia Artificial a la Pala</p>
<p>Bueno ahora viene lo interesante, lograr que la pala se mueva para golpear la bola, esto se hace definiendo otro método en la clase <strong>Pala</strong> al método lo llamaré <strong>ia</strong>.</p>
<pre class="brush: python;">
def ia(self, time, ball):
	if ball.speed[0] &gt;= 0 and ball.rect.centerx &gt;= WIDTH/2:
		if self.rect.centery &lt; ball.rect.centery:
			self.rect.centery += self.speed * time
		if self.rect.centery &gt; ball.rect.centery:
			self.rect.centery -= self.speed * time
</pre>
<p>En la <strong>línea 1</strong> vemos que recibe como siempre self y time y aparte recibe ball que es la bola, es necesario pues el método necesita conocer donde está la bola.</p>
<p>En la <strong>línea 2</strong> comprobamos que <em>ball.speed[0] &gt;= 0</em>, es decir, que la velocidad en el eje x de la pelota sea positiva, es decir, que la pelota se este moviendo hacia la derecha (hacia la pala de la cpu) y tambien comprueba que <em>ball.rect.centerx &gt;= WIDTH/2</em> es decir que el centro x de la pelota sea mayor o igual que el centro del tablero, es decir, que la pelota este en el campo de la cpu.</p>
<p>Por tanto la <strong>línea 2</strong> es un condicional que comprueba que la pelota vaya hacia donde está la pala de la cpu y que este en su campo, sino, que no se mueva. Esto se hace para que la CPU no sea invencible y no llegue a todas las pelotas.</p>
<p>La <strong>línea 3</strong> comprueba si el centery de la pelota es menor que el centery de la bola, es decir si la pala está más arriba que que la pelota en cullo caso, ejecuta la <strong>línea 4</strong> que mueve la pala de la cpu hacia abajo.</p>
<p>Las <strong>líneas 5 y 6</strong> hacen lo mismo, pero a la inversa como se ve a simple vista.</p>
<p>Ahora solo nos queda llamar a la ia junto con las llamadas <strong>actualizar</strong> de la <strong>bola</strong> y <strong>mover</strong> de la <strong>pala_cpu</strong>.</p>
<pre class="brush: python;">
pala_cpu.ia(time, bola)
</pre>
<p>El código nos queda de la siguiente manera:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

class Bola(pygame.sprite.Sprite):
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/ball.png&quot;, True)
		self.rect = self.image.get_rect()
		self.rect.centerx = WIDTH / 2
		self.rect.centery = HEIGHT / 2
		self.speed = [0.5, -0.5]

	def actualizar(self, time, pala_jug, pala_cpu):
		self.rect.centerx += self.speed[0] * time
		self.rect.centery += self.speed[1] * time
		if self.rect.left &lt;= 0 or self.rect.right &gt;= WIDTH:
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time
		if self.rect.top &lt;= 0 or self.rect.bottom &gt;= HEIGHT:
			self.speed[1] = -self.speed[1]
			self.rect.centery += self.speed[1] * time

		if pygame.sprite.collide_rect(self, pala_jug):
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time

		if pygame.sprite.collide_rect(self, pala_cpu):
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time

class Pala(pygame.sprite.Sprite):
	def __init__(self, x):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/pala.png&quot;)
		self.rect = self.image.get_rect()
		self.rect.centerx = x
		self.rect.centery = HEIGHT / 2
		self.speed = 0.5

	def mover(self, time, keys):
		if self.rect.top &gt;= 0:
			if keys[K_UP]:
				self.rect.centery -= self.speed * time
		if self.rect.bottom &lt;= HEIGHT:
			if keys[K_DOWN]:
				self.rect.centery += self.speed * time

	def ia(self, time, ball):
		if ball.speed[0] &gt;= 0 and ball.rect.centerx &gt;= WIDTH/2:
			if self.rect.centery &lt; ball.rect.centery:
				self.rect.centery += self.speed * time
			if self.rect.centery &gt; ball.rect.centery:
				self.rect.centery -= self.speed * time

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)

	background_image = load_image('images/fondo_pong.png')
	bola = Bola()
	pala_jug = Pala(30)
	pala_cpu = Pala(WIDTH - 30)

	clock = pygame.time.Clock()

	while True:
		time = clock.tick(60)
		keys = pygame.key.get_pressed()
		for eventos in pygame.event.get():
			if eventos.type == QUIT:
				sys.exit(0)

		bola.actualizar(time, pala_jug, pala_cpu)
		pala_jug.mover(time, keys)
		pala_cpu.ia(time, bola)
		screen.blit(background_image, (0, 0))
		screen.blit(bola.image, bola.rect)
		screen.blit(pala_jug.image, pala_jug.rect)
		screen.blit(pala_cpu.image, pala_cpu.rect)
		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>Ahora el juego es jugable, pero no tiene ni sistema de puntuación, ni sonidos ni nada de nada. Lo solucionaremos en los próximos tutoriales.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/" title="Pygame X: Fuentes tipográficas">Pygame X: Fuentes tipográficas</a></li><li><a href="http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/" title="Pygame IX: Sistema de puntuación">Pygame IX: Sistema de puntuación</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/pnuGGIhyV4OWhLW3Mhz9UpjbyAQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/pnuGGIhyV4OWhLW3Mhz9UpjbyAQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/pnuGGIhyV4OWhLW3Mhz9UpjbyAQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/pnuGGIhyV4OWhLW3Mhz9UpjbyAQ/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/m0corTLkY_w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/02/pygame-8-inteligencia/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Pygame VII: Colisiones</title>
		<link>http://razonartificial.com/2010/02/pygame-7-colisiones/</link>
		<comments>http://razonartificial.com/2010/02/pygame-7-colisiones/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 20:27:41 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=171</guid>
		<description><![CDATA[Tenemos una pelota que se mueve como loca y una pala que va para arriba y para abajo a nuestra voluntad, es hora de que se den cuenta que están en el mismo mundo. Vamos a crear colisiones entre los dos sprites. Actualizando el método actualizar de la clase Bola Saber si un Sprite colisiona [...]]]></description>
			<content:encoded><![CDATA[<p>Tenemos una pelota que se mueve como loca y una pala que va para arriba y para abajo a nuestra voluntad, es hora de que se den cuenta que están en el mismo mundo. Vamos a crear colisiones entre los dos sprites.</p>
<h3>Actualizando el método actualizar de la clase Bola</h3>
<p>Saber si un Sprite colisiona con otro es muy fácil en Python, basta con ejecutar el siguiente método:</p>
<pre class="brush: python;">
pygame.sprite.collide_rect(objeto1, objeto2)
</pre>
<p>Esto comprueba si el rectángulo del Sprite objeto1 está en contacto con el rectángulo de objeto2, por lo que es tan fácil como mejorar el método actualizar de la clase Bola para que lo tenga en cuenta:<span id="more-171"></span></p>
<pre class="brush: python;">
def actualizar(self, time, pala_jug):
	self.rect.centerx += self.speed[0] * time
	self.rect.centery += self.speed[1] * time
	if self.rect.left &lt;= 0 or self.rect.right &gt;= WIDTH:
		self.speed[0] = -self.speed[0]
		self.rect.centerx += self.speed[0] * time
	if self.rect.top &lt;= 0 or self.rect.bottom &gt;= HEIGHT:
		self.speed[1] = -self.speed[1]
		self.rect.centery += self.speed[1] * time

	if pygame.sprite.collide_rect(self, pala_jug):
		self.speed[0] = -self.speed[0]
		self.rect.centerx += self.speed[0] * time
</pre>
<p>Como vemos todo igual, salvo que ahora recibe un parámetro más que es <strong>pala_jug</strong> por el que pasaremos el Sprite con el que queremos comprobar si colisiona, en este caso <strong>pala_jug</strong>.</p>
<p>Luego al final añadimos 3 líneas con un nuevo condicional con el que comprobamos si la pelota choca contra la pala, en caso afirmativo cambiamos la dirección de la bola como cuando choca con el borde izquierdo de la ventana.</p>
<p>Por último solo actualizamos la llamada a la función <strong>actualizar</strong> que hacemos desde el bucle para pasarle la <strong>pala_jug</strong>.</p>
<pre class="brush: python;">
bola.actualizar(time, pala_jug)
</pre>
<p>Y con esto ya hemos logrado que nuestra bola detecte si ha chocado contra la pala del jugador en caso afirmativo &#8220;rebota&#8221;.</p>
<p>Asi nos queda el código:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

class Bola(pygame.sprite.Sprite):
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/ball.png&quot;, True)
		self.rect = self.image.get_rect()
		self.rect.centerx = WIDTH / 2
		self.rect.centery = HEIGHT / 2
		self.speed = [0.5, -0.5]

	def actualizar(self, time, pala_jug):
		self.rect.centerx += self.speed[0] * time
		self.rect.centery += self.speed[1] * time
		if self.rect.left &lt;= 0 or self.rect.right &gt;= WIDTH:
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time
		if self.rect.top &lt;= 0 or self.rect.bottom &gt;= HEIGHT:
			self.speed[1] = -self.speed[1]
			self.rect.centery += self.speed[1] * time

		if pygame.sprite.collide_rect(self, pala_jug):
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time

class Pala(pygame.sprite.Sprite):
	def __init__(self, x):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/pala.png&quot;)
		self.rect = self.image.get_rect()
		self.rect.centerx = x
		self.rect.centery = HEIGHT / 2
		self.speed = 0.5

	def mover(self, time, keys):
		if self.rect.top &gt;= 0:
			if keys[K_UP]:
				self.rect.centery -= self.speed * time
		if self.rect.bottom &lt;= HEIGHT:
			if keys[K_DOWN]:
				self.rect.centery += self.speed * time

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)

	background_image = load_image('images/fondo_pong.png')
	bola = Bola()
	pala_jug = Pala(30)

	clock = pygame.time.Clock()

	while True:
		time = clock.tick(60)
		keys = pygame.key.get_pressed()
		for eventos in pygame.event.get():
			if eventos.type == QUIT:
				sys.exit(0)

		bola.actualizar(time, pala_jug)
		pala_jug.mover(time, keys)
		screen.blit(background_image, (0, 0))
		screen.blit(bola.image, bola.rect)
		screen.blit(pala_jug.image, pala_jug.rect)
		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>En el siguiente tutorial crearemos la pala del jugador de la CPU y la dotaremos de Inteligencia Artificial para que golpee la pelota.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/" title="Pygame X: Fuentes tipográficas">Pygame X: Fuentes tipográficas</a></li><li><a href="http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/" title="Pygame IX: Sistema de puntuación">Pygame IX: Sistema de puntuación</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/YD4dwosOEXRsE9gjWlmOz36a2mA/0/da"><img src="http://feedads.g.doubleclick.net/~a/YD4dwosOEXRsE9gjWlmOz36a2mA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/YD4dwosOEXRsE9gjWlmOz36a2mA/1/da"><img src="http://feedads.g.doubleclick.net/~a/YD4dwosOEXRsE9gjWlmOz36a2mA/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/XMAdcgJw7Z4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/02/pygame-7-colisiones/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Pygame VI: Control del teclado</title>
		<link>http://razonartificial.com/2010/02/pygame-6-control-del-teclado/</link>
		<comments>http://razonartificial.com/2010/02/pygame-6-control-del-teclado/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 18:52:19 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=160</guid>
		<description><![CDATA[Bien ya tenemos nuestra pelota que se mueve como loca por toda la pantalla. El siguiente paso es crear un nuevo Sprite para las palas, este a diferencia de la bola no se moverá solo sino que lo controlaremos nosotros por el teclado. Creando el Sprite Pala Lo primero que necesitamos es una imagen que [...]]]></description>
			<content:encoded><![CDATA[<p>Bien ya tenemos nuestra pelota que se mueve como loca por toda la pantalla. El siguiente paso es crear un nuevo Sprite para las palas, este a diferencia de la bola no se moverá solo sino que lo controlaremos nosotros por el teclado.</p>
<h3>Creando el Sprite Pala</h3>
<p>Lo primero que necesitamos es una imagen que la represente, <a href="http://razonartificial.com/wp-content/uploads/2010/02/pala.png">descargarla aquí</a> y como siempre, al directorio images. Como ves la pala no es más que un rectángulo blanco, no es cuestión de complicarse.</p>
<p>La clase Pala es casi idéntica a la clase Bola, salvo por unos pequeños cambios:<span id="more-160"></span></p>
<pre class="brush: python;">
class Pala(pygame.sprite.Sprite):
	def __init__(self, x):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/pala.png&quot;)
		self.rect = self.image.get_rect()
		self.rect.centerx = x
		self.rect.centery = HEIGHT / 2
		self.speed = 0.5
</pre>
<p>Como vemos es idéntica salvo que ahora le pasamos el parámetro <strong>x</strong> para usarlo en <em>self.rect.centerx</em>, esto es debido a que necesitamos dos palas una en la parte izquierda y otra en la derecha, con el parámetro x definimos a que altura del <strong>eje x</strong> queremos colocar el Sprite.</p>
<p>Otro cambio es la velocidad, como la pala del Pong solo se mueve en el eje y no definimos velocidad para el eje x.</p>
<p>para crear la pala del jugador ya sabéis, debajo de donde habéis creado la bola ponéis la siguiente línea:</p>
<pre class="brush: python;">
pala_jug = Pala(30)
</pre>
<p>La llamo <strong>pala_jug</strong> porque habrá otra que será la <strong>pala_cpu</strong> que será la que maneje el ordenador. Como ves le paso como valor de <strong>x = 30</strong>, esto quiere decir que <strong>centerx</strong> estará a 30 px del borde derecho de la ventana.</p>
<p>Por último dentro del bucle lo de siempre, despues de actualizar el fondo y la bola actualizamos la pala:</p>
<pre class="brush: python;">
screen.blit(pala_jug.image, pala_jug.rect)
</pre>
<h3>Moviendo la pala</h3>
<p>Para mover la pala definimos el método <strong>mover</strong> dentro de la clase Pala:</p>
<pre class="brush: python;">
def mover(self, time, keys):
	if self.rect.top &gt;= 0:
		if keys[K_UP]:
			self.rect.centery -= self.speed * time
	if self.rect.bottom &lt;= HEIGHT:
		if keys[K_DOWN]:
			self.rect.centery += self.speed * time
</pre>
<p>Recibe los parámetros self y time como el <strong>método</strong> actualizar de la bola y además recibe el parámetro keys que luego definiremos y que es una lista con el valor booleano de las teclas pulsadas.</p>
<p>La <strong>línea 2 y 5</strong> comprueban que la parte superior (en el caso de la linea 2) de la pala sea mayor o igual a 0 y que la parte inferior de la pala (línea 5) sea menor o igual que que la altura de la ventana. Resumiendo comprueban que la pala no se sale de la ventana.</p>
<p>La <strong>línea 3</strong> comprueba si la constante <strong>K_UP</strong> de <strong>keys</strong> es 1, lo que querría decir que tenemos presionada la tecla de la flecha hacia arriba del teclado.</p>
<p>La <strong>línea 5</strong> en caso de tener la tecla presionada <strong>disminuye</strong> el valor de <strong>centery</strong> haciendo que la pala se mueva hacia arriba.</p>
<p>La <strong>línea 6 y 7</strong> hacen lo mismo, pero para abajo y <strong>aumentando</strong> el valor de <strong>centery</strong>.</p>
<p>Ahora solo debemos saber que teclas se están pulsando creando la variable keys, esto se consigue añadiendo la siguiente línea en el bucle principal, justo despues de comprobar el tiempo transcurrido con time.</p>
<pre class="brush: python;">
keys = pygame.key.get_pressed()
</pre>
<p>Esto nos devuelve las teclas pulsadas en una lista como explicamos arriba.</p>
<p>Por ultimo debemos llamar al método mover en el bucle justo después de actualizar la bola, con la línea:</p>
<pre class="brush: python;">
pala_jug.mover(time, keys)
</pre>
<p>El código nos queda así:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

class Bola(pygame.sprite.Sprite):
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/ball.png&quot;, True)
		self.rect = self.image.get_rect()
		self.rect.centerx = WIDTH / 2
		self.rect.centery = HEIGHT / 2
		self.speed = [0.5, -0.5]

	def actualizar(self, time):
		self.rect.centerx += self.speed[0] * time
		self.rect.centery += self.speed[1] * time
		if self.rect.left &lt;= 0 or self.rect.right &gt;= WIDTH:
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time
		if self.rect.top &lt;= 0 or self.rect.bottom &gt;= HEIGHT:
			self.speed[1] = -self.speed[1]
			self.rect.centery += self.speed[1] * time

class Pala(pygame.sprite.Sprite):
	def __init__(self, x):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/pala.png&quot;)
		self.rect = self.image.get_rect()
		self.rect.centerx = x
		self.rect.centery = HEIGHT / 2
		self.speed = 0.5

	def mover(self, time, keys):
		if self.rect.top &gt;= 0:
			if keys[K_UP]:
				self.rect.centery -= self.speed * time
		if self.rect.bottom &lt;= HEIGHT:
			if keys[K_DOWN]:
				self.rect.centery += self.speed * time

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)

	background_image = load_image('images/fondo_pong.png')
	bola = Bola()
	pala_jug = Pala(30)

	clock = pygame.time.Clock()

	while True:
		time = clock.tick(60)
		keys = pygame.key.get_pressed()
		for eventos in pygame.event.get():
			if eventos.type == QUIT:
				sys.exit(0)

		bola.actualizar(time)
		pala_jug.mover(time, keys)
		screen.blit(background_image, (0, 0))
		screen.blit(bola.image, bola.rect)
		screen.blit(pala_jug.image, pala_jug.rect)
		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>Ya tenemos nuestra pala que podemos controlar con el teclado, pero la bola como vemos para olímpicamente de ella y la atraviesa. En el siguiente tutorial aprenderemos a crear colisiones entre Sprites</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/" title="Pygame X: Fuentes tipográficas">Pygame X: Fuentes tipográficas</a></li><li><a href="http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/" title="Pygame IX: Sistema de puntuación">Pygame IX: Sistema de puntuación</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/5xN0i_pcRB6bbr-glRDM8usNORo/0/da"><img src="http://feedads.g.doubleclick.net/~a/5xN0i_pcRB6bbr-glRDM8usNORo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/5xN0i_pcRB6bbr-glRDM8usNORo/1/da"><img src="http://feedads.g.doubleclick.net/~a/5xN0i_pcRB6bbr-glRDM8usNORo/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/bnwtE01O9kM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/02/pygame-6-control-del-teclado/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Pygame V: Moviendo Sprite</title>
		<link>http://razonartificial.com/2010/02/pygame-5-moviendo-sprites/</link>
		<comments>http://razonartificial.com/2010/02/pygame-5-moviendo-sprites/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 17:07:02 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=148</guid>
		<description><![CDATA[En el siguiente tutorial aprenderemos a mover nuestra pelota por la ventana y hacer que rebote contra los bordes, Usaremos física y matemáticas básicas para mover la pelota. El método actualizar Para mover la pelota crearemos un metodo llamado actualizar dentro de la clase Bola que controle el movimiento de la pelota y si choca [...]]]></description>
			<content:encoded><![CDATA[<p>En el siguiente tutorial aprenderemos a mover nuestra pelota por la ventana y hacer que rebote contra los bordes, Usaremos física y matemáticas básicas para mover la pelota.</p>
<h3>El método actualizar</h3>
<p>Para mover la pelota crearemos un metodo llamado actualizar dentro de la clase Bola que controle el movimiento de la pelota y si choca contra los bordes de la ventana, el método es el siguiente:</p>
<pre class="brush: python;">
def actualizar(self, time):
	self.rect.centerx += self.speed[0] * time
	self.rect.centery += self.speed[1] * time
	if self.rect.left &lt;= 0 or self.rect.right &gt;= WIDTH:
		self.speed[0] = -self.speed[0]
		self.rect.centerx += self.speed[0] * time
	if self.rect.top &lt;= 0 or self.rect.bottom &gt;= HEIGHT:
		self.speed[1] = -self.speed[1]
		self.rect.centery += self.speed[1] * time
</pre>
<p><span id="more-148"></span></p>
<p>La <strong>linea 1 </strong>define el método, recibe el parámetro self (como siempre) y el parámetro time que es el tiempo transcurrido, más adelante lo explicamos.</p>
<p>La <strong>línea 2 y 3 </strong>usa la física básica de espacio es igual a la velocidad por el tiempo (e = v*t), por tanto establecemos que el centro de nuestro rectangulo en x es el valor que tenía (self.rect.centerx) más (+=) la valocidad a la que se mueve en el eje x (self.speed[0]) por (*) el tiempo transcurrido (time). Lo mismo se aplica al eje y en la línea 3.</p>
<p>La <strong>linea 4, 5 y 6</strong> establece que si la parte izquierda del rectángulo de la bola es menor o igual a 0 ó mayor o igual a el ancho de la pantalla (WIDTH), es decir,  que este en el extremo izquierdo o derecho, la velocidad de x (self.speed[0]) cambie de signo (-self.speed[0]) con esto conseguiremos que vaya hacia el otro lado.</p>
<p>Las <strong>líneas 7, 8 y 9</strong> es lo mismo pero en el eje y como se puede ver.</p>
<h3>Creando un reloj</h3>
<p>Ahora vamos a crear un reloj que controle el tiempo del juego, esto es importante para el movimiento, pues sabemos cuanto tiempo a pasado desde la ultima actualización de la pelota y con ello poder situarla en el espacio.</p>
<pre class="brush: python;">
clock = pygame.time.Clock()
</pre>
<p>Esta línea va justo antes de entrar en el bucle del juego y sirve para crear el reloj con el que gestionar el tiempo.</p>
<p>Ahora necesitamos saber cuanto tiempo pasa cada vez que se ejecuta una interección del bucle, para ello dentro del bucle ponemos como primera línea:</p>
<pre class="brush: python;">
time = clock.tick(60)
</pre>
<p>El 60 que se le pasa como parámetro es el framerate, con él nos aseguramos de que el juego no va a más de la velocidad estipulada. Con ello conseguimos que el juego corra igual en todos los ordenadores. <a href="http://www.losersjuegos.com.ar/traducciones/pygame/time/clock">Aquí más inftomación</a>.</p>
<p>Por último debemos actualizar la posición de la bola antes de actualizarla en la ventana, es decir antes de los screen.blit.</p>
<pre class="brush: python;">
bola.actualizar(time)
</pre>
<p>Como ves le pasamos el parametro time que es el tiempo que ha pasado desde la última vez que se ejecuto.</p>
<p>El juego queda así:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

class Bola(pygame.sprite.Sprite):
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/ball.png&quot;, True)
		self.rect = self.image.get_rect()
		self.rect.centerx = WIDTH / 2
		self.rect.centery = HEIGHT / 2
		self.speed = [0.5, -0.5]

	def actualizar(self, time):
		self.rect.centerx += self.speed[0] * time
		self.rect.centery += self.speed[1] * time
		if self.rect.left &lt;= 0 or self.rect.right &gt;= WIDTH:
			self.speed[0] = -self.speed[0]
			self.rect.centerx += self.speed[0] * time
		if self.rect.top &lt;= 0 or self.rect.bottom &gt;= HEIGHT:
			self.speed[1] = -self.speed[1]
			self.rect.centery += self.speed[1] * time

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)

	background_image = load_image('images/fondo_pong.png')
	bola = Bola()

	clock = pygame.time.Clock()

	while True:
		time = clock.tick(60)
		for eventos in pygame.event.get():
			if eventos.type == QUIT:
				sys.exit(0)

		bola.actualizar(time)
		screen.blit(background_image, (0, 0))
		screen.blit(bola.image, bola.rect)
		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>Ya nuestra pelota se mueve y rebota contra las paredes. En el próximo tutorial crearemos el Sprite pala y aprenderemos a moverlo con el teclado.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/" title="Pygame X: Fuentes tipográficas">Pygame X: Fuentes tipográficas</a></li><li><a href="http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/" title="Pygame IX: Sistema de puntuación">Pygame IX: Sistema de puntuación</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/KAMhK-Ze25KPixwRoqjs0MxhW-c/0/da"><img src="http://feedads.g.doubleclick.net/~a/KAMhK-Ze25KPixwRoqjs0MxhW-c/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/KAMhK-Ze25KPixwRoqjs0MxhW-c/1/da"><img src="http://feedads.g.doubleclick.net/~a/KAMhK-Ze25KPixwRoqjs0MxhW-c/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/CPAmoMZ7Sqs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/02/pygame-5-moviendo-sprites/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Pygame IV: Creando Sprites</title>
		<link>http://razonartificial.com/2010/02/pygame-4-creando-sprites/</link>
		<comments>http://razonartificial.com/2010/02/pygame-4-creando-sprites/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 16:16:02 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=137</guid>
		<description><![CDATA[La parte 1, parte 2 y parte 3 nos sirvieron como introducción a Pygame, aprendimos a iniciar pygame, crear ventanas y poner imágenes. con ello creamos una plantilla básica desde la que trabajar con Pygame. Ahora empieza lo divertido, vamos a crear nuestro primer juego, y como no será un clon del clásico Pong. Lo [...]]]></description>
			<content:encoded><![CDATA[<p>La <a href="http://razonartificial.com/2010/02/pygame-1-importar-inicializar/">parte 1</a>, <a href="http://razonartificial.com/2010/02/pygame-2-creando-una-ventana/">parte 2</a> y <a href="http://razonartificial.com/2010/02/pygame-3-cargar-imagenes/">parte 3</a> nos sirvieron como introducción a Pygame, aprendimos a iniciar pygame, crear ventanas y poner imágenes. con ello creamos una plantilla básica desde la que trabajar con Pygame.</p>
<p>Ahora empieza lo divertido, vamos a crear nuestro primer juego, y como no será un clon del clásico Pong. Lo primero que necesitamos es hacer una copia de nuestra plantilla creada en los anteriores tutoriales y guardarla con el nombre pong.py que será sobre el archivo que trabajaremos. Lo primero que haremos será <a href="http://razonartificial.com/wp-content/uploads/2010/02/fondo_pong.png">descargar este fondo</a>, mucho más apropiado  y guardarlo en la carpeta images de nuestro directorio base.</p>
<p>Recordad cambiar el nombre de la imagen en el programa.</p>
<pre class="brush: python;">
background_image = load_image('images/fondo_pong.png')
</pre>
<p><span id="more-137"></span></pre>
<h3>La clase Bola</h3>
<p>Para crear la pelota de nuestro Pong lo primero que necesitamos es la imagen de la pelota, <a href="http://razonartificial.com/wp-content/uploads/2010/02/ball.png">descargar esta</a> y guardarla como siempre en el directorio images.</p>
<p>Ahora vamos a crear una clase para la pelota, que será el Sprite de nuestra pelota, un Sprite es más que una imagen, es una superficie que puede interactuar, moverse y demás.</p>
<pre class="brush: python;">
class Bola(pygame.sprite.Sprite):
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/ball.png&quot;, True)
		self.rect = self.image.get_rect()
		self.rect.centerx = WIDTH / 2
		self.rect.centery = HEIGHT / 2
		self.speed = [0.5, -0.5]
</pre>
<p>La <strong>línea 1</strong> crea la clase Bola que hereda los métodos de la clase pygame.sprite.Sprite, esto es muy importante debido a que contiene métodos necesarios para el manejo de Sprites.</p>
<p>La <strong>línea 2</strong> crea el método __init__ que inicializa la clase.</p>
<p>La <strong>línea 3</strong> invoca al método init de la clase heredada, muy importante también y difícil de explicar para comenzar.</p>
<p>La <strong>línea 4</strong> ya nos suena más y lo que hace es cargar con nuestra función load_image() la imagen de la pelota, como vemos tenemos puesto True porque la pelota si tiene zonas transparentes.</p>
<p>La <strong>línea 5 </strong>es de las cosas más útiles de pygame la función self.image.get_rect() obtiene un rectangulo con las dimensiones y posición de la imagen (en este caso self.image) y se lo asignamos a self.rect</p>
<p>Aquí hago un inciso para comentar que get_rect() tiene unos parámetros muy útiles que podemos modificar para posicionar y redimensionar nuestra imagen, son los siguientes:</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>
<p>Así que podemos acceder a los diferentes valores como self.rect.centerx que nos devuelve la posición central de la pelota respecto al ancho de la pantalla, y así con todos es cuestión de probarlos, pero más o menos se entiende lo que devuelve cada uno. Lo mejor de todos ellos es que si cambias el valor de alguno el resto se actualiza. Aquí lo tenéis mejor expliado.</p>
<p>En la <strong>línea 6 y 7</strong> usamos las propiedades de rect y con centerx y centery definimos el centro de la pelota en el centro de la pantalla. (aquí vemos porque pusimos WIDTH y HEIGHT como constantes globales).</p>
<p>La <strong>línea 8 </strong>define la velocidad que queremos para la pelota, separamos la velocidad en dos, la velocidad en el eje x y la velocidad en el eje y, luego veremos porqué.</p>
<h3>Poniendo una Bola en nuestro juego</h3>
<p>Bien una vez creada la clase Bola vamos a crear una bola, para ello como cuando cargamos el fondo, debemos cargarla antes del bucle del juego, con la siguiente línea:</p>
<pre class="brush: python;">
bola = Bola()
</pre>
<p>Ahora solo debemos "ponerla" en nuestra ventana, ejecutando la siguiente sentencia, después de la sentencia idéntica a la del fondo.</p>
<pre class="brush: python;">
screen.blit(bola.image, bola.rect)
</pre>
<p>Como puedes ver ahora no le pasamos la imagen y en vez de unas coordenadas como en el fondo (entonces le pasamos (0, 0)) le pasamos el rect de la bola, con esto conseguiremos más tarde que cada vez que movamos el rect, moveremos la pelota de sitio.</p>
<p>Es muy importante "ponerla en pantalla después y no antes que el fondo porque si pones la pelota y luego pones el fondo encima esta no se verá, como es lógico.</p>
<p>El programa nos queda así:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

class Bola(pygame.sprite.Sprite):
	def __init__(self):
		pygame.sprite.Sprite.__init__(self)
		self.image = load_image(&quot;images/ball.png&quot;, True)
		self.rect = self.image.get_rect()
		self.rect.centerx = WIDTH / 2
		self.rect.centery = HEIGHT / 2
		self.speed = [0.5, -0.5]

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)

	background_image = load_image('images/fondo_pong.png')
	bola = Bola()

	while True:
		for eventos in pygame.event.get():
			if eventos.type == QUIT:
				sys.exit(0)

		screen.blit(background_image, (0, 0))
		screen.blit(bola.image, bola.rect)
		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>Ahora tenemos una pelota en el centro de nuestra pantalla lo siguiente es conseguir que se mueva e interactúe con los bordes. Todo eso en el próximo tutorial.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/" title="Pygame X: Fuentes tipográficas">Pygame X: Fuentes tipográficas</a></li><li><a href="http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/" title="Pygame IX: Sistema de puntuación">Pygame IX: Sistema de puntuación</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/zobUHBaHpWijoM7xaBuwQQBpXcg/0/da"><img src="http://feedads.g.doubleclick.net/~a/zobUHBaHpWijoM7xaBuwQQBpXcg/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/zobUHBaHpWijoM7xaBuwQQBpXcg/1/da"><img src="http://feedads.g.doubleclick.net/~a/zobUHBaHpWijoM7xaBuwQQBpXcg/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/-J-MR9Ri_34" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/02/pygame-4-creando-sprites/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Pygame III: Cargar imágenes</title>
		<link>http://razonartificial.com/2010/02/pygame-3-cargar-imagenes/</link>
		<comments>http://razonartificial.com/2010/02/pygame-3-cargar-imagenes/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 15:03:03 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=127</guid>
		<description><![CDATA[En el primer tutorial aprendimos a importar e inicializar, En la segunda parte a crear una ventana y en este aprenderemos a cargar imagenes y a mostrarlas en pantalla. Cargando imagenes Para cargar una imagen en Pygame vamos a usar una función que está muy bien y facilita mucho el cargar imágenes al vuelo, pongo la función [...]]]></description>
			<content:encoded><![CDATA[<p>En el <a href="http://razonartificial.com/2010/02/pygame-1-importar-inicializar/">primer tutorial</a> aprendimos a importar e inicializar, En la <a href="http://razonartificial.com/2010/02/pygame-2-creando-una-ventana/">segunda parte</a> a crear una ventana y en este aprenderemos a cargar imagenes y a mostrarlas en pantalla.</p>
<h3>Cargando imagenes</h3>
<p>Para cargar una imagen en Pygame vamos a usar una función que está muy bien y facilita mucho el cargar imágenes al vuelo, pongo la función y la explicamos línea por línea:</p>
<pre class="brush: python;">
def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image
</pre>
<p><span id="more-127"></span></pre>
<p>La <strong>línea 1</strong> define la función, recibe dos parámetros el nombre/ruta del archivo y la segunda si tiene parte transparente (por defecto definida como falso).</p>
<p>La<strong> línea 2</strong> asigna a la variable imagen la imagen a través de la función de Pygame <em>pygame.image.load()</em> si se puede sino, en la <strong>líneas 3 y 4</strong> manejan el error y salen del programa.</p>
<p>La <strong>línea 5 </strong>convierte la imagen al tipo interno de Pygame que hace que sea mucho más eficiente.</p>
<p>Las <strong>línea 6</strong> es un condicional que controla  si el parámetro transparent es verdadero y en caso afirmativo ejecuta las <strong>líneas 7 y 8</strong>, la primera obtiene el color del pixel (0, 0) de la imagen (esquina superior izquierda) y la la <strong>línea 8</strong> lo define como color transparente de la imagen. Es decir que si quieres una imagen con transparencia, el color que actúa como transparente se toma del pixel superior izquierdo, así que asegúrate que este color no está en la imagen.</p>
<p>Por último la <strong>línea 9</strong> retorna la imagen después de todo el proceso.</p>
<p>El programa nos queda así:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)
	while True:
		for eventos in pygame.event.get():
			if eventos.type == QUIT:
				sys.exit(0)
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<h3>Poniendo un fondo</h3>
<p>Vamos a poner un fondo a nuestra ventana usando nuestra función <strong>load_image</strong>. Lo primero es <a href="http://razonartificial.com/wp-content/uploads/2010/02/fondo.jpg">descargar el fondo</a> y guardarlo en la carpeta images del directorio de trabajo.</p>
<p>Para cargar la imagen usaremos la siguiente línea, la ponemos justo antes de entrar en el bucle del juego:</p>
<pre class="brush: python;">
background_image = load_image('images/fondo.jpg')
</pre>
<p>Como ves no definimos color transparente, porque para el fondo no es necesario.</p>
<p>Ahora necesitamos "ponerla en la ventana" para ello dentro del bucle principal debemos definir que imagen poner y en que posición:</p>
<pre class="brush: python;">
screen.blit(background_image, (0, 0))
</pre>
<p>Esto es lo que hace es poner la imagen la pantalla sobre las que había, recibe dos parámetros (en realidad algunos más), la imagen a poner y en que lugar situar la esquina superior izquierda de la imagen, en este caso (0, 0), es decir, queremos que la esquina superior izquierda de la imagen este en la posición (0, 0), con esto conseguimos que el fondo ocupe toda la ventana (si la imagen es mayor o superior a la ventana, claro está).</p>
<p>por último, como última línea del bucle debemos incluir la siguiente línea:</p>
<pre class="brush: python;">
pygame.display.flip()
</pre>
<p>Esto lo que hace es actualizar toda la ventana para que se muestren los cambios que han sucedido.</p>
<p>El programa nos queda de la siguiente manera:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

def load_image(filename, transparent=False):
        try: image = pygame.image.load(filename)
        except pygame.error, message:
                raise SystemExit, message
        image = image.convert()
        if transparent:
                color = image.get_at((0,0))
                image.set_colorkey(color, RLEACCEL)
        return image

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)

	background_image = load_image('images/fondo.jpg')

	while True:
		for eventos in pygame.event.get():
			if eventos.type == QUIT:
				sys.exit(0)

		screen.blit(background_image, (0, 0))
		pygame.display.flip()
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>Bien con esto hemos conseguido poner una imagen de fondo y tener una forma fácil de cargar imagenes en Pygame. Aconsejo guardar esto como plantilla base de Pygame, pues en casi todos los juegos necesitaremos cargar imagenes y establecer un fondo por defecto.</p>
<p>En el siguiente tutorial empezaremos a crear nuestro primer juego, un Pong, utilizando sptrites (imagenes con movimientos), colisiones entradas por teclado y demás cosas.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/" title="Pygame X: Fuentes tipográficas">Pygame X: Fuentes tipográficas</a></li><li><a href="http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/" title="Pygame IX: Sistema de puntuación">Pygame IX: Sistema de puntuación</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/Rj6U6WCmIC78M3jrJh1Qig40f_8/0/da"><img src="http://feedads.g.doubleclick.net/~a/Rj6U6WCmIC78M3jrJh1Qig40f_8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/Rj6U6WCmIC78M3jrJh1Qig40f_8/1/da"><img src="http://feedads.g.doubleclick.net/~a/Rj6U6WCmIC78M3jrJh1Qig40f_8/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/QSoRqwOhbmw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/02/pygame-3-cargar-imagenes/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Pygame II: Creando una ventana</title>
		<link>http://razonartificial.com/2010/02/pygame-2-creando-una-ventana/</link>
		<comments>http://razonartificial.com/2010/02/pygame-2-creando-una-ventana/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 13:27:20 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=122</guid>
		<description><![CDATA[Seguimos con los tutoriales de Pygame, después de aprender a importar e inicializar, vamos a lo que es realmente divertido. En este tutorial aprenderemos a crear una ventana, así que abrimos nuestro archivo donde ya tenemos empezado nuestro programa y continuamos. Creando una ventana Lo primero que necesitamos es definir las constantes del ancho y [...]]]></description>
			<content:encoded><![CDATA[<p>Seguimos con los tutoriales de Pygame, después de aprender a <a href="http://razonartificial.com/2010/02/pygame-1-importar-inicializar/">importar e inicializar</a>, vamos a lo que es realmente divertido. En este tutorial aprenderemos a crear una ventana, así que abrimos nuestro archivo donde ya tenemos empezado nuestro programa y continuamos.</p>
<h3>Creando una ventana</h3>
<p>Lo primero que necesitamos es definir las constantes del ancho y alto de la ventana, yo estas las defino como constantes porque de momento no vas a hacer cosas complicadas con cambios de resolución ni nada por el estilo y tenerlas como constantes ayuda a trabajar con ellas desde cualquier clase o función.<span id="more-122"></span></p>
<pre class="brush: python;">
WIDTH = 640
HEIGHT = 480
</pre>
<p>Ahora pasamos a crear la ventana, se debe crear dentro de la función main(), es tan fácil como lo siguiente:</p>
<pre class="brush: python;">
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(&quot;Pruebas Pygame&quot;)
</pre>
<p>La primera linea crea una ventana, date cuenta que la pasamos la tupla (WIDTH, HEIGHT) para definir las dimensiones de la ventana. La segunda línea sirve para definir el título de la ventana.</p>
<p>El programa nos queda así:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>Si lo ejecutas te darás cuenta que se crea una ventana, pero esta desaparece al instante. Esto es debido a que necesitamos crear un bucle infinito, que será el bucle del juego. Lo creamos justo después de la creación de la ventana.</p>
<pre class="brush: python;">
while True:
	pass
</pre>
<p>Como vemos es un bucle infinito vacío que se ejecuta eternamente y hace que la ventana no se cierra, pero ¡sorpresa!, ahora no hay forma de cerrar la ventana si no es matando el proceso. La solución consiste en que el bucle infinito compruebe si queremos cerrar la ventana y en ese caso que deje de ejecutarse. Sustituimos las dos líneas anteriores por:</p>
<pre class="brush: python;">
while True:
	for eventos in pygame.event.get():
		if eventos.type == QUIT:
			sys.exit(0)
</pre>
<p>La primera línea del bucle recorre con un for <em>pygame.event.get() </em>que es una lista interna de Pygame con los eventos que se están ejecutando. En la siguiente línea comprobamos que si el tipo de evento es igual a QUIT, es decir, que si le estamos dando a la crucesita de cerrar ventana. En caso de que sí, invoca a <em>sys.exit(0)</em>, para el que necesitamos haber importado el <strong>módulo sys</strong>, y cierra el programa. Ya tenemos la manera de crear una ventana y controlar cuando cerrarla.</p>
<p>El código nos queda así:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import sys, pygame
from pygame.locals import *

# Constantes
WIDTH = 640
HEIGHT = 480

# Clases
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

def main():
	screen = pygame.display.set_mode((WIDTH, HEIGHT))
	pygame.display.set_caption(&quot;Pruebas Pygame&quot;)
	while True:
		for eventos in pygame.event.get():
			if eventos.type == QUIT:
				sys.exit(0)
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>En el próximo tutorial aprenderemos a cargar imágenes y ponerlas en nuestra ventana.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/" title="Pygame X: Fuentes tipográficas">Pygame X: Fuentes tipográficas</a></li><li><a href="http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/" title="Pygame IX: Sistema de puntuación">Pygame IX: Sistema de puntuación</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/8gSefq75t0mrtBFoPrzl2osI6pk/0/da"><img src="http://feedads.g.doubleclick.net/~a/8gSefq75t0mrtBFoPrzl2osI6pk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/8gSefq75t0mrtBFoPrzl2osI6pk/1/da"><img src="http://feedads.g.doubleclick.net/~a/8gSefq75t0mrtBFoPrzl2osI6pk/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/epG_qTUpEWU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/02/pygame-2-creando-una-ventana/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Pygame I: Importar e inicializar</title>
		<link>http://razonartificial.com/2010/02/pygame-1-importar-inicializar/</link>
		<comments>http://razonartificial.com/2010/02/pygame-1-importar-inicializar/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 12:51:40 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Pygame]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=110</guid>
		<description><![CDATA[He decidido progresar en el tema de aplicaciones gráficas y aunque GASP estaba bien, se quedaba corto y no era muy estable. Ahora he comenzado con Pygame que a pesar de que podemos encontrar toda la referencia traducida, esto no nos ayuda a comenzar pues no sabe bien como usar las cosas. Voy a intentar [...]]]></description>
			<content:encoded><![CDATA[<p>He decidido progresar en el tema de aplicaciones gráficas y aunque <a href="http://razonartificial.com/2010/01/gasp-graficos-faciles-en-python/">GASP</a> estaba bien, se quedaba corto y no era muy estable. Ahora he comenzado con <a href="http://www.pygame.org/">Pygame</a> que a pesar de que podemos encontrar <a href="http://www.losersjuegos.com.ar/traducciones/pygame">toda la referencia traducida</a>, esto no nos ayuda a comenzar pues no sabe bien como usar las cosas. Voy a intentar explicar unas nociones básicas de Pygame que he obtenido a base de leer y probar. Con estos tutoriales no seréis expertos en Pygame, pero si tendréis un punto de partida para empezar. Vamos allá.</p>
<h3>Requesitos previos</h3>
<ul>
<li>Conocimientos de <strong>Python</strong>. Se da por hecho que se manejan con soltura la creación de clases, funciones y demás.</li>
<li>Algo de <strong>matemáticas</strong> y <strong>física</strong> básica. Para empezar con conceptos básicos de lo que es un punto matemática y algunas formulas básicas de física tenemos de sobra.</li>
</ul>
<h3>Qué necesitamos</h3>
<ul>
<li>Tener Python y Pygame instalados.</li>
<li>Un IDE o editor de texto a elección.</li>
<li>Un directorio base donde trabajar. Yo he creado una carpeta llamada <strong>pygame</strong> con dos carpetas en el interior llamadas <strong>images</strong> y <strong>sound.</strong></li>
</ul>
<p><span id="more-110"></span></p>
<h3>El documento base</h3>
<p>Mi método de trabajo es tener todo organizado para que el código sea fácil de leer, es por eso que antes de empezar voy a compartir mi plantilla base que podéis guardar como <strong>plantilla.py</strong>. A partir de ella escribo mis programas y es desde donde comenzare estos tutoriales.</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos

# Constantes

# Clases
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

def main():
	return 0

if __name__ == '__main__':
	main()
</pre>
<h3>Importar e inicializar</h3>
<p>Lo primero que hay que hacer para trabajar con Pygame es importarlo e inicializarlo. Para importarlo basta con las líneas:</p>
<pre class="brush: python;">
import pygame
from pygame.locals import *
</pre>
<p>La primera línea importa pygame y la segunda carga las constantes para poder utilizar, por ejemplo, K_ESCAPE, en lugar de estar de tener que llamarla a través del módulo Pygame.</p>
<p>Una vez importado pasamos a inicializar. Se puede inicializar cualquiera de los módulos de Python por separado, pero para no complicarnos por ahora inicializaremos todo pygame con la línea:</p>
<pre class="brush: python;">
pygame.init()
</pre>
<p>Esta se debe ejecutar antes de empezar a usar Pygame, un buen lugar es antes de llamar a la función main(), justo aquí:</p>
<pre class="brush: python;">
if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>Con esto ya tenemos importado e inicializado Pygame y estamos listos para trabajar, dejo como se debe tener el archivo hasta ahora:</p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Módulos
import pygame
from pygame.locals import *

# Constantes

# Clases
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

# ---------------------------------------------------------------------

def main():
	return 0

if __name__ == '__main__':
	pygame.init()
	main()
</pre>
<p>En el siguiente tutorial aprenderemos a crear una ventana y poner en ella una imagen.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/07/juego-de-la-serpiente-paso-a-paso-parte-2/" title="Juego de la serpiente paso a paso. Parte 2">Juego de la serpiente paso a paso. Parte 2</a></li><li><a href="http://razonartificial.com/2010/04/engine-ii-el-archivo-principal/" title="Engine II: El archivo principal">Engine II: El archivo principal</a></li><li><a href="http://razonartificial.com/2010/04/engine-i-preparandonos-para-trabajar/" title="Engine I: Preparándonos para trabajar">Engine I: Preparándonos para trabajar</a></li><li><a href="http://razonartificial.com/2010/02/pygame-10-fuentes-tipograficas/" title="Pygame X: Fuentes tipográficas">Pygame X: Fuentes tipográficas</a></li><li><a href="http://razonartificial.com/2010/02/pygame-9-sistema-puntuacion/" title="Pygame IX: Sistema de puntuación">Pygame IX: Sistema de puntuación</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/Wq8HamewKx8C9C8FbXL8nvQoN38/0/da"><img src="http://feedads.g.doubleclick.net/~a/Wq8HamewKx8C9C8FbXL8nvQoN38/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/Wq8HamewKx8C9C8FbXL8nvQoN38/1/da"><img src="http://feedads.g.doubleclick.net/~a/Wq8HamewKx8C9C8FbXL8nvQoN38/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/C2NJ1pOH1bE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/02/pygame-1-importar-inicializar/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Optimización basada en colonias de hormigas</title>
		<link>http://razonartificial.com/2010/01/optimizacion-basada-en-colonias-de-hormigas-en-la-naturaleza/</link>
		<comments>http://razonartificial.com/2010/01/optimizacion-basada-en-colonias-de-hormigas-en-la-naturaleza/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 17:01:43 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Artículos]]></category>
		<category><![CDATA[Vida Artificial]]></category>
		<category><![CDATA[Algoritmo]]></category>
		<category><![CDATA[Búsqueda]]></category>
		<category><![CDATA[Hormigas]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=97</guid>
		<description><![CDATA[Muchas veces para resolver problemas de inteligencia artificial no hay nada como fijarse en la naturaleza. Uno de estos casos es la capacidad que tienen las hormigas  para encontrar el camino más corto entre la comida y el hormiguero, teniendo en cuenta que las hormigas son ciegas. Pero actuando como una colonia y no como [...]]]></description>
			<content:encoded><![CDATA[<p>Muchas veces para resolver problemas de inteligencia artificial no hay nada como fijarse en la naturaleza. Uno de estos casos es la capacidad que tienen las hormigas  para encontrar el camino más corto entre la comida y el hormiguero, teniendo en cuenta que las hormigas son ciegas. Pero actuando como una colonia y no como individuos aislados consiguen el objetivo.</p>
<h2>Las Hormigas en la naturaleza</h2>
<p>Las hormigas son ciegas y salen del hormiguero en busca de comida sin nada que las oriente, van caminando a ciegas en busca de alimento hasta que lo encuentran, luego regresan al hormiguero y &#8220;comunica&#8221; al resto de las hormigas el camino hacia la comida y no solo eso, sino que ha medida que van más hormigas consiguen optimizarse para encontrar el camino más corto del hormiguero a la fuente de alimento. ¿Cómo es esto posible si son ciegas y no tienen un medio de comunicación entre ellas? La clave está en las <strong>feromonas</strong>.</p>
<p>Las hormigas al caminar van dejando tras de sí una sustancia llamada feromonas que aparte de servirle para encontrar el camino de regreso al hormiguero sirve para orientar a otras hormigas hacia la comida. Las hormigas tienden a seguir el rastro de feromonas de otros individuos de su especie. Las hormigas solo detectan las feromonas cuando están en contancto directo con ella, es decir, es un contacto local.</p>
<h3>Optimizando el resultado</h3>
<p>¿Y como pueden encontrar el camino más corto con este método? Fácil, las feromonas es una sustancia química que al pasar otra hormiga por el mismo lugar intensifica y si no pasa ninguna con el tiempo se evapora. Esto hace que entre más hormigas pasan por un lugar más feromonas tendrá ese camino y más deseable será para otras hormigas, en cambio en los caminos menos trancitados se van evaporando las feromonas haciendo que sean menos deseables.</p>
<p><a href="http://razonartificial.com/wp-content/uploads/2010/01/hormigas.png"><img class="aligncenter size-full wp-image-98" title="hormigas" src="http://razonartificial.com/wp-content/uploads/2010/01/hormigas.png" alt="" width="459" height="319" /></a></p>
<p>En la imagen superior podemos ver dos caminos para llegar desde el hormiguero hasta la comida, en principio, las hormigas a ciegas elegirán aleatoriamente uno de las dos caminos como podemos ver en <strong>B</strong>. Es obvio que el camino superior es mucho más corto, esto produce que las hormigas que han optado por el camino superior lleguen y vuelvan más rápido a la comida que las que eligen el camino inferior, al ir y venir más rápido la cantidad de feromonas se verá reforzada más rápidamente y se evaporará mucho más despacio. Con esto se conseguirá que próximas hormigas a la hora de decidir uno de los dos caminos elijan el camino con más feromonas, reforzando el camino superior y hacienda cada vez menos atractivo el camino inferior.</p>
<p>Al cabo de un tiempo casi todas las hormigas irán por el camino superior como podemos ver en <strong>D</strong>.</p>
<p>Aquí hemos visto como las hormigas en la naturaleza sin comunicarse entre ellas son capaces de organizarse como una colonia para lograr un objetivo común. Los individuos por si solo no son nada, pero la suma de los agentes hacen un sistema muy eficaz, en el próximo artículo veremos como aplicar esto en un programa informático para encontrar el camino más corto.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/04/usando-pilas-binarias-en-un-pathfinding-a/" title="Usando Pilas Binarias en Pathfinding A*">Usando Pilas Binarias en Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-de-2-niveles/" title="Pathfinding A* de 2 niveles">Pathfinding A* de 2 niveles</a></li><li><a href="http://razonartificial.com/2010/04/heuristica-para-el-pathfinding-a-star/" title="Heurística para el Pathfinding A*">Heurística para el Pathfinding A*</a></li><li><a href="http://razonartificial.com/2010/04/pathfinding-a-en-python-parte-iii/" title="Pathfinding A* en Python. Parte III">Pathfinding A* en Python. Parte III</a></li><li><a href="http://razonartificial.com/2010/03/pathfinding-a-en-python-parte-i/" title="Pathfinding A* en Python. Parte I">Pathfinding A* en Python. Parte I</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/fLVghGSqDa9ENdGeZIAHnSMgCvw/0/da"><img src="http://feedads.g.doubleclick.net/~a/fLVghGSqDa9ENdGeZIAHnSMgCvw/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/fLVghGSqDa9ENdGeZIAHnSMgCvw/1/da"><img src="http://feedads.g.doubleclick.net/~a/fLVghGSqDa9ENdGeZIAHnSMgCvw/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/ltCxAjwS26M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/01/optimizacion-basada-en-colonias-de-hormigas-en-la-naturaleza/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Curso Python II – Tipos y variables</title>
		<link>http://razonartificial.com/2010/01/curso-python-ii-tipos-y-variables/</link>
		<comments>http://razonartificial.com/2010/01/curso-python-ii-tipos-y-variables/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 21:18:31 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Curso]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=78</guid>
		<description><![CDATA[Tipos de datos En el capítulo anterior vimos dos tipos de datos: Las cadenas de caracteres, que son un conjunto de letras, &#8220;Hola Mundo&#8221; y también vimos enteros que no son más que números. Anteriormente usamos la sentencia print para imprimir una cadena de caracteres, pero también puedes imprimir otros tipos de datos con print, [...]]]></description>
			<content:encoded><![CDATA[<h3>Tipos de datos</h3>
<p>En el capítulo anterior vimos dos tipos de datos: Las cadenas de caracteres, que son un conjunto de letras, &#8220;Hola Mundo&#8221; y también vimos enteros que no son más que números.</p>
<p>Anteriormente usamos la sentencia print para imprimir una cadena de caracteres, pero también puedes imprimir otros tipos de datos con print, como enteros.</p>
<pre>&gt;&gt;&gt; print 5
5</pre>
<p>Para saber de qué tipo es un dato en concreto puede usar la siguiente función, todavía no se preocupe por el concepto de función más adelante lo trataremos:</p>
<p><span id="more-78"></span></p>
<pre>&gt;&gt;&gt; type(5)
&lt;type 'int'&gt;
&gt;&gt;&gt; type("Hola Mundo")
&lt;type 'str'&gt;
&gt;&gt;&gt; type(4.2)
&lt;type 'float'&gt;
&gt;&gt;&gt; type("6")
&lt;type 'str'&gt;
&gt;&gt;&gt; type("8.45")
&lt;type 'str'&gt;</pre>
<p>Como vemos la función type() devuelve el tipo de dato que se encuentra entre paréntesis, vamos a ir línea por línea para ver que tipos de datos son:</p>
<p>En el primero como vemos al poner 5 devuelve int (integer es entero en inglés). &#8220;Hola Mundo&#8221; devuelve str de string (cadena en inglés). Ahora viene un tipo de dato nuevo 4.2 es un número decimal y en python se les llama float.</p>
<p class="advertencia">Los dos últimos son casos especiales &#8220;6&#8243; y &#8220;8.45&#8243; parecen de tipo int y float respectivamente, pero como están entre comillas para python son cadena de caracteres como lo era &#8220;Hola Mundo&#8221;, no son números y no se deben tratar como tal.</p>
<p class="advertencia">Otra cosa a tener en cuenta es que para imprimir un entero largo como por ejemplo 1000000 usted podría usar la &#8220;,&#8221; para separar los miles 1,000,000 con esto lo que estaría diciendo a python es que imprima 3 enteros: 1, 0, 0. Por tanto no use la coma para separar los miles.</p>
<pre>&gt;&gt;&gt; print 1000000

1000000
&gt;&gt;&gt; print 1,000,000
1 0 0</pre>
<h3>Variables</h3>
<p>Las variables son una de las características más importante de la programación y las encontrará en todos los lenguajes. Una variable en programación no dista mucho de una variable matemática es una palabra o letra que hace referencia a un valor en concreto.</p>
<pre>&gt;&gt;&gt; a = 5
&gt;&gt;&gt; mensaje = "Me gusta Python"
&gt;&gt;&gt; pi = 3.1415</pre>
<p>Como vemos mediante el signo &#8220;=&#8221; asignamos el valor que queramos a una variable. a vale 5, mensaje contiene &#8220;Me gusta Python&#8221; y pi el valor 3.1415.</p>
<p>Las sentencias anteriores también funcionan con variables, por ejemplo la sentencia print:</p>
<pre>&gt;&gt;&gt; print a
5
&gt;&gt;&gt; print mensaje
Me gusta Python
&gt;&gt;&gt; print pi
3.1415</pre>
<p>y también la función type(), en general en cualquier sitio donde puede ir un valor puede ir una variable que represente ese valor:</p>
<pre>&gt;&gt;&gt; type(a)
&lt;type 'int'&gt;
&gt;&gt;&gt; type(mensaje)
&lt;type 'str'&gt;
&gt;&gt;&gt; type(pi)
&lt;type 'float'&gt;</pre>
<p>como vemos el tipo que devuelve type() se corresponde con el tipo de dato que contiene cada una de las variables pasadas.</p>
<h3>Nombres de variable</h3>
<p>En general python acepta cualquier conjunto de letras y número como nombre de variable, pero hay una serie de reglas a tener en cuenta:</p>
<ul>
<li>Puedes usar números y letras pero debe comenzar con una letra.</li>
<li>Puedes usar mayúsculas y minúsculas, por convenio se suelen usar las minúsculas.</li>
<li>Python distingue entre mayúsculas y minúsculas no es la misma variable número que Número.</li>
<li>También es válido el guión bajo &#8220;_&#8221;, por ejemplo, numero_lapices.</li>
<li>Totalmente prohibido el uso de tildes en los nombres de variable.</li>
<li>tampoco puedes usar como nombres de variable las palabras reservadas de Python, son las siguientes: and, assert, break, class, continue, def, del, elif, else, except, exec, finally, for, from, global, if, import, in, is, lambda, not, or, pass, print, raise, return, try y while.</li>
</ul>
<p class="consejo">Procura usar nombres de variables descriptivos, que no sean ambiguos y que definan claramente lo que contienen, por ejemplo si quieres almacenar el número de caramelos no uses c = 20, sino, num_caramelos = 20.</p>
<h3>Operadores y expresiones</h3>
<p>En el primer capítulo ya vimos que podíamos usar python para resolver operaciones matemáticas como 5+4, no es difícil averiguar que estas operaciones se pueden realizar también con variables, veamos algunos ejemplos:</p>
<pre>&gt;&gt;&gt; a = 2
&gt;&gt;&gt; b = 5
&gt;&gt;&gt; a*b
10
&gt;&gt;&gt; c = a + b
&gt;&gt;&gt; b*c+a
37
&gt;&gt;&gt; -a
-2</pre>
<p>Como vemos podemos usar las variables como si de números se trataran y asignar a una variable el resultado es una operación ya sea entre variables, o números y variables.</p>
<p>Los operadores que encontrarás en Python son los típicos matemáticos +, -, *, / son los símbolos de suma, resta, multiplicación y división el operador ** es el operador de potencia y uno no tan común es el % que devuelve el resto de una división, ejemplos de uso:</p>
<pre>&gt;&gt;&gt; 5+4
9
&gt;&gt;&gt; 5-4
1
&gt;&gt;&gt; 5*4
20
&gt;&gt;&gt; 5/4
1
&gt;&gt;&gt; 5%4
1
&gt;&gt;&gt; 5.0/4.0
1.25
&gt;&gt;&gt; 5**4
625</pre>
<p>De todos parecen resultados lógicos menos 5/4 que devuelve 1 cuando el resultado es 1.25, esto es así porque estas dividiendo dos enteros y por tanto devuelve un entero, para que el resultado se nos dé en decimales alguno de los operandos debe ser de tipo float como hemos hecho en 5.0/4.0 que en este caso si devuelve 1.25.</p>
<p class="advertencia">No olvide que el operador % no tiene nada que ver con el porcentaje y que lo que devuelve es el resto de una división.</p>
<p>Si ha sido un poco curioso verá que python evalúa más que operaciones simples, expresiones como las siguientes:</p>
<pre>&gt;&gt;&gt; a = 6
&gt;&gt;&gt; b = 4.53
&gt;&gt;&gt; c = a + b * 8 ** 5 / a
&gt;&gt;&gt; print c
24745.84</pre>
<p class="consejo">En Python hay unas reglas para decidir que operaciones se hacen primero como ya dijimos, sinceramente yo nunca las aprendí, pienso que cuando se duda es más fácil aplicar paréntesis, aparte de que propicia menos errores el programa quedará más fácil de leer.</p>
<h3>Operaciones con cadenas</h3>
<p>Hasta ahora hemos visto operaciones que actúan sobre los tipos de datos int y float, pero ¿Qué pasa con las cadenas? en general es ilógico hacer una opereación sobre una cadena, pero algunas sí se pueden, eso sí, el resultado no será el esperado.</p>
<pre>&gt;&gt;&gt; a = "Hola"
&gt;&gt;&gt; b = "Mundo"
&gt;&gt;&gt; c = a + b
&gt;&gt;&gt; print c
HolaMundo
&gt;&gt;&gt; a*3
'HolaHolaHola'
&gt;&gt;&gt; c*2
'HolaMundoHolaMundo'
&gt;&gt;&gt; a + " " + b
'Hola Mundo'</pre>
<p>Como vemos el operador &#8220;+&#8221; sirve para unir dos cadenas de caracteres y el operador &#8220;*&#8221; multiplica el valor de la cadena por el número pasado.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/curso-python-iv-%e2%80%93-funciones/" title="Curso Python IV – Funciones">Curso Python IV – Funciones</a></li><li><a href="http://razonartificial.com/2010/08/curso-python-iii-%e2%80%93-scripts-y-comentarios/" title="Curso Python III – Scripts y Comentarios">Curso Python III – Scripts y Comentarios</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-i-interprete-y-scripts/" title="Curso Python I &#8211; Intérprete y scripts">Curso Python I &#8211; Intérprete y scripts</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-%e2%80%93-presentacion/" title="Curso Python – Presentación">Curso Python – Presentación</a></li><li><a href="http://razonartificial.com/2010/01/curso-python/" title="Curso Python">Curso Python</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/ezGZ0x1pxCJCc1mSVAWokmNThck/0/da"><img src="http://feedads.g.doubleclick.net/~a/ezGZ0x1pxCJCc1mSVAWokmNThck/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ezGZ0x1pxCJCc1mSVAWokmNThck/1/da"><img src="http://feedads.g.doubleclick.net/~a/ezGZ0x1pxCJCc1mSVAWokmNThck/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/phuQQBQdPi4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/01/curso-python-ii-tipos-y-variables/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Curso Python I – Intérprete y scripts</title>
		<link>http://razonartificial.com/2010/01/curso-python-i-interprete-y-scripts/</link>
		<comments>http://razonartificial.com/2010/01/curso-python-i-interprete-y-scripts/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 21:13:32 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Curso]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=74</guid>
		<description><![CDATA[Ejecutar Python Python tiene dos modos de ejecución, mediante scripts o interactivamente en el intérprete. A la hora de escribir programas serios usará la modalidad script, pero el modo intérprete es genial para probar pequeños código y para aprender. Para abrir el intérprete de Python en linux basta con escribir en la consola &#8220;python&#8221;, sin [...]]]></description>
			<content:encoded><![CDATA[<h3>Ejecutar Python</h3>
<p>Python tiene dos modos de ejecución, mediante scripts o interactivamente en el intérprete. A la hora de escribir programas serios usará la modalidad script, pero el modo intérprete es genial para probar pequeños código y para aprender.</p>
<p>Para abrir el intérprete de Python en linux basta con escribir en la consola &#8220;python&#8221;, sin comillas. En Windows basta con buscar en el menú de inicio el programa. En cualquier caso se abrirá una ventana de consola con lo siguiente:</p>
<p><span id="more-74"></span></p>
<pre>Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit (Intel)]
on win32
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt;</pre>
<p>En este caso es la versión 2.6.2 para Windows, pero en Linux será algo parecido. Lo importante es ese &#8220;&gt;&gt;&gt;&#8221; es la entrada de datos de Python. Puedes usarlo como calculadora, por ejemplo:</p>
<pre>&gt;&gt;&gt; 5+4
9
&gt;&gt;&gt; 8*3
24
&gt;&gt;&gt; 2+4*3
14
&gt;&gt;&gt; (2+4)*3
18
&gt;&gt;&gt; _+2
20</pre>
<p>Como puedes ver funciona como una calculadora. Algunas cosas a tener en cuenta que se pueden ver aquí:</p>
<ul>
<li>Python sigue el orden matemático establecido para realizar operaciones, es decir, multiplicaciones y divisiones antes que sumas y restas, paréntesis antes que todo. Por ejemplo fíjese que en el 2+4*3, Python primero hace la multiplicación y a continuación la suma, dando como resultado 14, pero para (2+4)*3, al ir los paréntesis antes según las reglas matemáticas primero suma 2+4 y a continuación lo multiplica por 3 dando 18.</li>
<li>el &#8220;_&#8221;, hace referencia a la última salida de datos del intérprete. Fíjese en el &#8220;_+2&#8243;, la salida anterior había sido 18 más 2 da como resultado 20.</li>
</ul>
<h3>El primer programa</h3>
<p>Tradicionalmente, cuando se aprende un lenguaje de programación el primer programa que se enseña es el &#8220;Hola Mundo&#8221;, que consiste en mostrar en pantalla el texto &#8220;Hola Mundo&#8221;, en otros lenguajes suele tener sentido pues sirve para explicar cosas básicas del lenguaje, pero en Python es tan simple como escribir en consola lo siguiente:</p>
<pre>&gt;&gt; print "Hola Mundo"
Hola Mundo</pre>
<p>Ya ves, nada del otro mundo, pero sirve para que aprendamos la primera palabra clave de python: <em>print</em>. <em>print</em> es la salida estándar en Python y su sintáxi es print más un valor, en este caso el valor es la cadena de caracteres &#8220;Hola Mundo&#8221;, pero no te preocupes por esto, ya trataremos las cadenas más adelante.</p>
<h3>Scripts</h3>
<p>El intérprete está muy bien para probar cosas y como calculadora(en realidad el intérprete es más potente de lo que parece, pero ya lo veremos), pero seguramente querrás guardar tus programas para ejecutarlos cuando tu quieras. Para ello deberás crear un script de Python que no es más que un fichero de texto plano con la extensión .py. Así que abre tu editor de texto plano favorito o el IDE que vayas a usar para programar en python y escribe ahí:</p>
<pre lang="python">print "Hola Mundo"</pre>
<p>Guarda el archivo y desde la consola, situando en la ruta donde hayas guardado el archivo escribe, si estas en linux:</p>
<pre>python nombreArchivo.py</pre>
<p>Y si estas en Windows, escribe simplemente:</p>
<pre>nombreArchivo.py</pre>
<p>Y ya puedes ejecutar tu script en Python, siempre que quieras de esta forma.</p>
<p>Bueno está ha sido la primera entrega del curso que sirve para ponernos en situación. Ahora que sabemos usar el intérprete y crear scripts en Python empieza lo bueno.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/curso-python-iv-%e2%80%93-funciones/" title="Curso Python IV – Funciones">Curso Python IV – Funciones</a></li><li><a href="http://razonartificial.com/2010/08/curso-python-iii-%e2%80%93-scripts-y-comentarios/" title="Curso Python III – Scripts y Comentarios">Curso Python III – Scripts y Comentarios</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-ii-tipos-y-variables/" title="Curso Python II &#8211; Tipos y variables">Curso Python II &#8211; Tipos y variables</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-%e2%80%93-presentacion/" title="Curso Python – Presentación">Curso Python – Presentación</a></li><li><a href="http://razonartificial.com/2010/01/curso-python/" title="Curso Python">Curso Python</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/VhRVf3TYX2C8Bo9bBd1MLIIRLmg/0/da"><img src="http://feedads.g.doubleclick.net/~a/VhRVf3TYX2C8Bo9bBd1MLIIRLmg/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/VhRVf3TYX2C8Bo9bBd1MLIIRLmg/1/da"><img src="http://feedads.g.doubleclick.net/~a/VhRVf3TYX2C8Bo9bBd1MLIIRLmg/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/0jTufEVQ5FM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/01/curso-python-i-interprete-y-scripts/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Curso Python – Presentación</title>
		<link>http://razonartificial.com/2010/01/curso-python-%e2%80%93-presentacion/</link>
		<comments>http://razonartificial.com/2010/01/curso-python-%e2%80%93-presentacion/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 21:08:31 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Tutoriales]]></category>
		<category><![CDATA[Curso]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=70</guid>
		<description><![CDATA[Este es el primer artículo acerca del curso sobre Python que voy a llevar en el blog. En esta parte se tratará la guía de estilo del curso, como estará estructurado y en definitiva todo lo necesario para poder entender y comprender el curso. Requesitos previos No es necesario haber programado nunca antes en algún lenguaje de programación, el curso [...]]]></description>
			<content:encoded><![CDATA[<p>Este es el primer artículo acerca del <strong>curso</strong> sobre <strong>Python</strong> que voy a llevar en el blog. En esta parte se tratará la guía de estilo del <strong>curso</strong>, como estará estructurado y en definitiva todo lo necesario para poder entender y comprender el <strong>curso</strong>.</p>
<h3>Requesitos previos</h3>
<p>No es necesario haber programado nunca antes en algún lenguaje de programación, el <strong>curso</strong> partirá desde cero por lo que cualquier podrá seguirlo. Aún que no es necesario haber programado nunca, el <strong>curso</strong> presupondrá unas nociones básicas sobre que es una variable o una constante, para esto no hace falta saber programación sino unas nociones básicas de matemáticas serán suficientes. También necesitará concer lo básico del manejo de ordenadores: crear ficheros, directorios, instalar programas, etc.</p>
<h3>Herramientas necesarias</h3>
<ul>
<li>Un sistema operativo, pueda usar el que quiera, pero recomendamos usar alguno de los Unix libre como Linux o BSD.</li>
<li>Intérprete <strong>Python</strong>. Lo puede obtener de <a href="http://python.org/">http://<strong>python</strong>.org</a>. Si usted usa una distribución linux probablemente ya lo tenga instalado.</li>
<li>Un editor de texto plano. puede usar el que quiera, yo recomiendo <a href="http://geany.org/">Geany</a>, es un IDE libre, multiplataforma, y sencillo, además tiene resaltodo y autocompletado de código. Si lo usas desde tiene una consola integrada perfecta para probar el código que vayas aprendiendo.</li>
<li>Ganas de aprender.</li>
</ul>
<h3>Guía de estilo</h3>
<p>El código de ejemplo se mostrará de la siguiente manera:</p>
<pre class="brush: python;">def multiplicar(x):
	n = 1
	while n &lt;= 10:
		r = n*x
		print x, &quot;x&quot;, n, &quot;=&quot;, r
		n += 1

num = input(&quot;Introduce un numero: &quot;)
multiplicar(num)</pre>
<p>La salida en consola se mostrará de la siguiente manera:</p>
<pre>Introduce un numero: 7
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70</pre>
<p>El siguiente recuadro amarillo es usado para mostrar advertencias y cosas a tener en cuenta:</p>
<p class="advertencia">Esto es un recuadro de advertencia, tenlos muy en cuenta a lo largo del curso.</p>
<p>Por último, los recuadros verdes son usados para consejos, tips y trucos.</p>
<p class="consejo">Esto es un recuadro de consejos. Échales un vistazo para que tu código sea mejor y eficaz.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/curso-python-iv-%e2%80%93-funciones/" title="Curso Python IV – Funciones">Curso Python IV – Funciones</a></li><li><a href="http://razonartificial.com/2010/08/curso-python-iii-%e2%80%93-scripts-y-comentarios/" title="Curso Python III – Scripts y Comentarios">Curso Python III – Scripts y Comentarios</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-ii-tipos-y-variables/" title="Curso Python II &#8211; Tipos y variables">Curso Python II &#8211; Tipos y variables</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-i-interprete-y-scripts/" title="Curso Python I &#8211; Intérprete y scripts">Curso Python I &#8211; Intérprete y scripts</a></li><li><a href="http://razonartificial.com/2010/01/curso-python/" title="Curso Python">Curso Python</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/NatSKbNYZdx6jRjWdXAZd_6-NrE/0/da"><img src="http://feedads.g.doubleclick.net/~a/NatSKbNYZdx6jRjWdXAZd_6-NrE/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/NatSKbNYZdx6jRjWdXAZd_6-NrE/1/da"><img src="http://feedads.g.doubleclick.net/~a/NatSKbNYZdx6jRjWdXAZd_6-NrE/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/PMPq1VKNuQM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/01/curso-python-%e2%80%93-presentacion/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Curso Python</title>
		<link>http://razonartificial.com/2010/01/curso-python/</link>
		<comments>http://razonartificial.com/2010/01/curso-python/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 21:01:54 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Curso]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=67</guid>
		<description><![CDATA[Está página va dedicada la Inteligencia Artificial, la Vida Artificial y la Robótica, todo a un nivel principiante y experimental para gente &#8220;normal&#8221; no para expertos, es por eso que todo lo que porgramo he decidido hacerlo con un lenguaje sencillo, claro y que no complique más las cosas. El lenguaje perfecto para esto para [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://razonartificial.com/wp-content/uploads/2010/01/python-logo.png"><img class="alignright size-full wp-image-68" title="python-logo" src="http://razonartificial.com/wp-content/uploads/2010/01/python-logo.png" alt="" width="149" height="148" /></a></p>
<p>Está página va dedicada la Inteligencia Artificial, la Vida Artificial y la Robótica, todo a un nivel principiante y experimental para gente &#8220;normal&#8221; no para expertos, es por eso que todo lo que porgramo he decidido hacerlo con un lenguaje sencillo, claro y que no complique más las cosas. El lenguaje perfecto para esto para mi es Python y aprenderlo no cuesta nada, es perfecto para quien se quiera iniciar en la programación.</p>
<p>Es por eso que he decidido continuar un curso que empecé hace tiempo sobre Python, para que la gente que se quiera iniciar en este mundo.</p>
<p>El <strong>curso</strong> se presentará de una manera amena, con ejemplos prácticos. Es decir, no me limitaré a dar la sintaxis de <strong>Python</strong>, tipos de datos y ya está, sino que después de explicar las cosas haré ejemplos prácticos y propondré ejercicios sobre la aprendido.</p>
<p>A través de los comentarios podrás preguntar todo tipo de dudas e incluso puedes mandarme los ejercicios para corregirlos.</p>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/08/curso-python-iv-%e2%80%93-funciones/" title="Curso Python IV – Funciones">Curso Python IV – Funciones</a></li><li><a href="http://razonartificial.com/2010/08/curso-python-iii-%e2%80%93-scripts-y-comentarios/" title="Curso Python III – Scripts y Comentarios">Curso Python III – Scripts y Comentarios</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-ii-tipos-y-variables/" title="Curso Python II &#8211; Tipos y variables">Curso Python II &#8211; Tipos y variables</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-i-interprete-y-scripts/" title="Curso Python I &#8211; Intérprete y scripts">Curso Python I &#8211; Intérprete y scripts</a></li><li><a href="http://razonartificial.com/2010/01/curso-python-%e2%80%93-presentacion/" title="Curso Python – Presentación">Curso Python – Presentación</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/rQKOAylhTI7L0LJBz7P7QX9zFjQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/rQKOAylhTI7L0LJBz7P7QX9zFjQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/rQKOAylhTI7L0LJBz7P7QX9zFjQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/rQKOAylhTI7L0LJBz7P7QX9zFjQ/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/XayKRMdPjew" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/01/curso-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Buscador de Caminos con Python</title>
		<link>http://razonartificial.com/2010/01/buscador-de-caminos-con-python/</link>
		<comments>http://razonartificial.com/2010/01/buscador-de-caminos-con-python/#comments</comments>
		<pubDate>Sun, 17 Jan 2010 20:40:59 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Ejemplos]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[backtracking]]></category>
		<category><![CDATA[GASP]]></category>
		<category><![CDATA[Inteligencia Artificial]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=58</guid>
		<description><![CDATA[Un problema típico de Inteligencia Artificial puede ser la búsqueda de caminos, he diseñado un programa en el que una pelotita en un laberinto tiene que encontrar la salida, el juego actúa por el método prueba error, la pelota busca las posibles caminos que puede seguir desde la posición que se encuentra y toma uno [...]]]></description>
			<content:encoded><![CDATA[<p>Un problema típico de Inteligencia Artificial puede ser la búsqueda de caminos, he diseñado un programa en el que una pelotita en un laberinto tiene que encontrar la salida, el juego actúa por el método prueba error, la pelota busca las posibles caminos que puede seguir desde la posición que se encuentra y toma uno de ellos, si llega a un callejón sin salida vuelve hasta la última intersección y toma otro de los caminos disponibles, así hasta encontrar la salida. Lo bueno de la IA es que recuerda muy bien que caminos y cuales no ha visitado, impidiendo que vuelva a pasar por una ya visitado.</p>
<p>Crear laberintos es muy fácil, solo hay que modificar el fichero laberinto.txt que viene de ejemplo y puedes hacer el laberinto que quieras para poner a prueba la IA.</p>
<pre># # # # # # # # # # # # # # # # #
# T . . . . . . . . . # . # . . #
# # # # # # # # # . . . . # . # #
# . . . . . . . . . # . . . . . #
# . # # # . # . # . # . # . # . #
# . # . # . # . # . # . # . # . #
# . # . # . # . # . . # # . # # #
# . # . . . # . # # . # . . . . #
# # . . # # # . . # . # . . # # #
# . . # . . . . # # . # # . . . #
# # # # . # . . . # . # . . # # #
# . . . . # . # . # . # # . # . #
# . # # . # . # . # . . # . . . #
# # # # # # # # # # # # # # # S #</pre>
<p>Ahi podemos ver el mapa de ejemplo donde los &#8220;#&#8221; representan las paredes, los &#8220;.&#8221; los caminos, la &#8220;T&#8221; es la pelota y la &#8220;S&#8221; es la salida. Puedes modificar paredes la posición de la salida o la pelota o hacer laberintos mucho más grandes.</p>
<p><a href="http://razonartificial.com/wp-content/uploads/2010/01/laberinto1.png"><img class="aligncenter size-full wp-image-62" title="laberinto" src="http://razonartificial.com/wp-content/uploads/2010/01/laberinto1.png" alt="" width="453" height="379" /></a></p>
<p>La salida gráfica de la aplicación la he hecho con GASP, los gráficos se encuentran en la carpeta del programa y se pueden modificar.</p>
<ul>
<li><a href="http://razonartificial.com/wp-content/uploads/2010/01/buscador.zip">Descargar Buscador de Caminos</a></li>
</ul>
<h2  class="related_post_title">Entradas relacionadas</h2><ul class="related_post"><li><a href="http://razonartificial.com/2010/01/el-salto-del-caballo-backtracking/" title="El salto del caballo, backtracking">El salto del caballo, backtracking</a></li><li><a href="http://razonartificial.com/2010/08/arboles-e-inteligencia-artificial/" title="Arboles e inteligencia Artificial">Arboles e inteligencia Artificial</a></li><li><a href="http://razonartificial.com/2010/08/algoritmo-minimax-un-jugador-incansable/" title="Algoritmo Minimax, un jugador incansable">Algoritmo Minimax, un jugador incansable</a></li><li><a href="http://razonartificial.com/2010/08/muestra-del-engine-de-pyia/" title="Muestra del Engine de PyIA">Muestra del Engine de PyIA</a></li><li><a href="http://razonartificial.com/2010/08/pyia-competicion-de-inteligencia-artificial-en-python/" title="PyIA &#8211; Competición de Inteligencia Artificial en Python">PyIA &#8211; Competición de Inteligencia Artificial en Python</a></li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/tRpFEFXGnPrRFZbBQd5kYpUM0OA/0/da"><img src="http://feedads.g.doubleclick.net/~a/tRpFEFXGnPrRFZbBQd5kYpUM0OA/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/tRpFEFXGnPrRFZbBQd5kYpUM0OA/1/da"><img src="http://feedads.g.doubleclick.net/~a/tRpFEFXGnPrRFZbBQd5kYpUM0OA/1/di" border="0" ismap="true"></img></a></p><img src="http://feeds.feedburner.com/~r/RazonArtificial/~4/RtwcHwv6_N8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://razonartificial.com/2010/01/buscador-de-caminos-con-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>El juego de la vida en Python</title>
		<link>http://razonartificial.com/2010/01/el-juego-de-la-vida-en-python/</link>
		<comments>http://razonartificial.com/2010/01/el-juego-de-la-vida-en-python/#comments</comments>
		<pubDate>Sun, 17 Jan 2010 15:26:40 +0000</pubDate>
		<dc:creator>adrigm</dc:creator>
				<category><![CDATA[Ejemplos]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[GASP]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Vida Artificial]]></category>

		<guid isPermaLink="false">http://razonartificial.com/?p=51</guid>
		<description><![CDATA[Aquí traigo una versión del juego de la vida en Python utilizando GASP, se trata de una aplicación gráfica en el que se pueden elegir dos tipos de configuraciones: Aleatoria. Donde se debe introducir el numero de filas y columnas del mapa y se rellenan de forma aleatoria. Cargar Mapa. Donde se debe indicar la [...]]]></description>
			<content:encoded><![CDATA[<p>Aquí traigo una versión del <a href="http://razonartificial.com/2010/01/el-juego-de-la-vida/">juego de la vida</a> en Python utilizando <a href="http://razonartificial.com/2010/01/gasp-graficos-faciles-en-python/">GASP</a>, se trata de una aplicación gráfica en el que se pueden elegir dos tipos de configuraciones:</p>
<ol>
<li>Aleatoria. Donde se debe introducir el numero de filas y columnas del mapa y se rellenan de forma aleatoria.</li>
<li>Cargar Mapa. Donde se debe indicar la ruta de un mapa en formato txt con la configuración inicial, se incluye un ejemplo de mapa con el juego.</li>
</ol>
<p><img class="aligncenter size-medium wp-image-52" title="jvida" src="http://razonartificial.com/wp-content/uploads/2010/01/jvida-300x237.png" alt="" width="300" height="237" /></p>
<p>El juego es muy mejorable y se recomienda no usar mapas de más de 900 casillas (30&#215;30), porque la API gráfica no es la mejor y va un poco mal. La configuración del juego se hace a través de consola, pero este se ejecuta en una ventana gráfica. Por defecto esta es de 640&#215;480, pero se puede cambiar muy facilmente en el programa.</p>
<p>El programa necesita el paquete python-gasp que podéis encontrar en las repositorios de la distribuciones basadas en Debian, para otros sistemas consultar la <a href="https://launchpad.net/gasp">página oficial</a>. El código después del salto.</p>
<ul>
<li><a href="http://razonartificial.com/wp-content/uploads/2010/01/JVida.zip">Descargar Juego de la Vida</a></li>
</ul>
<p><span id="more-51"></span></p>
<pre class="brush: python;">
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# ---------------------------------------------------------------------
# Programa: EL juego de la vida.
# Autor: Adrián Guerra Marrero (adrigm).
# Web: www.razonartificial.com
# Licencia: GNU/GPL
# ---------------------------------------------------------------------

# Módulos
from gasp import *
import time, os, random

# CONSTANTES
width = 640
height = 480

# Clases
# ---------------------------------------------------------------------

class Juego:
	def __init__(self, opcion=1, archivo=&quot;mapa.txt&quot;, fil=10, col=10):
		if opcion == 2:
			self.mapa = leerMapa(archivo)
		else:
			self.mapa = range(fil)
			for i in range(fil):
				self.mapa[i] = range(col)

			for f in range(fil):
				for c in range(col):
					self.mapa[f][c] = random.randint(0, 1)

		self.filas = len(self.mapa)
		self.columnas = len(self.mapa[0])

	def __str__(self):
		mapa = &quot;&quot;
		for f in range(self.filas):
			for c in range(self.columnas):
				if self.mapa[f][c] == 0:
					mapa += &quot;. &quot;
				if self.mapa[f][c] == 1:
					mapa += &quot;* &quot;
			mapa += &quot;\n&quot;
		return mapa

	def analizarVecinos(self, fil, col):
		vecinos = 0
		if fil-1 &gt;= 0 and col-1 &gt;= 0:
			if self.mapa[fil-1][col-1] == 1:
				vecinos += 1
		if fil-1 &gt;= 0:
			if self.mapa[fil-1][col] == 1:
				vecinos += 1
		if fil-1 &gt;= 0 and col+1 &lt;= self.columnas-1:
			if self.mapa[fil-1][col+1] == 1:
				vecinos += 1
		if col-1 &gt;= 0:
			if self.mapa[fil][col-1] == 1:
				vecinos += 1
		if col+1 &lt;= self.columnas-1:
			if self.mapa[fil][col+1] == 1:
				vecinos += 1
		if fil+1 &lt;= self.filas-1 and col-1 &gt;= 0:
			if self.mapa[fil+1][col-1] == 1:
				vecinos += 1
		if fil+1 &lt;= self.filas-1:
			if self.mapa[fil+1][col] == 1:
				vecinos += 1
		if fil+1 &lt;= self.filas-1 and col+1 &lt;= self.columnas-1:
			if self.mapa[fil+1][col+1] == 1:
				vecinos += 1
		return vecinos

	def ciclo(self):
		nueva_conf = []
		for f in range(self.filas):
			columna = []
			for c in range(self.columnas):
				vecinos = self.analizarVecinos(f, c)
				if self.mapa[f][c] == 0:
					if vecinos == 3:
						columna.append(1)
					else:
						columna.append(0)
				if self.mapa[f][c] == 1:
					if vecinos == 2 or vecinos == 3:
						columna.append(1)
					else:
						columna.append(0)
			nueva_conf.append(columna)

		self.mapa = nueva_conf

	def dibujar(self):
		dist_lv = width/self.columnas
		dist_lh = height/self.filas
		for i in range(self.columnas):
			Line((dist_lv*i, 0), (dist_lv*i, height))
		for n in range(self.filas):
			Line((0, dist_lh*n), (width, dist_lh*n))

		for f in range(self.filas):
			y = height-dist_lh - ((dist_lh)*f)+(dist_lh/2)
			for c in range(self.columnas):
				x = ((dist_lv)*c)+(dist_lv/2)
				if self.mapa[f][c] == 1:
					Circle((x, y), ((dist_lh/2)-((dist_lh/2)*0.2)))

# ---------------------------------------------------------------------

# Funciones
# ---------------------------------------------------------------------

# Quita el ultimo caracter de una lista.
def quitarUltimo(lista):
	for i in range(len(lista)):
		lista[i] = lista[i][:-1]
	return lista

# Covierte una cadena en una lista.
def listarCadena(cadena):
	lista = []
	for i in range(len(cadena)):
		if cadena[i] == &quot;.&quot;:
			lista.append(0)
		if cadena[i] == &quot;*&quot;:
			lista.append(1)
	return lista

# Lee un archivo de texto y lo convierte en una lista.
d