<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ya he aprendido otra cosa :D</title>
	<atom:link href="http://www.aureoares.es/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.aureoares.es</link>
	<description>por Áureo Ares</description>
	<lastBuildDate>Thu, 17 Jul 2014 15:48:10 +0000</lastBuildDate>
	<language>es-ES</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<item>
		<title>Meta información en WordPress: título y descripción.</title>
		<link>http://www.aureoares.es/titulo-y-descripcion-en-wordpress/</link>
		<comments>http://www.aureoares.es/titulo-y-descripcion-en-wordpress/#comments</comments>
		<pubDate>Wed, 16 Jul 2014 09:43:38 +0000</pubDate>
		<dc:creator><![CDATA[Áureo Ares]]></dc:creator>
				<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://www.aureoares.es/?p=151</guid>
		<description><![CDATA[Título y meta-descripción personalizados en Wordpress. Aprende a modificar directamente el tema que uses para añadir funcionalidades sin sobrecargar de plugins el blog.]]></description>
				<content:encoded><![CDATA[<p>La sobrecarga de plugins termina siendo un problema en muchos sitios web basados en cualquier gestor de contenidos, no sólo en WordPress. Es común recurrir a ellos para realizar tareas que en realidad no necesitan un plugin.</p>
<p>Por eso quería traer algunos ejemplos de cómo conseguir lo que necesitamos realizando algunas modificaciones directamente en nuestra plantilla de WordPress.<span id="more-151"></span></p>
<p>Uno de los ámbitos que más suelen preocupar y que más tiende a hacer un uso intensivo de plugins es el SEO. Aún no sé si escribiré artículos más avanzados, pero de momento empezaremos por lo básico: título y descripción de las páginas.</p>
<h2>¿Qué necesitamos?</h2>
<p>Esto no va a ser una clase de SEO, de modo que supondremos que ya sabemos cómo escribir y escoger los textos para las distintas partes de cada página.</p>
<p>Lo que necesitamos es que cada página pueda mostrar un título y una descripción diferentes. Por ejemplo, hay montones de plantillas que utilizan la misma descripción para todas las páginas del blog (la descripción del blog, configurada en Ajustes &gt; Generales) o directamente no ponen descripción en ninguna página salvo la principal.</p>
<h2>¿Cómo lo hacemos?</h2>
<p>Con el título lo tenemos fácil, sobre todo porque seguramente la plantilla en cuestión ya lo esté haciendo bien (o más o menos bien). Mi método suele ser el siguiente:</p><pre class="crayon-plain-tag">&lt;title&gt;
&lt;?php
	if(is_home() or is_front_page())
	{
		$site_name = get_bloginfo('name', 'display');
		echo $site_name;
	}
	else
	{
		wp_title('', True, 'right');
	}
?&gt;
&lt;/title&gt;</pre><p>A veces puede ser suficiente con utilizar la función <a title="Función wp_title en la documentación oficial de WordPress" href="http://codex.wordpress.org/Function_Reference/wp_title" target="_blank">wp_title</a>, pero en muchos casos aparecerá un título en blanco en la página principal.</p>
<p>Otro modo de hacer lo mismo pero más &#8220;elegante&#8221; sería añadir un filtro a wp_title:</p><pre class="crayon-plain-tag">function filter_wp_title($title)
{
	if(is_home() or is_front_page())
	{
		$site_name = get_bloginfo('name', 'display');
		return $site_name;
	}
	return $title;
}
add_filter('wp_title', 'filter_wp_title');</pre><p>Pero personalmente prefiero dejar el fichero functions.php lo más limpio posible. Manías.</p>
<p>El resultado de la función wp_title es predecible (títulos de artículos, nombres de categorías&#8230;) y suele ser suficiente. En caso de querer algo muy sofisticado y completamente diferente a lo habitual, con las herramientas anteriores se puede hacer casi de todo.</p>
<p>Con la descripción tendremos que ser un poco más creativos. Mi opción favorita para esto son los &#8220;campos personalizados&#8221; que WordPress permite añadir tanto a los artículos como a las páginas.</p>
<p>Creo un campo personalizado llamado &#8220;meta_description&#8221; y lo añado en cada nueva página. Para los artículos, el propio WordPress permite añadir un &#8220;extracto&#8221;, que por alguna razón no se suele utilizar pero puede ser muy útil. WordPress también permite dar descripciones a las categorías.</p>
<p>De modo que para la página principal utilizo la descripción del blog, para las categorías su propia descripción, para los artículos el extracto y para las páginas el campo personalizado &#8220;meta_description&#8221;.</p>
<p>Todo esto traducido a código sería algo así:</p><pre class="crayon-plain-tag">$meta_description = '';
	if(is_home() or is_front_page())
	{
		$meta_description = get_bloginfo('description', 'display');
	}
	elseif(is_single() or is_page())
	{
		if(has_excerpt()) $meta_description = get_the_excerpt();
		else $meta_description = get_post_meta(get_the_ID(), 'meta_description', True);
	}
	elseif(is_category())
	{
		$meta_description = category_description();
	}
	if($meta_description)
	{ 
		$meta_description = strip_tags($meta_description);
		echo '&lt;meta name="description" content="'.$meta_description.'" /&gt;'; 
	}</pre><p>En los artículos sin extracto se intentará utilizar el campo personalizado igual que en las páginas.</p>
<h2>¿Y las keywords?</h2>
<p>Me sorprende que a estas alturas aún se siga hablando de las &#8220;meta keywords&#8221; junto con el título y descripción. <strong>Simplemente no deberían usarse, al menos no como antes.</strong></p>
<p><a title="Artículo oficial de Google sobre la &quot;meta keywords&quot;." href="http://googlewebmastercentral.blogspot.com.es/2009/09/google-does-not-use-keywords-meta-tag.html" target="_blank">Este artículo de Google</a> (de Septiembre de 2009) deja bastante claro que en el mejor de los casos no sirven para nada y en el peor de los casos podría ser perjudicial. Desde el punto e vista de Google, claro.</p>
<p>Hasta la fecha no hay señales de que esto haya cambiado o vaya a cambiar, y personalmente no creo que otros buscadores den algún tipo de valor positivo a esta meta-información.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aureoares.es/titulo-y-descripcion-en-wordpress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cómo escalar el contenido de un &#8220;canvas&#8221; en HTML5 sobre la marcha.</title>
		<link>http://www.aureoares.es/escalar-canvas-html5/</link>
		<comments>http://www.aureoares.es/escalar-canvas-html5/#comments</comments>
		<pubDate>Thu, 26 Jun 2014 16:31:33 +0000</pubDate>
		<dc:creator><![CDATA[Áureo Ares]]></dc:creator>
				<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://www.aureoares.es/?p=117</guid>
		<description><![CDATA[Ejemplo de cómo podemos escalar los elementos de un Canvas en HTML5 según va cambiando el dibujo o el tamaño de la pantalla. Mantenemos el tamaño del dibujo adaptado al lienzo.]]></description>
				<content:encoded><![CDATA[<p>Cuando trabajas con canvas hay ocasiones en las que no tienes ni idea del tamaño que va a tener el &#8220;dibujo&#8221;.</p>
<p>Digamos que el contenido de tu canvas va cambiando. Si se hace más grande que el canvas pintarás fuera. Si se hace demasiado pequeño se verá ridículo con todo el espacio disponible alrededor. También puede ocurrir que en lugar de variar el tamaño del dibujo, sea el tamaño del canvas lo que cambie.<span id="more-117"></span></p>
<p>Hay técnicas básicas para escalar el contenido del canvas mediante CSS, pero sólo son útiles en casos muy concretos y sencillos.</p>
<p>Yo utilizo un método bastante sencillo pero que funciona muy bien:</p>
<ol>
<li>Coloco los elementos dentro del canvas con el tamaño que me convenga.</li>
<li>Mantengo una lista de &#8220;puntos clave&#8221; en el dibujo.</li>
<li>Calculo la escala óptima para que todos los puntos clave quepan dentro del canvas manteniendo el dibujo lo más grande posible.</li>
<li>Aplico la escala al dibujo.</li>
<li>Recoloco el dibujo, pegándolo a la esquina superior izquierda.</li>
<li>Cada vez que haya un cambio en el dibujo (o en el tamaño del canvas) habrá que recalcular la escala y mover de nuevo el dibujo a la esquina si es necesario.</li>
</ol>
<p>Se este modo el dibujo se ve siempre lo más grande posible.</p>
<p>Es importante tener claro que todos los elementos tendrán una doble representación. Por una parte tendremos las coordenadas y medidas &#8220;reales&#8221; que manejaremos internamente y por otra parte las que utilicemos para pintarlos al aplicar la escala.</p>
<h2>¿Por qué dos medidas diferentes?</h2>
<p>Supongamos que tenemos una línea que representa una pared que mide 4 metros. Por comodidad decidimos que vamos a tomar como referencia 1px = 1cm, de modo que tenemos una línea de 400px.</p>
<p>Si va recta desde la esquina superior izquierda hacia la derecha, la línea comenzará en las coordenadas (0/0) y terminará en (400/0). Internamente es mejor guardar las líneas como puntos así que nos guardamos esas dos coordenadas como representación de nuestra &#8220;pared&#8221;.</p>
<p>Pero el canvas que tenemos para dibujar es muy pequeño, digamos que de 200 x 200 píxeles. La escala a aplicar se ve claramente que es 0,5. Sin embargo, sólo aplicamos la escala en el momento de dibujar la línea, sin modificar las coordenadas reales del elemento.</p>
<p>De este modo conservamos los valores reales para otros usos y al mismo tiempo evitamos arrastrar pequeños errores de redondeo, ya que la escala se aplica siempre sobre el valor original en lugar de sobre valores que ya se han escalado anteriormente.</p>
<h2>Los puntos clave.</h2>
<p>Lo que suelo hacer es guardarme una lista con la posición de cada uno de los puntos que definen los extremos de los objetos. Los dos extremos de una línea, los vértices de un polígono, las 4 esquinas de una imagen&#8230;</p>
<p>Normalmente estos puntos sirven también para otros propósitos. Pero si no los necesito para nada más, otra opción es guardar solamente los puntos más extremos del dibujo ya que son los que usaremos para decidir la escala. En este caso tendremos que estar seguros de mantener los puntos actualizados si los elementos se mueven.</p>
<h2>La escala.</h2>
<p>La función para calcular la escala dependerá de cómo desarrollemos la aplicación, pero en general es muy fácil.</p>
<p>Tenemos que localizar los &#8220;bordes&#8221; del dibujo, que vienen a ser los valores máximos y mínimos de las coordenadas X e Y. Son 4 valores que delimitan el dibujo y pueden pertenecer a 4 puntos diferentes (el valor mínimo de X y de Y por ejemplo, no tienen por qué ser del mismo punto):</p>
<p><a href="http://www.aureoares.es/wp-content/uploads/canvas_max_min_coords.png"><img class="aligncenter size-full wp-image-121" src="http://www.aureoares.es/wp-content/uploads/canvas_max_min_coords.png" alt="Ejemplo de puntos que definen los bordes de un dibujo." width="350" height="255" /></a></p>
<p>Con los 4 valores encontrados, tendremos dos posibles escalas que calcular. El ancho del dibujo viene marcado por la distancia entre los valores mínimo y máximo de X. La relación entre el ancho del canvas y del dibujo nos da la escala óptima para el eje X, y lo mismo sucede con el alto para el eje Y.</p>
<p>Si no es necesario mantener la relación de aspecto en el dibujo podemos directamente aplicar la escala óptima a cada eje, de lo contrario nos quedaremos con la menor y aplicaremos la misma a los dos.</p>
<p>Por último sólo tenemos que mover todo el contenido del canvas para pegarlo a la esquina superior izquierda. Para ello calculamos la distancia entre la esquina superior izquierda (0/0 si no estamos dejando ningún margen) para ambos ejes y la restamos a la posición de todos los elementos.</p>
<p>En el caso de aplicar la misma escala a ambos ejes seguramente nos sobre espacio a un lado del canvas, así que podemos optar por centrar el dibujo en lugar de moverlo completamente a la esquina.</p>
<h2>El código:</h2>
<p>Podéis ver un ejemplo en el siguiente enlace: <a title="Ejemplo de ajuste de escala en Canvas." href="http://www.aureoares.es/demos/canvas_resize/index.html" target="_blank">Ejemplo de escala en canvas</a>.</p>
<p>Por comodidad está todo el código en la misma página, basta con ver el código fuente desde el navegador o guardarla y abrirla con un editor de texto.</p>

<!-- iframe plugin v.3.0 wordpress.org/plugins/iframe/ -->
<iframe src="http://www.aureoares.es/demos/canvas_resize/index.html" width="90%" height="500" scrolling="yes" class="iframe-class" frameborder="0"></iframe>

]]></content:encoded>
			<wfw:commentRss>http://www.aureoares.es/escalar-canvas-html5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Exportando el catálogo de Prestashop a Mercamania.</title>
		<link>http://www.aureoares.es/exportando-el-catalogo-de-prestashop-a-mercamania/</link>
		<comments>http://www.aureoares.es/exportando-el-catalogo-de-prestashop-a-mercamania/#comments</comments>
		<pubDate>Mon, 26 May 2014 15:03:54 +0000</pubDate>
		<dc:creator><![CDATA[Áureo Ares]]></dc:creator>
				<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://www.aureoares.es/?p=129</guid>
		<description><![CDATA[Módulo para Prestashop 1.5 que permite generar el fichero CSV de exportación para los catálogos de LeGuide, concretamente para la web de Mercamanía.]]></description>
				<content:encoded><![CDATA[<p>Los del grupo <a title="Web del grupo LeGuide (en inglés)" href="http://www.leguidegroup.com/" target="_blank">LeGuide</a> responden bastante bien en los servicios de pago, pero integrar tiendas con el servicio gratuito a partir de la información disponible en la web y el &#8220;manual&#8221; que ofrecen puede ser desesperante.<span id="more-129"></span></p>
<p>La interfaz para facilitar los datos de la empresa y la tienda es clara. El problema viene al generar el fichero CSV con los datos de los productos. Ni siquiera queda claro cómo se deben de llamar los campos y terminas a base de prueba y error, corrigiendo poco a poco las cosas que te dicen que están mal, en un castellano que se ve que no es su primer ni su segundo idioma. Al menos esa es mi experiencia con ellos.</p>
<p>Tras preparar un módulo de Prestashop (1.5, pero no creo que haya mucho problema en pasarlo a 1.6) he pensado en compartirlo por si alguien quiere usarlo o adaptarlo a sus necesidades.</p>
<p>Los campos exportados para cada producto son:</p>
<ul>
<li>Categoría: El nombre de la categoría principal del producto en la tienda.</li>
<li>Referencia interna: La referencia del producto en la tienda (no la del proveedor).</li>
<li>Título: El nombre del producto.</li>
<li>Descripción: La descripción corta del producto.</li>
<li>Precio: El precio del producto base, sin contar los atributos.</li>
<li>URL producto: La URL de la página del producto.</li>
<li>URL imagen: La URL de la imagen principal del producto.</li>
<li>Gastos de envío: Modificable en la configuración del módulo.</li>
<li>Disponibilidad: Todos los productos se marcan como disponibles ya que el módulo solo exporta los productos disponibles.</li>
<li>Plazo de entrega: Modificable en la configuración del módulo.</li>
<li>Garantía: Este campo es obligatorio que aparezca, pero lo dejamos siempre vacío.</li>
</ul>
<p>Es sencillito y se puede ampliar mucho, pero en mi caso es más que suficiente. Si alguien quiere usarlo es posible que necesite hacerle alguna modificación. Está probado con Mercamania, pero debería funcionar tal cual con el resto de servicios de LeGuide (Pikengo, choozen, dooyoo&#8230;).</p>
<p>Así es como se ve la pantalla de configuración:</p>
<p><a href="http://www.aureoares.es/wp-content/uploads/leguideexport.png"><img class="aligncenter size-full wp-image-133" src="http://www.aureoares.es/wp-content/uploads/leguideexport.png" alt="leguideexport" width="1425" height="756" /></a></p>
<p>Básicamente lo que hace es crear un CSV al vuelo al acceder a cualquiera de las URLs que aparecen al final, a partir de los parámetros configurados.</p>
<p>Está escrito siguiendo el estándar de codificación de <a title="Sitio oficial de módulos para Prestashop" href="http://addons.prestashop.com/" target="_blank">addons.prestashop.com</a> (que es diferente a mi estilo habitual) ya que hice el intento de publicarlo como si lo fuese a vender, para ver si pasaba el análisis técnico que hacen a los módulos (y lo pasó).</p>
<p>El módulo en cuestión lo podéis encontrar en <a title="Página del módulo en Google Code" href="https://code.google.com/p/prestashop-leguide-export/" target="_blank">Google Code</a>. Cualquier aportación es bienvenida.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aureoares.es/exportando-el-catalogo-de-prestashop-a-mercamania/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Seguir utilizando Windows XP sin soporte.</title>
		<link>http://www.aureoares.es/seguir-utilizando-windows-xp-sin-soporte/</link>
		<comments>http://www.aureoares.es/seguir-utilizando-windows-xp-sin-soporte/#comments</comments>
		<pubDate>Wed, 23 Apr 2014 08:13:38 +0000</pubDate>
		<dc:creator><![CDATA[Áureo Ares]]></dc:creator>
				<category><![CDATA[Sin categoría]]></category>

		<guid isPermaLink="false">http://www.aureoares.es/?p=125</guid>
		<description><![CDATA[Consejos para continuar utilizando Windows XP tras la finalización del soporte por parte de Microsoft, sin que tu equipo se convierta en una bomba de relojería.]]></description>
				<content:encoded><![CDATA[<p>Hace dos semanas <a title="Anuncio de cese del soporte técnico de Windows XP" href="http://windows.microsoft.com/es-es/windows/end-support-help" target="_blank">finalizó el soporte de Windows XP</a> y Microsoft nos sugiere dos alternativas: actualizar a Windows 8 o comprar un equipo nuevo y utilizar Windows 8.</p>
<p>Personalmente he oído todo tipo de comentarios, desde &#8220;total, yo no lo actualizaba&#8230;&#8221; hasta &#8220;¿y de dónde saco un crack para el 8?&#8221;. Evidentemente, una grandísima cantidad de gente continuará utilizando XP aunque a otros nos parezca una locura.<span id="more-125"></span></p>
<p>Si sigues utilizando XP o tienes un padre/amigo/vecino que no quiere o no puede cambiar, lo más recomendable reforzar la seguridad al máximo nivel de paranoia. Nuevas brechas de seguridad no serán parcheadas y es de esperar que un montón de malas personas estén ahí afuera frotándose las manos. De hecho, si somos muy paranoicos, podemos pensar que ya puede haber vulnerabilidades descubiertas hace meses que estén a la espera de comenzar a explotarse.</p>
<h2>¿Internet? No, gracias.</h2>
<p>El mejor modo de evitar casi cualquier amenaza es anular la conexión del equipo de Internet, pero en la mayoría de los casos no será una opción.</p>
<p>Entonces lo primero es utilizar un navegador que no sea Internet Explorer, ya que IE 10 y 11 no están disponibles para XP. Las opciones claras son Chrome y Firefox, y si la prioridad es la seguridad yo me quedaría con Chrome. Ambos tienen una extensión muy recomendable llamada <a title="HTTPS Everywhere" href="https://www.eff.org/https-everywhere" target="_blank">HTTPS Everywhere</a> para forzar el uso de HTTPS.</p>
<p>Luego viene un clásico que en la realidad no he visto hacer a casi nadie: utilizar cuentas de usuario limitadas. Utiliza una cuenta de administrador cuando tengas que instalar algo o hacer alguna configuración del sistema, pero ya está. Todo el resto del tiempo puedes y debes utilizar una cuenta limitada. Y todas las cuentas deben tener una contraseña, por difícil que resulte convencer a algunos&#8230;</p>
<h2>El software actualizado siempre.</h2>
<p>Lo siguiente que yo haría es asegurarme de que no queda nada instalado que no sea imprescindible y que todo lo instalado esté siempre actualizado (especialmente todo lo relacionado con Adobe y Java, y si puedes vivir con ellos mejor desinstálalos también). Una interesante herramienta puede ser <a title="Personal Software Inspector" href="http://secunia.com/vulnerability_scanning/personal/" target="_blank">PSI</a>.</p>
<p>Lo mismo ocurre con las extensiones del navegador, cuantas menos mejor y de vez en cuando hay que comprobar que no se queden desactualizadas.</p>
<p>También hay que tener en cuenta que no sólo el sistema operativo deja de tener soporte, sino programas como Microsoft Office 2003 y muchos otros que se pueden sumar. Lo mejor es buscar alternativas para cualquier programa que deje de tener soporte para XP.</p>
<h2>El software de seguridad.</h2>
<p>Mis elecciones personales son <a title="Antivirus AVG" href="http://www.avg.com/es-es/avf_download_2014_ppc" target="_blank">AVG</a> como antivirus, <a title="Cortafuegos Comodo" href="http://personalfirewall.comodo.com/" target="_blank">Comodo</a> como Cortafuegos y <a title="Malwarebytes" href="http://es.malwarebytes.org/" target="_blank">Malwarebytes</a> de refuerzo. Pero hay muchas opciones y cada uno tendrá sus preferencias.</p>
<p>En cualquier caso siempre vas a estar menos seguro por el simple hecho de utilizar un sistema operativo sin soporte.</p>
<h2>Resumiendo.</h2>
<p>En general, todo se resume a los consejos de siempre. No hay nada especial que puedas hacer para mantener un Windows XP con cierto nivel de seguridad, más que lo habitual. En mi opinión casi ninguna empresa que necesite tener conexión a Internet en los equipos puede permitirse el riesgo de mantenerlos con XP.</p>
<p>Operaciones sensibles como utilizar la web del banco o realizar compras online, sería mejor realizarlas en otro equipo que tenga un sistema actual. Por lo demás, supongo que ya se verá cómo de factible es seguir utilizando Windows XP a largo plazo. Yo aún me encuentro con Windows 98 más a menudo de lo que me gustaría, de modo que quién sabe&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aureoares.es/seguir-utilizando-windows-xp-sin-soporte/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Filtros Bloom escalables.</title>
		<link>http://www.aureoares.es/filtros-bloom-escalables/</link>
		<comments>http://www.aureoares.es/filtros-bloom-escalables/#comments</comments>
		<pubDate>Mon, 07 Apr 2014 18:51:32 +0000</pubDate>
		<dc:creator><![CDATA[Áureo Ares]]></dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Web scraping]]></category>

		<guid isPermaLink="false">http://www.aureoares.es/?p=90</guid>
		<description><![CDATA[Cómo utilizar filtros Bloom escalables con Python. Funcionamiento y ejemplo de código.]]></description>
				<content:encoded><![CDATA[<p>Hace dos semanas publiqué un <a title="Filtros Bloom en web scraping." href="http://www.aureoares.es/filtros-bloom-en-web-scraping/">ejemplo de filtro Bloom básico</a>. En mis aventuras con web scraping el que realmente uso es una versión escalable ya que suele ser muy difícil estimar el número máximo de enlaces que voy a necesitar almacenar.</p>
<p>No existe (que yo sepa) un modo de aumentar el tamaño del array de bits de un filtro Bloom una vez que ya se han empezado a añadir elementos. El modo de implementar un filtro escalable no es ni más ni menos que utilizar más de un filtro a la vez.<span id="more-90"></span></p>
<p>Para ello, cada vez que un filtro se llena se crea uno nuevo de mayor capacidad. Los nuevos elementos se van añadiendo al último filtro creado y a la hora de buscar un elemento se busca en todos uno por uno.</p>
<p>La base del filtro escalable es por tanto muy sencilla. La mayor complicación sería escoger el modo de escalar la capacidad de los filtros, es decir, cómo de grande debe ser el nuevo en comparación con el anterior. En su momento me vino a la cabeza la posibilidad de que todos tengan el mismo tamaño e incluso de que fuesen cada vez más pequeños, pero hasta la fecha no se me ha ocurrido ningún extraño caso en el que pueda resultar útil.</p>
<p>Lo normal es utilizar una función lineal o exponencial. Yo he optado por permitir ambas ya que no era ningún esfuerzo pero en la práctica siempre me ha venido mejor la exponencial. Los cálculos son muy sencillos:</p><pre class="crayon-plain-tag"># initial_capacity = capacidad del primer filtro
# scale_factor = factor de aumento
# filters = array de filtros, len(filters) es el n&uacute;mero de filtros que ya haya
# Funci&oacute;n lineal:
capacity = int(initial_capacity * (scale_factor * len(filters)))
# Funci&oacute;n exponencial:
capacity = int(initial_capacity * (scale_factor ** len(filters)))</pre><p></p>
<p>&nbsp;</p>
<p>Añadir y buscar elementos también es muy sencillo:</p><pre class="crayon-plain-tag">def add(element):
    if filters[-1].is_full():
        # En el ejemplo del art&iacute;culo anterior, el filtro se creaba pasando como par&aacute;metros la capacidad y el margen de error.
        filters.append(BloomFilter(calc_next_capacity(), error_rate))
    filters[-1].add(element)
#
def lookup(string):
    for f in reversed(filters):
        if f.lookup(string): return True
    return False</pre><p>Lo único destacable es que al buscar es más eficiente recorrer los filtros en orden inverso (del último al primero), ya que de media se tardará menos en encontrar el elemento. Aunque en caso de no encontrarse la búsqueda tardará lo mismo se haga en un sentido u otro.</p>
<p>El código completo comentado se puede ver en <a title="Código completo en Google Code" href="https://code.google.com/p/python-scalable-bloom-filter/source/browse/" target="_blank">Google Code</a>.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aureoares.es/filtros-bloom-escalables/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hack: Facebook nos trae el nuevo PHP&#8230; ¿o no?</title>
		<link>http://www.aureoares.es/hack-facebook-y-php/</link>
		<comments>http://www.aureoares.es/hack-facebook-y-php/#comments</comments>
		<pubDate>Mon, 31 Mar 2014 11:21:01 +0000</pubDate>
		<dc:creator><![CDATA[Áureo Ares]]></dc:creator>
				<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[Programación]]></category>

		<guid isPermaLink="false">http://www.aureoares.es/?p=53</guid>
		<description><![CDATA[Primeras impresiones sobre Hack, el nuevo lenguaje de programación propuesto por Facebook y basado en PHP.]]></description>
				<content:encoded><![CDATA[<div id="attachment_69" style="width: 310px" class="wp-caption alignleft"><a href="http://www.aureoares.es/wp-content/uploads/hack_language.png"><img class="size-medium wp-image-69 " title="Logo Hack." src="http://www.aureoares.es/wp-content/uploads/hack_language-300x185.png" alt="hack_language" width="300" height="185" /></a><p class="wp-caption-text">Logotipo de Hack, el nuevo lenguaje de programación creado por Facebook y basado en PHP.</p></div>
<p>Hace poco que Facebook ha liberado su lenguaje de programación Hack, un nombre desafortunado para buscar en Google (prueba a buscar &#8220;hack code sample&#8221;).</p>
<p>Para echarle un vistazo rápido, el pequeño <a title="Tutorial de Hack en la web oficial" href="http://hacklang.org/tutorial/" target="_blank">tutorial (inglés)</a> que han preparado es un modo de empezar. Para empezar a probarlo más en serio se puede instalar una máquina virtual de <a title="Web oficial de Vagrant." href="http://www.vagrantup.com/" target="_blank">Vagrant (inglés)</a> con <a title="Web oficial de HHVM." href="http://hhvm.com/" target="_blank">HHVM (inglés)</a>. Googleando un poco se encuentran máquinas virtuales ya listas para utilizar.<span id="more-53"></span></p>
<p>En <a title="Documentación ofcicial de HHVM y Hack." href="http://docs.hhvm.com/" target="_blank">docs.hhvm.com</a> está toda la documentación sobre HHVM y Hack. De momento toda la documentación es en inglés, pero supongo que con el tiempo la irán traduciendo.</p>
<p>Ya hay montones de artículos por ahí enumerando las características y novedades del lenguaje (y se pueden leer en la web oficial o en el mismo índice del manual, no hace falta irse más lejos), así que me centraré en dos reflexiones que seguramente estaremos haciendo muchos ahora mismo:</p>
<h2>¿Vale la pena aprenderlo y utilizarlo?</h2>
<p>Si ya controlas PHP y comprendes los nuevos conceptos añadidos por Hack de trabajar con otros lenguajes, realmente hay poco que aprender salvo algunas reglas más de sintaxis. El resto es como en todos los lenguajes, usarlo lo suficiente como para aprender a &#8220;pensar en Hack&#8221; para sacarle el máximo partido.</p>
<p>Usarlo o no supongo que depende del punto de vista. Si quieres trabajar en Facebook, ya estás tardando :D. Creo que no se pierde nada por probarlo en una pequeña aplicación, aunque sólo sea por curiosidad. Pero para un proyecto serio me lo tendría que pensar.</p>
<p>Tiene desde luego un punto muy a favor: si Facebook lleva un tiempo utilizándolo, mal no debe funcionar. A esto se añaden todas las mejoras sobre PHP, que a simple vista parecen muy atractivas.</p>
<p>Sin embargo, hay que tener en cuenta un par de cosas. Supongamos que empiezas un proyecto nuevo y decides desarrollarlo con Hack. Supongamos también que dentro de dos años Facebook decide migrar a Python (por decir algo) y abandona el desarrollo de Hack y de HHVM. Como &#8220;la comunidad&#8221; no retome el proyecto y además lo haga bien (que puede pasar) vas a tener un problema.</p>
<p>También hay que tener en cuenta que HHVM y Hack están creados por Facebook para satisfacer sus necesidades específicas. Estas necesidades pueden coincidir con las tuyas o no.</p>
<h2>¿Hack va a sustituir a PHP?</h2>
<p>Pues no lo creo, al menos en mucho tiempo.</p>
<p>Supongamos por un momento que Hack es &#8220;superior&#8221; a PHP en todos los aspectos. Aunque fuese así, es muy difícil que los grandes frameworks y CMS se conviertan y mantengan dos versiones del software (Hack y PHP).</p>
<p>Por otra parte, el grueso de la comunidad de PHP está demasiado acostumbrado a buscar en Google cómo hacer X cosa en PHP y encontrar 40 implementaciones donde elegir. Por mucho que se pueda hablar de las bondades de PHP, su mejor carta es la enorme cantidad de código que ya hay escrito.</p>
<p>También es posible que con el tiempo PHP vaya adoptando características de Hack. Seguramente incluyendo el tipado gradual (la característica estrella de Hack) ya disuadiría a la mayoría de desarrolladores de &#8220;pasarse&#8221; a Hack, aunque no será lo que se dice una tarea fácil.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aureoares.es/hack-facebook-y-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Filtros Bloom en web scraping.</title>
		<link>http://www.aureoares.es/filtros-bloom-en-web-scraping/</link>
		<comments>http://www.aureoares.es/filtros-bloom-en-web-scraping/#comments</comments>
		<pubDate>Mon, 24 Mar 2014 12:37:32 +0000</pubDate>
		<dc:creator><![CDATA[Áureo Ares]]></dc:creator>
				<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Web scraping]]></category>

		<guid isPermaLink="false">http://www.aureoares.es/?p=24</guid>
		<description><![CDATA[Cómo utilizar filtros Bloom el Python, orientado al web scraping. Funcionamiento y ejemplo de código.]]></description>
				<content:encoded><![CDATA[<p>En mis aventuras con <a title="Definición de web scraping en Wikipedia" href="http://es.wikipedia.org/wiki/Web_scraping" target="_blank">web scraping</a> me encontré con un problema muy común al detectar automáticamente las URLs:</p>
<p>Cuando sabes lo que buscas es muy fácil fabricar un listado de URLs que necesitas revisar. Puede incluso ser una sola URL. Sin embargo, cuando necesitas ir detectando sobre la marcha nuevas URLs tienes que guardar un registro de las que ya has visitado. De lo contrario te encontrarás visitando las mismas páginas enlazadas entre sí una y otra vez hasta el fin de los tiempos.<span id="more-24"></span></p>
<p>Si sabemos que serán pocas las URLs a visitar, esto no es un gran problema. Simplemente nos guardamos una lista de las que vamos visitando y nos aseguramos de no repetir. El problema está cuando nos enfrentamos a sitios web muy grandes de los que necesitamos revisar una gran cantidad de páginas. Entonces eso de tener la lista de URLs en memoria se convierte rápidamente en una mala idea.</p>
<p>En estos casos, si las URLs en sí son relevantes (es decir, si cada URL es un dato que necesitas guardar por alguna otra razón) seguramente necesites una base de datos. Pero si lo único que necesitas saber es si ya has visitado antes una URL, los filtros Bloom son una opción increíblemente eficiente y rápida.</p>
<h2>Bonita historia, pero ¿qué es un filtro Bloom?</h2>
<p>No lo voy a explicar en profundidad ya que aparece muy bien explicado en la <a title="Definición de filtro Bloom en Wikipedia (en inglés)" href="http://en.wikipedia.org/wiki/Bloom_filter" target="_blank">Wikipedia (inglés)</a>, incluyendo muchas referencias interesantes al final del artículo. De modo que comentaré lo más importante.</p>
<p>Las características principales de los filtros Bloom son las siguientes:</p>
<ul>
<li>Tiene un cierto <strong>margen de error</strong> (falsos positivos), calculable y ajustable.</li>
<li>Al buscar un elemento, un resultado negativo significa que con toda seguridad <strong>no está</strong> en la lista.</li>
<li>Un resultado positivo significa que un elemento <strong>probablemente está</strong> en la lista (debido a la posibilidad de falsos positivos).</li>
<li><span style="line-height: 1.5em;">Requiere muy <strong>poco espacio</strong> en memoria y las consultas son muy rápidas.</span></li>
</ul>
<p>El funcionamiento es muy sencillo, para implementarlo necesitaremos:</p>
<ul>
<li>Encontrar una implementación ya realizada que nos guste (nos parezca apropiada) y podamos utilizar (licencia), en cuyo caso ya habremos terminado :D.</li>
</ul>
<p>o</p>
<ul>
<li>Una lista de elementos binarios (bit array).</li>
<li>Una o más funciones de hashing.</li>
</ul>
<p>En mi caso necesitaba una implementación en Python ya que es el lenguaje que suelo utilizar para las tareas de scraping. La implementación de <a title="Pybloom en GitHub" href="https://pypi.python.org/pypi/pybloom/1.0.2" target="_blank">pybloom</a> la verdad es que no me gustó nada y no encontré ninguna otra que me sirviese. De modo que opté por hacerme la mía.</p>
<p>La elección de la <strong>función de hashing</strong> es muy importante. El requisito indispensable es que sea <strong>uniforme</strong> (todos los posibles valores tienen la misma probabilidad de aparecer como resultado) y <strong>determinista</strong> (un mismo valor de entrada genera siempre el mismo valor de resultado). También es importante, aunque no imprescindible, que sea <strong>no criptográfica</strong>. Las funciones de hashing criptográficas están muy bien para otros usos, pero son más lentas (este es uno de los principales inconvenientes que le veo a pybloom). No soy ningún experto en hashing, pero leyendo un poco la que más me convence por el momento es <a title="MurmurHash3" href="https://pypi.python.org/pypi/mmh3" target="_blank">MurmurHash3</a>.</p>
<p>Resumiendo, para la implementación en Python utilicé lo siguiente:</p>
<p></p><pre class="crayon-plain-tag"># Requiere instalar previamente bitarray y mmh3 (murmurhash3)
# sudo pip install bitarray
# sudo pip install mmh3

from bitarray import bitarray
import mmh3
from math import log, ceil</pre><p></p>
<h2>Añadir un elemento al filtro:</h2>
<p>Para añadir un elemento realizaremos varios hashes del mismo. Se pueden utilizar distintas funciones de hashing o una sola función con diferentes semillas. Teniendo ya una función que me gusta y sin saber cuántos hashes diferentes voy a necesitar, me parece más lógico utilizar una sola con diferentes semillas:</p>
<p></p><pre class="crayon-plain-tag"># hash_count = n&uacute;mero de hashes a realizar.
# size = tama&ntilde;o del bitarray.
for seed in xrange(hash_count):
	position = mmh3.hash(element, seed) % size
	bit_array[position] = 1
element_count += 1</pre><p></p>
<p>Los hashes mmh3 son numéricos, de modo que se pueden ajustar al tamaño del bitarray calculando el &#8220;módulo&#8221; (resto de división) con el operador &#8220;%&#8221;. El resultado es la posición del bitarray que marcamos a 1.</p>
<h2>Buscar un elemento en el filtro:</h2>
<p>Buscar un elemento en el filtro es muy parecido, simplemente comprobamos las posiciones que corresponderían al elemento que estamos buscando.</p>
<p></p><pre class="crayon-plain-tag"># hash_count = n&uacute;mero de hashes a realizar.
# size = tama&ntilde;o del bitarray.
for seed in xrange(self.hash_count):
	position = mmh3.hash(element, seed) % self.size
	if self.bit_array[position] == 0:
		return False
return True</pre><p></p>
<div style="width: 659px" class="wp-caption aligncenter"><a href="http://www.aureoares.es/wp-content/uploads/bloom_filter.png"><img class="size-full " src="http://www.aureoares.es/wp-content/uploads/bloom_filter.png" alt="Ejemplo de filtro Bloom." width="649" height="233" /></a><p class="wp-caption-text">Imagen extraída de la Wikipedia, donde se muestra la idea básica de un filtro Bloom utilizando 3 hashes para cada elemento.</p></div>
<h2>El tamaño del bitarray y el número de hashes:</h2>
<p>La mayoría de implementaciones que encontré eran clases cuyo constructor recibía como parámetros el tamaño del bitarray y el número de hashes a utilizar. Aunque se puede utilizar de esta manera, en la práctica creo que es mucho más cómodo especificar lo que realmente me importa: el número de elementos que quiero guardar y el margen de error que estoy dispuesto a permitir.</p>
<p>Para esto es necesario calcular el tamaño del bitarray y el número de hashes necesarios para poder almacenar el número de elementos que queremos con un margen de error menor o igual al especificado. Las fórmulas y su explicación se pueden ver también en la Wikipedia, pero escritas en Python serían algo así:</p>
<p></p><pre class="crayon-plain-tag"># capacity = n&uacute;mero de elementos a guardar.
# error_rate = tasa de error, entre 0 (0%) y 1 (100%). Por ejemplo, 0.01 ser&iacute;a un 1%.
def calc_size():
	return int(ceil(- (float(capacity) * log(float(error_rate))) / (log(2))**2))

# Para calcular el n&uacute;mero de hashes tenemos que haber calculado primero el tama&ntilde;o del bitarray.
# size = tama&ntilde;o del bitarray.
def calc_hash_count():
	return int(ceil((float(size) / float(capacity)) * log(2)))</pre><p></p>
<p>Utilizo la función &#8220;ceil&#8221; para asegurarme de que se cumplen los requisitos (redondeando hacia arriba).</p>
<h2>Uniones e intersecciones:</h2>
<p>Algo que no he visto hasta la fecha en ninguna implementación de filtros Bloom, al menos en Python, son las operaciones de unión e intersección entre dos filtros (desde el punto de vista de teoría de conjuntos). Son increíblemente fáciles de implementar y en concreto la unión de filtros me ha resultado bastante útil.</p>
<p>Las intersecciones también pueden ser útiles, pero en mi caso (pocos o ningún elemento en común) los resultados no me han parecido lo bastante fiables.</p>
<p>Más abajo en el código final de la clase se puede ver la implementación de estas dos operaciones, pero es tan sencillo como realizar las operaciones a nivel de bit AND (&amp;) y OR (|) entre los dos bitarray.</p>
<h2>Mi implementación:</h2>
<p>Esta es la clase que me hice. No es la que uso actualmente ya que más tarde hice un filtro Bloom escalable, más avanzado, que detallaré en otro artículo ya que este me está quedando más grande de lo que esperaba.</p>
<p>Los filtros Bloom tienen una infinidad de utilidades. Cabe destacar que esta clase fue creada específicamente para cubrir mis necesidades, por lo que hay algunas decisiones de implementación (como permitir añadir más elementos aunque el filtro esté al máximo de capacidad o devolver un valor vacío si no se puede realizar una unión) que pueden no ser buenas en otros contextos.</p>
<p></p><pre class="crayon-plain-tag">#!/usr/bin/python
# -*- coding: utf-8 -*-
#

# Requires bitarray and mmh3 (murmurhash3)
# sudo pip install bitarray
# sudo pip install mmh3

from bitarray import bitarray
import mmh3
from math import log, ceil

class BloomFilter:

        def __init__(self, capacity, error_rate):
                if not capacity &gt; 0: raise ValueError(&quot;capacity must be &gt; 0&quot;)
                if not (0 &lt; error_rate &lt; 1): raise ValueError(&quot;error_rate must be between 0 and 1.&quot;)
capacity.
                self.capacity = capacity
                self.element_count = 0
                self.error_rate = error_rate
                self.size = self.calc_size()
                self.hash_count = self.calc_hash_count()
                self.bit_array = bitarray(self.size)
                self.bit_array.setall(0)

        def add(self, element):
                for seed in xrange(self.hash_count):
                        position = mmh3.hash(element, seed) % self.size
                        self.bit_array[position] = 1
                self.element_count += 1

        def lookup(self, element):
                for seed in xrange(self.hash_count):
                        position = mmh3.hash(element, seed) % self.size
                        if self.bit_array[position] == 0:
                                return False
                return True

        def union(self, b):
                if self.size != b.size: return None
                if self.hash_count != b.hash_count: return None
                result = BloomFilter(self.capacity, self.error_rate)
                result.bit_array = self.bit_array | b.bit_array
                result.element_count = self.element_count + b.element_count
                return result

        def intersection(self, b):
                if self.size != b.size: return None
                if self.hash_count != b.hash_count: return None
                result = BloomFilter(self.capacity, self.error_rate)
                result.bit_array = self.bit_array &amp; b.bit_array
                result.element_count = result.calc_element_count()
                return result

        def is_full(self):
                if self.element_count &lt; self.capacity: return False
                else: return True

        def calc_size(self):
                return int(ceil(- (float(self.capacity) * log(float(self.error_rate))) / (log(2))**2))

        def calc_hash_count(self):
                return int(ceil((float(self.size) / float(self.capacity)) * log(2)))

        def calc_error_rate(self, use_capacity = False):
                if use_capacity: n = float(self.capacity)
                else: n = float(self.element_count)
                return (1.0 - (1.0 - 1.0 / float(self.size)) ** (float(self.hash_count) * n)) ** float(self.hash_count)

        def calc_element_count(self):
                x = float(self.bit_array.count())
                return int(ceil(- (float(self.size) * log(1.0 - (x / float(self.size)))) / float(self.hash_count)))

        def __contains__(self, string):
                return self.lookup(string)</pre><p></p>
<p>El código completo comentado, incluyendo la versión escalable, está alojado en <a title="Código completo del filtro Bloom en Google Code" href="https://code.google.com/p/python-scalable-bloom-filter/source/browse/" target="_blank">Google Code</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aureoares.es/filtros-bloom-en-web-scraping/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Paige: Moviendo personajes.</title>
		<link>http://www.aureoares.es/paige-moviendo-personajes/</link>
		<comments>http://www.aureoares.es/paige-moviendo-personajes/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 17:22:00 +0000</pubDate>
		<dc:creator><![CDATA[Áureo Ares]]></dc:creator>
				<category><![CDATA[Paige]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Videojuegos]]></category>

		<guid isPermaLink="false">http://www.aureoares.es/?p=4</guid>
		<description><![CDATA[Estuve dándole vueltas al tema del control del personaje y poco a poco va tomando forma el módulo controller. Aún no me acaba de convencer del todo, pero ya irá mejorando. Se trata básicamente de crear un controlador para cada jugador y asignarle un personaje. Luego se van asignando eventos de pulsación de teclas (sólo [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Estuve dándole vueltas al tema del control del personaje y poco a poco va tomando forma el módulo controller. Aún no me acaba de convencer del todo, pero ya irá mejorando.</p>
<p>Se trata básicamente de crear un controlador para cada jugador y asignarle un personaje. Luego se van asignando eventos de pulsación de teclas (sólo teclas de momento) a funciones que afectarán a dicho personaje.<span id="more-4"></span></p>
<p>Sobre la gestión de colisiones&#8230;, menudas locuras he estado haciendo, hasta que me dí cuenta de que estaba cometiendo un error que parece ser (por lo que he leído luego en otros sitios) muy típico de novatos en esto de la programación de videojuegos: comprobar la colisión después de haber movido al personaje en lugar de hacerlo antes. En otras palabras, yo me preguntaba &#8220;¿ha chocado?&#8221; cuando lo que debería preguntarme es &#8220;¿chocaría?&#8221;. Cuando caí en la cuenta fue muy rápido de implementar.</p>
<p>Como siempre, me queda el consuelo de que no volveré a caer en un error de ese estilo.</p>
<p>Por último, he estado pensando en la cantidad de información que voy a tener que guardar sobre los mapas. Cuando empiece a pensar en un juego &#8220;de verdad&#8221; tendré que almacenar mucho más que el propio escenario: necesitaré los objetos y personajes no jugadores (NPC&#8217;s) que aparezcan en él, las coordenadas donde aparecerán, las acciones que realizarán&#8230; En fin, que toca pensar en bases de datos.</p>
<p>Antes creo que voy a tratar de implementar el &#8220;scrolling&#8221; de los mapas para poder mover a los personajes por mapas que excedan la resolución de la pantalla. Después comenzaré a pensar en el modelo de datos.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aureoares.es/paige-moviendo-personajes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Paige: Creando los personajes.</title>
		<link>http://www.aureoares.es/paige-creando-los-personajes/</link>
		<comments>http://www.aureoares.es/paige-creando-los-personajes/#comments</comments>
		<pubDate>Mon, 24 Jan 2011 20:57:00 +0000</pubDate>
		<dc:creator><![CDATA[Áureo Ares]]></dc:creator>
				<category><![CDATA[Paige]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Videojuegos]]></category>

		<guid isPermaLink="false">http://www.aureoares.es/?p=5</guid>
		<description><![CDATA[Ya tenemos escenario (o algo así). Toca poner personajes en él. Para ello he creado una clase base a partir de la cual crear las clases para los distintos tipos de personajes. Aclaro que cuando me refiero a personajes quiero decir cualquier personaje que aparezca en el juego, no sólo el del jugador. La principal [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Ya tenemos escenario (o algo así). Toca poner personajes en él. Para ello he creado una clase base a partir de la cual crear las clases para los distintos tipos de personajes. Aclaro que cuando me refiero a personajes quiero decir cualquier personaje que aparezca en el juego, no sólo el del jugador.</p>
<p>La principal diferencia entre los distintos tipos de personajes va a ser el movimiento. De momento voy a distinguir entre el movimiento tipo puzzle (el personaje se mueve tile por tile, no puede parar de moverse entre dos tiles) y el movimiento normal (el personaje se mueve &#8220;libremente&#8221;, sin la restricción anterior). He comenzado por implementar el movimiento normal ya que el movimiento tipo puzzle será un caso especial de éste.<span id="more-5"></span></p>
<p>El problema vendría al realizar juegos de plataformas, en los que el personaje sólo se mueve de izquierda a derecha y además &#8220;salta&#8221;. Éste caso lo voy a dejar para más adelante, tengo que estudiar cómo implementar el tema de la &#8220;gravedad&#8221;.</p>
<p>Por otra parte he creado una clase Player para el caso especial del jugador. He hecho algunas pruebas de movimiento, de animación e incluso de cambios de velocidad (para andar y correr, por ejemplo). Ya ayer subí los avances del <a href="http://code.google.com/p/paige/">proyecto</a>. Para la prueba uso las flechas del teclado para mover al personaje y la tecla Z para &#8220;correr&#8221;.</p>
<p>Lo siguiente que quiero hacer es buscar alguna manera un poco más elegante de implementar el control del personaje y comenzar con la gestión de colisiones.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aureoares.es/paige-creando-los-personajes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Paige: Creando el escenario.</title>
		<link>http://www.aureoares.es/paige-creando-el-escenario/</link>
		<comments>http://www.aureoares.es/paige-creando-el-escenario/#comments</comments>
		<pubDate>Wed, 19 Jan 2011 18:19:00 +0000</pubDate>
		<dc:creator><![CDATA[Áureo Ares]]></dc:creator>
				<category><![CDATA[Paige]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Proyectos]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Videojuegos]]></category>

		<guid isPermaLink="false">http://www.aureoares.es/?p=6</guid>
		<description><![CDATA[Todo juego necesita un escenario, por simple que sea. Como era de esperar, voy a utilizar escenarios en 2D. En principio he pensado en un escenario compuesto por una imagen de fondo y un mapa de tres capas basado en tiles. ¿Por qué tres capas? Pues porque las usaré para representar lo que está por [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Todo juego necesita un escenario, por simple que sea. Como era de esperar, voy a utilizar escenarios en 2D.</p>
<p>En principio he pensado en un escenario compuesto por una imagen de fondo y un mapa de tres capas basado en <a href="http://es.wikipedia.org/wiki/Tile">tiles</a>. ¿Por qué tres capas? Pues porque las usaré para representar lo que está por detrás de los personajes, lo que está al mismo nivel y lo que está por delante. Combinado con un fondo creo que se pueden crear mapas decentes para casi cualquier tipo de juego.</p>
<p>En realidad voy a utilizar una cuarta capa para las colisiones con el escenario, que no se dibujará en pantalla ya que servirá para saber por qué partes del escenario no se pueden mover los personajes. Al principio pensé en considerar que el personaje colisionaría con todo lo que estuviese en la capa intermedia (supuestamente a su mismo nivel), pero creo que va a ser útil tenerlo por separado.<span id="more-6"></span></p>
<p>Existen bastantes herramientas para generar mapas basados en tiles, como <a href="http://www.tilemapper.com/">Tile Mapper</a>, <a href="http://www.tilemap.co.uk/mappy.php">Mappy</a> o <a href="http://www.mapeditor.org/">Tiled</a>. Como no voy a meterme en mapas muy complejos y Tiled me ha gustado bastante, me quedo con él. En su <a href="http://sourceforge.net/apps/mediawiki/tiled/index.php?title=Examining_the_map_format">wiki</a> se explica el formato que utiliza y en <a href="http://razonartificial.com/2010/04/engine-iv-tiled-map-editor/">Razón Artificial</a> hay un buen ejemplo de cómo usarlo, entre otros artículos y tutoriales muy interesantes.</p>
<p>En cuanto al código, ya he subido la primera versión de las clases que gestionarán los mapas. Al proyecto le he llamado <a href="http://code.google.com/p/paige/">Paige</a> y cualquiera queda invitado a colaborar.</p>
<p>Comento brevemente su estructura:</p>
<ul>
<li>La clase Map es la que se encarga de cargar los mapas y dibujar en pantalla el fondo y las distintas capas.</li>
<li>La clase Tileset carga las imágenes de los tileset y las &#8220;trocea&#8221; para obtener la tabla de tiles individuales, además de dibujar tiles en la pantalla.</li>
<li>La clase Layer carga las capas del mapa y las dibuja en pantalla.</li>
</ul>
<p>También he subido unas imágenes y un mapa de prueba para ir viendo los resultados. De momento el mapa debe ser del mismo tamaño que la pantalla, más adelante trataré el tema del &#8220;scrolling&#8221;. El siguiente paso será el personaje.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.aureoares.es/paige-creando-el-escenario/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
