We've just updated MediaWiki and its underlying software. If anything doesn't look or work quite right, please mention it to us. --RanAS

es/Dynamic Sprite: Difference between revisions

From SnesLab
Jump to: navigation, search
Line 80: Line 80:
==== Asignación Fija para tiles específicos ====
==== Asignación Fija para tiles específicos ====
Esta consiste en que en vez de usar una asignación fija para un sprite específico, se hace esta asignación para algunas animaciones de tiles específicas. Los tiles se suelen animar de forma continua y permite ahorrar algunos tiles en la VRAM.
Esta consiste en que en vez de usar una asignación fija para un sprite específico, se hace esta asignación para algunas animaciones de tiles específicas. Los tiles se suelen animar de forma continua y permite ahorrar algunos tiles en la VRAM.
===== Pros =====
===== Pros: =====
<ul>
<ul>
<li>Fácil de implementar.</li>
<li>Fácil de implementar.</li>

Revision as of 22:16, 16 January 2024

English Português Español 日本語

Un Sprite Dinámico es un Sprite que carga sus propios gráficos a la VRAM (Memoria de Video de la Super Nintendo). Esto permite que el sprite pueda utilizar una cantidad ilimitada de poses (cuadros de animación) y tener una mayor cantidad de variedad de enemigos en un nivel.

También podría considerarse Sprite dinámico si carga otros recursos como su paleta de colores o tilemaps, en estos casos suele diferenciarse usando el termino "Paletas Dinámicas", "Tilemaps Dinámicos", "Background Dinámico", etc.

¿Por qué es necesario un sistema de sprites dinámicos?

La VRAM de la SNES es muy limitada, permitiendo solamente 64 kb de memoria que debe ser utilizada tanto para los gráficos del nivel, los tilemaps y los gráficos de los sprites. Si consideramos el espacio que solamente es destinado para sprites (Páginas de Sprites), en general los juegos no usan más de 16 kb de VRAM para sprites, lo que es equivalente a un espacio de 128x256 que se reparte entre todos los enemigos, personajes, player o cualquier entidad hecha con sprites.

Además considerando que los sprites solo pueden utilizar 8 paletas de colores, un sistema de sprites dinámicos que incluya paletas de colores dinámicas también es necesario, ya que, con solo 8 paletas de colores la cantidad de enemigos distintos que puedes usar en un nivel se reduce bastante.

Para solucionar estos problemas lo que se hace es tener un sistema de sprites dinámicos que permita cambiar en tiempo real tanto gráficos como paletas de colores y así no tener todas estas limitaciones al momento de trabajar con sprites.

Aplicaciones Prácticas

Los sprites dinámicos tienen varias aplicaciones, lo más común es utilizarlos para el player de un juego, aunque en realidad podría ser utilizado para enemigos, bosses, decoración, etc.

Acá una lista de utilidades de un buen sistema de sprites dinámicos:

  • Disminuir Tiempo de carga de nivel: Dado que cada sprite carga sus propios gráficos, no es necesario que estos se carguen durante la carga del nivel.
  • Si añades un sistema de paletas de colores dinámicas, puedes usar cualquier sprite dinámico en cualquier nivel.
  • Poder tener Sprites con múltiples animaciones y poses sin preocuparse del espacio en la memoria de video.
  • Poder rotar o escalar sprites sin necesidad de modo 7.
  • Hacer Players, la mayoría de los sprites usados como player son casi imposibles sin usar sprites dinámicos.
  • Poder hacer sprites enormes con varias poses, usando técnicas de doble buffer se pueden cargar poses realmente grandes sin preocuparse por flickering.
  • Jefes: muchos jefes son imposibles de hacer sin sprites dinámicos.

Glosario

  • Sprite: Tiene 2 significados principales cuando se habla en el contexto de SNES:
    • Para referirse a cada uno de los objetos de la OAM, que vendrían siendo bloques de un tamaño fijo (ejemplo 8x8 o 16x16) que se utilizan para dibujar entidades en pantalla que no son parte de los backgrounds.
    • Para referirse a entidades que no son parte de los Backgrounds. Normalmente se utilizará la segunda definición cuando hablemos de Sprites, la primera definición será reemplazada con la palabra Tile.
  • Dinámico: En el contexto de esta guía, se refiere a la capacidad de cambiar en tiempo real recursos tales como gráficos, tilemaps o paletas de colores.
  • Sprite Dinámico: Sprite que carga sus propios recursos en tiempo real.
  • VRAM: Memoria de video de la SNES, se utiliza para almacenar gráficos y tilemaps.
  • CGRAM: Memoria de colores de la SNES, se utiliza para almacenar paletas de colores que son utilizadas por los gráficos.
  • BPP: Se refiere a la cantidad de bits por pixel que usa un tipo de gráfico, durante esta guía, en general se hablará de 4BPP que serían 4 bits por pixel (2 píxeles por byte).
  • Tile: En el contexto de esta guía se utilizará tile para referirse a bloques de tamaño específico (8x8, 16x16, etc.) que se usan para sprites o para Backgrounds. Esto es similar a la primera definición de Sprite y se utilizará en general para diferenciarse de la segunda definición de Sprite.
  • DMA: Direct Memory Access se refiere principalmente a una pieza de hardware que se preocupa de enviar una cantidad masiva de datos de la forma más rápida posible.
  • Overflow de DMA: Se refiere a cuando el DMA envía más datos de los que el snes puede procesar durante el NMI. Esto produce flickering y de ser excesivo podría incluso causar glitches gráficos.
  • Frame: Se refiere a 1 ciclo completo de la SNES, la Super Nintendo utiliza 60 de estos ciclos por cada segundo (50 si es versión PAL). Este ciclo normalmente incluye una ejecución completa de la lógica y una ejecución completa del NMI Handler.
  • NMI: Not Masked Interruption, en el contexto del SNES, se genera un NMI al momento de que el puntero de la TV pasa de la esquina inferior derecha a la esquina superior izquierda, lo que también es conocido como Blanking. Durante esta interrupción se llama una función llamada NMI Handler que permite hacer cambios en los recursos almacenados de la consola como gráficos, paletas de colores, tilemaps, etc.
  • Pose: Se utilizara este término para referirse a los cuadros de animación de un sprite, esto es debido a que cuadro de animación cuando se traduce al inglés es Animation Frame, lo que puede ser confuso con los Frames de la SNES.
  • Página de Sprites: Se refiere a el espacio en la VRAM que solamente puede ser utilizado por los sprites.
  • Tilemap: Normalmente se refiere a los Tiles utilizados por los backgrounds, que se utilizan tanto para el terreno de un nivel como para los fondos o en algunos casos elementos como cuadros de diálogos o HUD.

¿Cómo se crea un sistema de sprites dinámicos?

Al momento de crear un sistema de sprites dinámicos se deben considerar lo siguiente:

  • Gestión de Espacio en la VRAM.
  • Gestión de Overflow de DMA.
  • Subida de datos a la VRAM.
  • Inserción de Recursos en el ROM.
  • Conexión entre los recursos y el código.

Gestión de Espacio en la VRAM

Asignación Fija

Un sprite dinámico necesita un lugar en las páginas de sprites de la VRAM donde pueda cargar sus poses. Existen varias maneras de asignar espacio para sprites dinámicos, en esta sección abordaremos cada una de estas formas. Asignación Fija

Esta consiste en asignar un lugar fijo en la VRAM para un sprite dinámico específico.

Pros:
  • Fácil de implementar.
  • La implementación suele ser muy rápida y eficiente en términos de performance.
Contras:
  • En la mayoría de los casos, no puedes tener más de una instancia del mismo sprite.
  • El espacio asignado está diseñado de forma muy restrictiva para solo funcionar con ese sprite específico. Lo que hace que se restrinja mucho el cambiar la skin del sprite, dado que la skin debe usar el mismo espacio asignado que el sprite original.
  • Si quisieras hacer múltiples sprites dinámicos tendrás que asignarle a cada uno un espacio específico y eso haría que se limitará mucho el uso de estos sprites.
  • El sistema no escala bien, a medida que agregar más sprites dinámicos o más cosas que requieren la VRAM puede ser contraproducente.
  • Va en parte en contra del espíritu de los sprites dinámicos, ya que, la idea de estos es aumentar la flexibilidad de usar sprites y quitar limitaciones. Pero este sistema suele restringir más de lo que ayuda.
Recomendaciones de uso

Este sistema en general es bastante malo en varios sentidos, pero tiene un nicho de uso sobre todo para juegos sencillos que no tienen muchos gráficos o enemigos o que estos enemigos no usen muchas poses o un gran tamaño, en este tipo de juegos, tiene utilidad para el player o para un sprite específico que nunca debe tener más de 1 copia en pantalla. Este nicho es solamente si quieres tener una mejor performance aunque otros sistemas aunque no sean tan buenos en performance, dudo que tengas problemas de slowdown debido a ellos.

Asignación Fija para tiles específicos

Esta consiste en que en vez de usar una asignación fija para un sprite específico, se hace esta asignación para algunas animaciones de tiles específicas. Los tiles se suelen animar de forma continua y permite ahorrar algunos tiles en la VRAM.

Pros:
  • Fácil de implementar.
  • La implementación suele ser muy rápida y eficiente en términos de performance, aunque, no tanto como en la Asignación fija normal.
Contras:
  • En general tiene las mismas contras que la asignación fija, excepto que este si es un poco más flexible (dependiendo de cómo se haga para animar los tiles) para poder poner más de una instancia del sprite en pantalla.
Recomendaciones de uso

En general, este sistema también es bastante malo y si bien puede sacar de apuros a alguna persona sin muchos conocimientos de código, no lo recomiendo, ahora igual puede tener un nicho en el hacking de Rom Hacks cuando se desea implementar algo rapido sin programar un sistema complejo de sprites dinámicos para un par de sprites específicos.

Asignación Dinámica con tamaño fijo por Sprite

Consiste en asignar un espacio en la VRAM a cada instancia de algún sprite dinámico. El sprite se preocupa de subir sus gráficos a su espacio asignado. Los sprites que usan este sistema deben usar un tamaño específico en la VRAM que están pre definidos por el sistema (ejemplo que solo se puedan usar espacios de 64x16, 128x16 o 128x32).

Pros
  • Si bien la implementación de este sistema no es tan sencilla como el de asignación fija, suele ser bastante fácil de implementar.
  • En términos de performance si bien no es tan bueno como el de Asignación fija suele ser bastante rápido.
  • Permite mayor flexibilidad que los sistemas anteriores, ya que, puedes poner sprites dinámicos con mayor libertad.
  • Permite usar múltiples instancias distintas de distintos sprites.
Contras
  • El espacio asignado está diseñado de forma muy restrictiva para solo funcionar con ese sprite específico. Lo que hace que se restrinja mucho el cambiar la skin del sprite, dado que la skin debe usar el mismo espacio asignado que el sprite original.
  • El número de estos sprites que puedes usar en pantalla suele ser muy bajo debido a que se malgasta mucho espacio en la VRAM.
  • Suele tener muchos problemas de gestión de overflow de DMA dado que cada instancia de un sprite dinámico debe cargar las poses incluso si estas ya fueron cargadas por otro sprite previamente.
  • Ciertas combinaciones de sprites provocan huecos en la VRAM que son muy difíciles de aprovechar y que reducen la cantidad de sprites dinámicos que puedes utilizar al mismo tiempo. La solución a esto suele ser desfragmentar el espació asignado para sprites dinámicos, lo que puede terminar afectando la performance del sistema.
  • En muchos casos hay malgasto de VRAM, ya que, sprites que son más pequeños que el espacio que tienen asignado siguen usando todo ese espacio.
  • Una vez que el sprite tiene se le asigna un espacio, cambiar el tamaño de ese espacio puede ser muy difícil y acarrear muchos otros problemas debido a cómo el sistema fue construido. Esto provoca que por ejemplo tener un sprite que se agrande si pasa algún suceso específico no sea posible en este sistema o que debas asignarle un espacio mucho mayor del que necesita realmente desde un inicio.
Recomendaciones de uso

En general, este sistema si bien es mucho mejor a los anteriores, sin embargo, tiene varios inconvenientes que lo hacen poco atractivo. Solo recomendaría usarlo si necesitas un sistema de sprites dinámicos decente y que sea muy rápido, aunque en términos de performance es casi igual a “Asignación Dinámica con tamaño variable por Sprite”. Tiene un nicho también si se desea implementar rápidamente un sistema básico y funcional.

Asignación Dinámica con tamaño variable por Sprite

Es similar al sistema de “Asignación Dinámica con tamaño fijo por Sprite”, lo que cambia, es que cada sprite calcula cuánto espacio necesita en la VRAM (normalmente se calcula utilizando bloques de 16x16). Para hacer este cálculo de espacio, el sprite considera la pose que usa más espacio y en base a esa pose calcula cuánto espacio debe usar en la VRAM.

Pros
  • En términos de performance si bien no es tan bueno como el de Asignación fija suele ser bastante rápido.
  • Permite mayor flexibilidad que los sistemas anteriores, ya que, puedes poner sprites dinámicos con mayor libertad.
  • Permite usar múltiples instancias distintas de distintos sprites.
  • Sufre menos de huecos en la VRAM que “Asignación Dinámica con tamaño fijo por Sprite”.
  • Usa el espacio de manera más eficiente que “Asignación Dinámica con tamaño fijo por Sprite”.
  • Permite mayor cantidad de tamaños de sprites. Ya que, cada sprite usa el tamaño que necesita.
  • En general, permite mayor cantidad de sprites dinámicos a la vez que “Asignación Dinámica con tamaño fijo por Sprite”.
Contras
  • La implementación suele ser más compleja, dado que la búsqueda de espacio libre en la VRAM no es trivial de resolver de forma eficiente.
  • El espacio asignado está diseñado de forma muy restrictiva para solo funcionar con ese sprite específico. Lo que hace que se restrinja mucho el cambiar la skin del sprite, dado que la skin debe usar el mismo espacio asignado que el sprite original.
  • Suele tener muchos problemas de gestión de overflow de DMA dado que cada instancia de un sprite dinámico debe cargar las poses incluso si estas ya fueron cargadas por otro sprite previamente.
  • Ciertas combinaciones de sprites provocan huecos en la VRAM que son muy difíciles de aprovechar y que reducen la cantidad de sprites dinámicos que puedes utilizar al mismo tiempo. La solución a esto suele ser desfragmentar el espació asignado para sprites dinámicos, lo que puede terminar afectando la performance del sistema. Si bien estos problemas son menores a los de “Asignación Dinámica con tamaño fijo por Sprite”, estos siguen ocurriendo.
  • Si bien no malgasta tanto espacio como “Asignación Dinámica con tamaño fijo por Sprite”, sigue habiendo un gran malgasto debido a que el sprite siempre debe utilizar como espacio el utilizado por la pose más grande.
  • Una vez que el sprite tiene se le asigna un espacio, cambiar el tamaño de ese espacio puede ser muy difícil y acarrear muchos otros problemas debido a cómo el sistema fue construido. Esto provoca que por ejemplo tener un sprite que se agrande si pasa algún suceso específico no sea posible en este sistema o que debas asignarle un espacio mucho mayor del que necesita realmente desde un inicio.
Recomendaciones de uso

Este sistema en general es bastante bueno y de hecho es el que utilizan juegos como Donkey Kong Country. En la mayoría de casos, este sería una buena opción para usar como sistema de sprites dinámicos, sobre todo si el espacio asignado para sprites dinámicos no es tan grande. Aunque puede ser algo difícil de implementar, por lo que, no es recomendable para desarrolladores que aún no son muy hábiles o si se tiene poco tiempo para desarrollarlo. También, si el tamaño para sprites dinámicos que se posee es grande es mejor el sistema de “Asignación Dinámica por Pose”.

Asignación Dinámica por Pose

Se asigna un espacio en la VRAM por cada pose que es requerida, una vez que el espacio asignado para sprites dinámicos está lleno, se reemplaza una o más poses para poder cargar la nueva pose. La manera en que se reemplaza esta pose debe ser de acuerdo a alguna política de reemplazo como puede ser reemplazar la pose menos usada o reemplazar la pose que lleva más tiempo sin usarse.

Básicamente podría resumirse en que este sistema trata al espacio asignado para sprites dinámicos en una memoria caché de poses.

Pros
  • Cada pose se carga en la VRAM solo una vez y luego es reutilizada por cualquier código que requiera esa pose, lo que no solo es eficiente en términos de espacio sino también en performance.
  • No está restringido a solo ser usado desde el código de un sprite, podría cargarse la pose desde cualquier código.
  • Disminuye considerablemente la carga a la VRAM, lo que disminuye mucho las posibilidades de un overflow de DMA.
  • Es fácil hacer reskin de una entidad que use este sistema, ya que, cada pose puede tener cualquier tamaño.
  • La flexibilidad de uso de los sprites dinámicos aumenta considerablemente al punto que pueden ser usados como si fueran sprites normales en términos de cantidad. Este sistema se siente como que no estuvieras en una consola tan limitada como la SNES.
  • No hay casi nada de malgasto de VRAM, dado que cada pose usa el espacio más pequeño que puede.
  • Dado que cada sprite puede usar cualquier pose, no hay restricciones en el tamaño del espacio dinámico que usa siempre y cuando quepa en el espacio dinámico.
  • Permite un uso bastante flexible de double buffer, ya que, de por si este sistema es como un double buffer avanzado. Lo que permite separar los sprites en múltiples secciones y cargarlos por partes. Si bien el double buffer es posible en los otros sistemas, debe ser implementado por separado y suele ser más limitado.
  • Si tienes varias copias del mismo sprite dinámico tienes 0 limitaciones de uso para ese sprite.
  • Con este sistema, usar sprites dinámicos es tan conveniente que podrías reemplazar todos los sprites normales y transformarlos en sprites dinámicos y tener ventajas como poder usar cualquier entidad (enemigos, personajes, etc.) en cualquier nivel sin casi ninguna limitación.
Contras
  • Las poses que fueron utilizadas en el frame anterior, no pueden ser reemplazadas para evitar glitches gráficos, esto provoca que en algunos casos, tengas cargada la pose vieja y la pose nueva al mismo tiempo durante 1 frame específico y ,por lo tanto, requiere más espacio del necesario para un sprite específico. Esto se arregla aumentando el tamaño del espacio asignado para sprites dinámicos, mientras más grande este espacio, mejor funciona el sistema, otra solución es dividir las poses en distintas secciones para facilitar su carga en la VRAM.
  • La implementación suele ser muy compleja, ya que, no solo se debe hacer un sistema de espacio libre en la VRAM para cargar las poses que son requeridas, sino que también requiere la implementación de una tabla hash que almacene la información de las poses para poder hacer eficiente la búsqueda de estas.
  • En general requiere un tamaño de espacio asignado para sprites dinámicos mayor que otros sistemas.
Recomendaciones de uso

En general, este sistema es el mejor de todos y es preferible en casi todos los casos, ya que, tiene buena performance y elimina casi todas las limitaciones de los sprites dinámicos. Si el desarrollador tiene suficiente tiempo y experiencia para implementarlo, no hay ninguna excusa para no usarlo, salvo que de manera forzada requieras un espacio asignado para sprites dinámicos muy pequeño.

Gestión de Overflow de DMA

Subida de datos a la VRAM

Inserción de Recursos en el ROM

Conexión entre los recursos y el código