Una de las tareas más tediosas a las que me he tenido que enfrentar a la hora de desarrollar juegos es la generación y confección de las hojas de sprites. Un sprite en terminología de videojuegos es, generalmente, una pequeña imagen que contiene un fotograma de una animación de un personaje, o bien de un componente de interfaz de usuario, como un botón, un cursor, o lo que sea.
Imaginad la cantidad de ficheros que tenemos que gestionar cuando un simple movimiento de un personajes necesita 12 fotogramas o un botón de interfaz puede tener 3 o 4 estados, cada uno con su propia imágen. Por ello, por cuestiones de rendimiento, se agrupan todos los sprites en imágenes más grandes, llamadas hojas de sprites (spritesheets), con lo que reducimos drásticamente el número de ficheros a gestionar. Wizards War, por ejemplo, pasó de tener unos 90 sprites diferentes, a tener solamente unas 5 hojas, ni siquiera llenas a tope.
Pues bien, en este punto todo suena muy bien, siempre la teoría es bonita :)… La realidad es muy diferente: dibujo los sprites en ficheros de Photoshop divididos en múltiples capas, normalmente tengo capas de trabajo y capas finales que contienen un sprite plano, muchas veces utilizo el mismo fichero para muchos sprites, como es el caso del diseño de interfaces y menús del juego, pero otras utilizo ficheros independientes, como para el diseño de los personajes, donde cada uno tiene su propio fichero de trabajo.
Cuando tengo los sprites terminados a mi gusto, los voy copiando capa por capa, y colocándolos en un nuevo fichero de Photoshop, donde los organizo y confecciono la hoja de sprites. Suelo enmarcarlos en un simple cuadrado negro (a modo de bounding box) que localizo en una capa independiente, me sirven para cuidar que dos sprites no se solapen en el mismo area de la imagen. Una vez terminado este duro trabajo, queda todavía lo peor: ir tomando nota de las coordenadas que definen cada uno de esos bounding box, para luego, en el motor del juego, saber en qué lugar de la hoja se encuentra cada sprite.
Al principio, cuando tenía unas pocas decenas de sprites, realizar todo este trabajo casi no consumía tiempo, en 20 o 30 minutos actualizaba todas las hojas de sprite y tenía las coordenadas disponibles. Sin embargo, cuando los sprites empezaban a crecer, el tiempo se empezó a multiplicar exponelcialmente, ni que decir de la pesadez de ir repitiendo esta tarea tan sumamente pesada para cada sprite. Cuando tuve que invertir una jornada entera en hacer una actualización de las hojas de sprites, y aún así me faltó tiempo, me di cuenta que algo no marchaba bien. Tenía que buscar alguna forma de automatizar ésta tarea, porque el gasto de tiempo era tremendo.
Fue así cuando empecé a investigar por la web diferentes herramientas que hicieran ese trabajo. La que más me gustó fué Texture Packer, de Andreas Löw. Ésta útil herramienta acepta como entrada un conjunto de imágenes, y automáticamente las compacta en una sola hoja, grabando las coordenadas, optimizando el espacio y organizando todos nuestros sprites, o sea, automatizaba y mejoraba todo el trabajo que yo estaba haciendo de forma manual, o incluso artesanal. Lo que llegué a tardar casi una docena de horas, Texture Packer me lo podría hacer en pocos minutos y mejor. Podéis imaginaros la cara de imbécil que se me quedó tras descubrir y decidir utilizar la dichosa herramientita.
Pero ahora me encontraba con otro problema, mientras que yo tenía casi todos los sprites agrupados en los mismos ficheros de Photoshop, TexturePacker (y todas las herramientas que vi por el estilo) necesitaba tener las imágenes de cada sprite en su propio fichero. Ahora, o bien tenía que ir sprite por sprite copiándolos en ficheros aparte (más trabajo tedioso y aburrido) o bien me buscaba otra forma de automatizar el proceso, porque además, en mi flujo de trabajo me interesaba poder trabajar con diferentes sprites en el mismo fichero, mucho más cómodo, con lo que tendría que estar separándolos cada dos por tres a ficheros independientes.
Investigando un poco más, descubrí que la solución estaba en mi propio software, en Photoshop. Ésta maravillosa herramienta de edición gráfica dispone de una opción que permite exportar a ficheros cada una de las capas que tengamos en nuestra imagen (para quien no lo sepa, la opción se encuentra en File/Scriptting/Export layers to Files…). Pensé, todo resuelto, trabajo como he venido trabajando hasta ahora y cuando tenga todo listo, utilizo Photoshop para que me exporte todas las capas a imágenes independientes, selecciono las que son sprites finales, y se las paso a TexturePacker para que termine el resto del trabajo sucio.
Hago una primera prueba, con unos pocos sprites, y ¡perfecto!, funciona a las mil maravillas. Así que decido utilizarlo sobre mis ficheros de trabajo reales, en los que suelo tener más de 200 capas para organizar los diferentes sprites y partes de los mismos. Y ahí es cuando repito el proceso y… cuando llevaba 2 horas de trabajo, pensé que se había quedado bloqueado, pero tras verificarlo, no, Photoshop seguía generando imágenes, pero a un ritmo lento, lentísimo.
De nuevo tocaba echar mano de Google e investigar por ahí. Resulta que la opción de Photoshop que estaba usando era un script, que realizaba la tarea, y por lo que leí por diferentes foros, estaba pésimamente implementado, de forma que el tiempo que requería crecía exponencialmente con el número de capas que había en la imagen. Por ello, con unas pocas, iba rápido, pero a medida que incrementábamos el número de capas crecían los tiempos de forma brutal.
Lo que el script de photoshop hace es grabar el estado original de las capas, a continuación escoge una capa y oculta todas las demás, luego graba un fichero con la única capa que hay visible, así repetía el proceso para cada una de las capas, reestableciendo el estado original. Por eso, cuantas más capas, más son necesarias de ocultar, y más tiempo lleva la ejecución del script.
Nuevo problema, nueva investigación por la red pero con poco éxito. Lo único que conseguí encontrar, aparte de varios scripts que hacían otro tipo de cosas, fue la documentación de Adobe para programar scripts en Photoshop y toda su suite creativa. Un poco harto ya, de dar palos de ciego, y casi resignado a seguir con mi tedioso modelo de trabajo en el que invertía días enteros para cambiar las hojas de sprites, decidí gastar mi último granito de esperanza, e intentar aprender lo justo y necesario del sistema de scripting de photoshop para generar mi propio exportador. Y sorprendentemente, sin mucho esfuerzo, así fué como surgió el pequeño script que os adjunto en el enlace del final del artículo que podéis utilizar, mejorar o hacer lo que queráis con él. Solamente tenéis que copiarlo y desde Photoshop acceder a la opción File/Scriptting/Browse… buscar el fichero y ejecutarlo.
El script, es totalmente amateur y casero, no hace la infinidad de cosas que hace el script original de Adobe, la mitad de las cuales no sé ni para que son, ni ganas… pero tarda casi nada de tiempo en producir el mismo resultado. El truco está en que mi script no oculta capas, simplemente recorre las visibles una por una, las copia, abre un archivo nuevo donde las pega y las salva en un PNG con el mismo nombre que le dimos a la capa. Simple, sencillo y eficaz. Lo que con el script de Photoshop tardaba más de 2 horas, con mi script no tarda ni 3 minutos, y para lo que yo quiero hacer, me basta y me sobra.
Espero que a más de uno os sea de utilidad, y si conocéis más scripts de éste estilo os invito a que los comentéis para que el resto los conozcamos y podamos ahorrar ingentes cantidades de tiempo.
Enlace al proyecto: LayerExporter github link



eduardo
5 enero, 2012 at 04:50
gracias por compartir tu experiencia, la verdad yo estaba metido en el mismo lio que tu =D
PiterLouis
5 enero, 2012 at 09:25
De nada Eduardo, espero que el script te sea de utilidad, está diseñado para la CS3 de Adobe, no sé si funcionará en versiones más recientes.
Cesar
28 febrero, 2012 at 20:15
hola que tal yo tengo una duda diferente espero me puedan ayudar, verán uso los sprites que encuentro en internet pero las encuentro todos ya en una sola imagen pero sin las cordenadas de cada sprite en esa imagen, mi pregunta es si hay una manera de obtener estas coordenadas ya que hasta ahora tengo que ir copiando una por una para generar una imagen individual de cada sprite y luego pasarcelas todas a un programa que las una y me de las coordenadas de la imagen que forma (yo en particular uso el spritepaker) y asi tengo la imagen original con sus coordenadas. Otra maera es ir viendo las coordenadas con una malla (ya sea en paint o photoshop) pero es horriblemente tedioso ambas maneras espero me puedan ayudar.