Kaiser de Emperana
Called in hand
Hola.
Hace mucho tiempo que se sabe que se puede modificar la introducción de gamefreak (nidorino en FR, latios/latias en RZE) programando en C, como explica Shiny Quagsire en este tutorial.
Pero el hecho de que sea programando en C ya hace que las personas lo consideren imposible.
Por eso es que me puse a programar un poco para que el hacer una intro sea hasta más facil que hacer un script. El procedimiento es el mismo que antes, van a programar en C, pero no van a necesitar saber nada del otro mundo, ya que cree unas funciones (que vendrían a ser como los comandos de los scripts) que permiten hacer cosas en una sola línea. Por ejemplo, si quieren mostrar un sprite, lo único que tiene que hacer es poner "load_sprite" y los datos del sprite (imagen, paleta, posición, etc.).
Una muestra de una intro (bastante mala):
Bueno, ahora el tuto.
Primero que nada, para poder compilar su intro necesitan:
- DevkitARM
- Armips
- Make
Todos los cuales pueden instalar siguiendo mi tutorial anterior (ahora saben la verdadera razón por la que lo hice).
Y finalmente van a necesitar descargar esta plantilla.
Y además van a necesitar un editor de texto... El notepad de windows funcionaría si no fuera porque yo uso linux... Y yo escribi el archivo que deben editar... Van a necesitar un editor de texto que soporte codificación UTF-8. Yo recomiendo Notepad++.
Una vez tengan todo eso están listos para hacer su intro. Voy a dividir el tuto en partes ya que hay muchas cosas que tomar en cuenta.
Créditos y agradecimientos:
Bueno eso, sería todo. Cualquier problema/recomendación, no duden en postearlo. Y si alguien quiere hacer tutoriales más específicos sobre esto, los invito a que los hagan.
Siempre que hago un aporte la gente dice "ah, ¡que bueno!", pero después nadie lo usa. Esta vez úsenlo... please, este fue largo...
Saludos.
Hace mucho tiempo que se sabe que se puede modificar la introducción de gamefreak (nidorino en FR, latios/latias en RZE) programando en C, como explica Shiny Quagsire en este tutorial.
Pero el hecho de que sea programando en C ya hace que las personas lo consideren imposible.
Por eso es que me puse a programar un poco para que el hacer una intro sea hasta más facil que hacer un script. El procedimiento es el mismo que antes, van a programar en C, pero no van a necesitar saber nada del otro mundo, ya que cree unas funciones (que vendrían a ser como los comandos de los scripts) que permiten hacer cosas en una sola línea. Por ejemplo, si quieren mostrar un sprite, lo único que tiene que hacer es poner "load_sprite" y los datos del sprite (imagen, paleta, posición, etc.).
Una muestra de una intro (bastante mala):
Bueno, ahora el tuto.
Primero que nada, para poder compilar su intro necesitan:
- DevkitARM
- Armips
- Make
Todos los cuales pueden instalar siguiendo mi tutorial anterior (ahora saben la verdadera razón por la que lo hice).
Y finalmente van a necesitar descargar esta plantilla.
Y además van a necesitar un editor de texto... El notepad de windows funcionaría si no fuera porque yo uso linux... Y yo escribi el archivo que deben editar... Van a necesitar un editor de texto que soporte codificación UTF-8. Yo recomiendo Notepad++.
Una vez tengan todo eso están listos para hacer su intro. Voy a dividir el tuto en partes ya que hay muchas cosas que tomar en cuenta.
Bueno, para probar que todo esté correcto. Lo primero que vamos a hacer es insertar la intro que mostré en el video en una rom limpia.
Descarguen este archivo y extráiganlo.
Luego, en la carpeta example pongan un rom limpio de FR, con el nombre "BPRE0.gba".
(La mayoría de la intro funciona perfectamente en emerald, pero cómo los números de las canciones son diferentes, estos funcionan mal. Además la plantilla usada está desactualizada. Por eso a la hora de probar, usen una rom de fire red.)
Ahora copien el nombre de la ruta de la carpeta example y abran cygwin. Windows usa barras invertidas para las rutas, cygwin usa barras normales, así que deberán cambiar las mismas para que funcione. Si la ruta es "C:\ruta\a\la\carpeta\example", en cygwin será: "C:/ruta/a/la/carpeta/example"
Una vez en cygwin, escriban: 'cd "C:/ruta/a/la/carpeta/example" ' (obviamente, con la ruta correcta...) y aprieten enter
Y luego de eso, escriban "make" y aprieten enter.
Se deberían de mostrar algunos mensajes de compilación y aparecer algo como "Creating ROM".
Una vez que eso termine, habran con el emulador, no el rom BPRE0.gba, sino el que está dentro de la carpeta build, rom.gba.
Y walá deberían de estar viendo la intro customizada
Si les apareció algún error o no entendieron a que me refería con alguna cosa. No duden en postearlo.
Descarguen este archivo y extráiganlo.
Luego, en la carpeta example pongan un rom limpio de FR, con el nombre "BPRE0.gba".
(La mayoría de la intro funciona perfectamente en emerald, pero cómo los números de las canciones son diferentes, estos funcionan mal. Además la plantilla usada está desactualizada. Por eso a la hora de probar, usen una rom de fire red.)
Ahora copien el nombre de la ruta de la carpeta example y abran cygwin. Windows usa barras invertidas para las rutas, cygwin usa barras normales, así que deberán cambiar las mismas para que funcione. Si la ruta es "C:\ruta\a\la\carpeta\example", en cygwin será: "C:/ruta/a/la/carpeta/example"
Una vez en cygwin, escriban: 'cd "C:/ruta/a/la/carpeta/example" ' (obviamente, con la ruta correcta...) y aprieten enter
Y luego de eso, escriban "make" y aprieten enter.
Se deberían de mostrar algunos mensajes de compilación y aparecer algo como "Creating ROM".
Una vez que eso termine, habran con el emulador, no el rom BPRE0.gba, sino el que está dentro de la carpeta build, rom.gba.
Y walá deberían de estar viendo la intro customizada
Si les apareció algún error o no entendieron a que me refería con alguna cosa. No duden en postearlo.
Bueno, C es un lenguaje de programación. Para explicarlo sencillamente, es bastante parecido a los scripts, es un conjunto de instrucciones que se ejecutan en el orden que están escrito. Pero al igual que los scripts, se deben seguir unas pocas reglas para que el código compile. Por ahora lo único que necesitan saber es que las intrucciones, a las que llamaré expresiones de ahora en adelante, deben llevar un punto y coma (";") al final. Caso contrario producirá un error.
Así que ara ejecutar dos expresiones en C ustedes deberían hacer:
Pero como 3 instrucciones eso ya se volvería ilegible, así que si bien pueden escribir como mostré recién. Lo recomendado es que escriban:
C ignora los saltos de línea, los espacios y las tabulaciones. Acomoden el código como les sea más facil comprenderlo.
Así que ara ejecutar dos expresiones en C ustedes deberían hacer:
Código:
expresión1; expresión2;
Código:
expresión1;
expresión2;
Bueno. En los scripts ustedes saben que se pueden realizar operaciones matemáticas con variables. Pero es tan molesto que hace uno lo evite... En C es muchísmio más fácil, basta como poner "2 + 2" y el compilador va a tomar como si allí dijera 4. Eso se puede usar, ya sea para hacer el código más legible (por ejemplo, saber de donde es que aparecen los números), o para trabajar con valores variables variables.
(Cabe mencionar que C no lo numero se pueden escribir tanto en decimal como en hexadecimal. Para escribirlos en hexadecimal hay que ponerles el prefijo "0x").
(Cabe mencionar que C no lo numero se pueden escribir tanto en decimal como en hexadecimal. Para escribirlos en hexadecimal hay que ponerles el prefijo "0x").
Operadores aritméticos: dijo:Para estos tres primeros no creo que se necesiten explicaciones.
*: multiplicación.
+: suma.
-: resta.
Y también están estos dos:
/: división. Es una división como ustedes la conocen, pero con un pequeño detalle. La gba, no puede trabajar con número con coma. Así que la division ignorará los decimales. "1 / 2" será equivalente a 0 (no 0.5), "11 / 4" será equivalente a 2 (no 2.75).
%: módulo de la división. Suena raro pero es sencillo. Es el resto de la división, tomando en cuenta los ejemplos anteriores, 1 / 2 da 0, y sobra 1 (Dos por cero es igual a cero, y uno menos cero es igual a uno), así que "1 % 2" será equivalente a 1. Para el caso de 11 / 4, da 2, y sobran 3 (Cuatro por dos es igual a ocho, y once menos ocho da tres), por lo que "11 % 4" es igual a 3.
Operadores booleanos: dijo:En C los números sirven para algunas cosas más. Como para responder preguntas. "0" equivale a "false" (en español "falso", que vendría a ser NO), y cualquier otro valor distinto de cero equivale a "true" (en español "verdadero", que vendría a ser SÍ). Así que por ejemplo 1 + 4 segun el contexto donde lo pongan puede significar, o 5, o true. Esto se va a entender mejor más adelante, pero voy explicando las básicas.
Existen unos operadores que están pensado para resolver estas preguntas de sí o no. Como el tener muchos sí no es muy útil, estos operdores siempre o devolverán o 1 o 0 (pero eso no cambia que 5 sea equivalente a 1 en ciertas circunstancias). Los operadores son:
<: menor. Ej: "4 < 5" es equivalente a true. "5 < 5" es equivalente a false.
<=: menor o igual. Ej: "4 <= 5" es equivalente a true. "5 <= 5" es equivalente a true.
>: mayor. Ej: "4 > 5" es equivalente a false. "5 > 5" es equivalente a false.
>=: mayor o igual. Ej: "4 >= 5" es equivalente a false. "5 >= 5" es equivalente a true.
==: igual. Ej: "4 == 5" es equivalente a false. "5 == 5" es equivalente a true.
!=: distinto. Ej: "4 != 5" es equivalente a true. "5 != 5" es equivalente a false.
Operadores logicos: dijo:Pero las preguntas no son siempre tan sencillas de contestar. Por eso es que existen algunos operadores que sirven para dar respuestas que dependan de más cosas. Los mismos trabajan con valores de true o false y son remplazados con valores de true o false. Existen tres operadores:
&&: and (en español "y"). Si los dos valores son verdaderos devuelve true, caso contrario false. Ej: "(4 < 5) && (6 == 6)" se reamplaza por "false && true", que se remplaza finalmente por false.
||: or (en español "o"). Si almenos uno de los dos valores es true devuelve true, caso contrario false. Ej: "(4 < 5) || (6 == 6)" se reamplaza por "false || true", que se remplaza finalmente por true.
!: not (que vendria a ser "esto que te digo es mentira"). Este a diferencia de los otros recibe un único valor en lugar de dos. Ej: "!(4 != 5)" se reamplaza por "!(true)", lo que finalmente devuelve true.
Como ya dije esto no va a ser un tutorial de como programar. Así que no me voy a explayar mucho.
Ademas de poder realizar operaciones simples como estuvimos viendo. En C se pueden ejecutar unos comandos más complicados. El concepto es bastante similar a los comandos de los scripts. Tienen un nombre y cuando los usás tenés que pasar unos cuantos valores, que llamaré parámetros. Cada función va a recibir diferentes parámetros, pero todas se llaman con el mismo formato (nombre de la función; parametros entre parentesis, separados por coma; y un punt y coma final, como explique anteriormente):
Ademas de poder realizar operaciones simples como estuvimos viendo. En C se pueden ejecutar unos comandos más complicados. El concepto es bastante similar a los comandos de los scripts. Tienen un nombre y cuando los usás tenés que pasar unos cuantos valores, que llamaré parámetros. Cada función va a recibir diferentes parámetros, pero todas se llaman con el mismo formato (nombre de la función; parametros entre parentesis, separados por coma; y un punt y coma final, como explique anteriormente):
Código:
funcion1(); (una funcion que no recibe parámetros)
funcion2(4, 5); (una funcion que recibe dos parametros)
funcion2(4 + 8 * 9, 15); (se pueden realizaron operaciones dentro de los parametros, esto sería equivalente a "funcion2(76, 15);")
¿Se acuerdan de los comando "compare", "if goto" e "if call" de los scripts? ¡Sí! ¡Esa cosa que sirve para tomar deciciones en los scripts, pero que demoramos cerca de 5 minutos hasta saber lo que realmente hace, porque está escrito de una forma horrible!
Bueno en C también está, pero a diferencia de los scripts, es hermoso <3
Las "preguntas de sí o no" que mencioné antes sirven para esto. Miren este código:
Si en donde dice "condición" hubiera una expresión equivalente a true, se ejecutaría la funcion (y cualquier otra cosa que este dentro de las llaves). Mientras que si hubiera una expresión equivalente a false, no haría nada.
Esto,por ejemplo, ejecutaría la función:
Mientras que esto, no:
(Como pueden ver, pueden escribir cosas más complicadas dentro de los parentesis, les dejo razonar a ustedes porque la función no se ejecutaría)
Nótese que despues de un if no va ningun punto y coma, pero sí despues de las expresiones dentro de las llaves.
Bueno en C también está, pero a diferencia de los scripts, es hermoso <3
Las "preguntas de sí o no" que mencioné antes sirven para esto. Miren este código:
Código:
if ( "condición" ) {
funcion();
}
Esto,por ejemplo, ejecutaría la función:
Código:
if ( 4 < 5 ) {
funcion();
}
Código:
if ( ((4 + 5) > 8) && (4 == 5) ) {
funcion();
}
Nótese que despues de un if no va ningun punto y coma, pero sí despues de las expresiones dentro de las llaves.
Hay veces que dependiendo de una condición queremos hacer o una cosa u otra. Para eso existen los if...else
En este caso si "condición" es true, se ejecutará la funcion1 y si es false, se ejecutará la función2 y la función3.
Código:
if ( "condición" ) {
funcion1();
} else {
funcion2();
funcion3();
}
Y por si la cosa es todavía más complicada, podemos hacer cosas como esto.
Si se cumple la condicion1, se ejecutará la funcion1 y nada más. Si no se cumple pero se cumple la condicion2, se ejecutará la funcion2 y nada más. Si no se cumplen ni la condicion 1 ni la 2, pero sí la 3, se ejecutará la funcion3. Y si no se cumple ninguna condición se ejecutará la funcion4.
Pueden poner tantos else if como deseen y no necesariamente deben poner un else.
Código:
if ( "condición1" ) {
funcion1();
} else if ( "condicion2" ) {
funcion2();
} else if ( "condicion3" ) {
funcion3();
} else {
funcion4();
}
Pueden poner tantos else if como deseen y no necesariamente deben poner un else.
Hay situaciones en las que van a tener que trabajar con números en vez de palabras, como es el caso de los id de los sprites (más adelante lo van a ver).
Para que el código no se vuelva demasiado confuso ustede pueden escribir esto al comienzo de un archivo:
De esta forma hace que cada vez que ustedes escriban "ID_SPRITE_BULBASAUR" en su código, el compilador lo va a tomar como si hubieran escrito 1; y cuando escriban "ID_PALETA_BULBASAR" lo va a tomar como si escribieran 7.
Así no van a necesitar estar pensando constantemente en números.
Para que el código no se vuelva demasiado confuso ustede pueden escribir esto al comienzo de un archivo:
Código:
#define ID_SPRITE_BULBASAUR 1
#define ID_PALETA_BULBASAR 7
Así no van a necesitar estar pensando constantemente en números.
Si estedes escriben "//" en código fuente escrito en C. El compilador ignorará todo lo que escriban a la derecha de las dos barras.
Y si escriben "/*" el compilador ignorará todo lo escrito a continuación hasta que encuentre un lugar donde diga "*/".
Pueden usar esto para agregar anotaciones de que es lo que están haciendo en alguna parte de su código.
Y si escriben "/*" el compilador ignorará todo lo escrito a continuación hasta que encuentre un lugar donde diga "*/".
Pueden usar esto para agregar anotaciones de que es lo que están haciendo en alguna parte de su código.
Una vez hayan descargado la plantilla. Abran con su editor de texto el archivo "intro.c" que está en la carpeta "src".
Van a ver esto:
Ustedes pueden modificar todo lo que quieran que este dentro de las llaves externas ("bool intro_main() { ... }", ustedes podrían editar los puntos suspensivos). Ese código que está allí se va a ir ejecutando continuamente hasta que le digan que pare. Les explico por partes como funciona.
La parte que dice:
Esto es la parte principal. Aca debería poner todo lo que quieran que haga la intro.
Si leyeron las partes anteriores se darán cuenta que hay una funcion llamada "get_time", que no recibe ningún parámetro, y está comparando su valor con 0. Pero lo más seguro es que no entiendan que significa eso. Y está bien, porque no lo expliqué
Para hacer una intro ustedes tiene que realizar muchas cosas en diferentes momentos de tiempo. Por eso es que el sistema tiene un reloj. La funcion get_time(), lo que hace es devolver el valor actual del reloj. Si el reloj tiene un 0, get_time() será equivalente a que si hubiera un 0, pero si tiene un 25, se remplazará por 25.
Por eso es que esa primera parte se ejecutará sólo cuando el reloj esté en 0. Probablemente allí quiera cargar los gráficos e iniciar la música por ejemplo.
Ahora supongo que entienden un poco más la parte del else if. En la primera vuelta de la función se ejecutará lo que ustedes escriban en vez de "//Do something". Y a partir de la segunda vuelta, se ejecutará la parte del else if, hasta que la condición se deje de cumplir.
Y para que entiendan la condición que supongo que todos deben estar perdidos. SECOND es una palabra que se reamplaza por el valor numérico que vale un secundo (si get_time() es 1, no quiere decir que pasó un segundo). Así que básicamente 2* SECOND será el valor numérico equivalente a dos segundos; por lo que mientras el valor del reloj sea menor a 2 segundos, se ejecutará lo que escriban en lugar de "//Do more things".
Sientanse libres de modificar esto como les plazca.
La parte de:
Simplemente le suma uno al reloj. Les recomendaría no sacarlo a no ser que sepan lo que hacen.
Esta parte no la voy a explicar demasiado. "key_down" es una funcion que se remplaza por true si una tecla está presionada o por false si no lo esta. Para más información ver la seccion de funciones. Pero bueno lo que tenemos es basicamente una condición donde si el jugador presiona una tecla o el reloj alcanza 20 segundos ocurre algo. "return true" es la forma que tenemos de decirle al juego que la intro termino, por lo que si se cumple la condición la intro terminará (en este caso, que la saltee apretando A, B o start; o que pasen 20 segundos).
Y finalmente esto:
Es lo opuesto a return true, le dice al juego que la intro todavía continua.
Una vez hayan terminado con el hola mundo, lo que deberían hacer es ponerse a probar las diferentes funciones que dejo más abajo, total no pierden nada con probar.
La intro se inserta en unos pocos segundos y con un simple parche podrían volver todo a la normalidad. E incluso si son tontos y no hacen un parche, esto no borra el rom anterior sino que crea uno nuevo.
Así que mientras no inserten la intro en algún lugar que sobreescriba algo y por sobre todo borren el rom BPRE.gba, no deberían de tener ningún problema.
También lo que pueden hacer es ver la intro que subí de ejemplo al principio. Ahí básciamente hago de todo, cambio la música, cambio los gráficos de los bg en el medio de la secuencia, uso sprites, muevo sprites, uso animaciones, uso variables, y ya ni me acuerdo si hacía algo más.
Pero el código sigue siendo bastante corto. Aunque no sé si lo hice muy legible... Si no se entiende nada avisen y algún día que tenga tiempo le agrego explicaciones.
Van a ver esto:
Código:
#include "headers/important.h"
bool intro_main()
{
if (get_time() == 0) {
// Do something
} else if (get_time() < 2 * SECOND) {
//Do more things
}
if (key_down(KEY_A | KEY_B | KEY_START) || get_time() == 20 * SECOND)
{
return true;
}
inc_timer();
return false;
}
La parte que dice:
Código:
if (get_time() == 0) {
// Do something
} else if (get_time() < 2 * SECOND) {
//Do more things
}
Si leyeron las partes anteriores se darán cuenta que hay una funcion llamada "get_time", que no recibe ningún parámetro, y está comparando su valor con 0. Pero lo más seguro es que no entiendan que significa eso. Y está bien, porque no lo expliqué
Para hacer una intro ustedes tiene que realizar muchas cosas en diferentes momentos de tiempo. Por eso es que el sistema tiene un reloj. La funcion get_time(), lo que hace es devolver el valor actual del reloj. Si el reloj tiene un 0, get_time() será equivalente a que si hubiera un 0, pero si tiene un 25, se remplazará por 25.
Por eso es que esa primera parte se ejecutará sólo cuando el reloj esté en 0. Probablemente allí quiera cargar los gráficos e iniciar la música por ejemplo.
Ahora supongo que entienden un poco más la parte del else if. En la primera vuelta de la función se ejecutará lo que ustedes escriban en vez de "//Do something". Y a partir de la segunda vuelta, se ejecutará la parte del else if, hasta que la condición se deje de cumplir.
Y para que entiendan la condición que supongo que todos deben estar perdidos. SECOND es una palabra que se reamplaza por el valor numérico que vale un secundo (si get_time() es 1, no quiere decir que pasó un segundo). Así que básicamente 2* SECOND será el valor numérico equivalente a dos segundos; por lo que mientras el valor del reloj sea menor a 2 segundos, se ejecutará lo que escriban en lugar de "//Do more things".
Sientanse libres de modificar esto como les plazca.
La parte de:
Código:
inc_timer();
Esta parte no la voy a explicar demasiado. "key_down" es una funcion que se remplaza por true si una tecla está presionada o por false si no lo esta. Para más información ver la seccion de funciones. Pero bueno lo que tenemos es basicamente una condición donde si el jugador presiona una tecla o el reloj alcanza 20 segundos ocurre algo. "return true" es la forma que tenemos de decirle al juego que la intro termino, por lo que si se cumple la condición la intro terminará (en este caso, que la saltee apretando A, B o start; o que pasen 20 segundos).
Código:
if (key_down(KEY_A | KEY_B | KEY_START) || get_time() == 20 * SECOND)
{
return true;
}
Código:
return false;
Bueno. Como decirles la lista de comando y mandarlo a hacer algo es básicamente tirarlos al muere. Les voy a enseñar a hacer su primer intro personalizada.
Lo único que necesitan saber es como de una imagen obtener un tileset y una raw. Si alguna vez insertaron alguna portada o algún gráfico diferente de tiles y sprites deberían de saber lo que es. Para los que no sepan, miren los pasos 1 a 3 de este tutorial.
Descarguen la plantilla y sigan los siguientes pasos:
Lo único que necesitan saber es como de una imagen obtener un tileset y una raw. Si alguna vez insertaron alguna portada o algún gráfico diferente de tiles y sprites deberían de saber lo que es. Para los que no sepan, miren los pasos 1 a 3 de este tutorial.
Descarguen la plantilla y sigan los siguientes pasos:
Lo que necesitamos para este ejercicio es crear una imagen que vamos a mostrar en la pantalla. La pantalla de la gba es de 240x160 píxeles, así que háganla pensando en eso. Pero la imagen debe ser una imagen de 256x256 y debe estar indexada en 16 colores.
Esta va a ser mi imagen:
Ahora lo que sigue se los dejo a ustedes. Obtengan un tileset y una raw. Yo usé sphere.
Una vez tengan las dos cosas vamos a abrir la carpeta de la plantilla y vamos a entrar a la carpeta tools de la plantilla. Allí ejecuten el archivo main_iu.py con python. Para esto van a necesitar tener instalados los módulos: sip, PyQt5 y Pillow.
Los que no tengan idea de que es lo que acabo de decir, descarguen esto y hagan doble click en main.exe
Bueno, en estos momentos deberían de ver este programa que hice:
Es básicamente una herramienta que sirve para transformar los recursos a algo que el compilador de C entienda, podrían tranquilamente insertar las recursos al rom de la forma que están acostumbrados y usar el puntero de la mismas para referirse a ellas. Pero este modo me parece que es mucho mejor. Además así los mismos no se insertan al rom hasta que se inserte la intro completa, por lo que si cambian alguno no desperdician nada de espacio.
Me parece que la herramienta es bastante intuitiva. Lo que tiene que hacer es abrir el archivo que quiera insertar, elegir lo que quieren sacar de ello y agregarlo al header. Y finalmente le dan a guardar.
Yo lo que voy a hacer es:
-Cargar la imagen de mi tileset indexado.
-Selecciono la opción "Image". Lo que va a hacer que se me habiliten las opciones Compress data, Format image data y Format palette data.
-Yo quiero agregar como recurso la informacion de la imagen, comprimida, así que dejo tildado Compress data e Format image data. Y destildo Format palette data.
-En donde dice Resource name, pongo el nombre con el que me voy a referir al recurso. Yo le puse tileset.
-Le doy a Add Resource. Y con eso apareció en el panel de la derecha el nombre "tileset_img" (o el nombre que le hayan puesto).
-Como con la imagen sola no hago nada ahora hay que importar la paleta. Destildo las opciones Compress data (porque una paleta es muy chica literalmente ocupa más espacio si la intentamos comprimir a si la dejamos como está) y Format image data (porque ya agregamos la imagen); y tildamos Format palette data.
-Add Resource y debería aparecer "tileset_pal" en el panel de la derecha.
-Ya agregamos los datos de la imagen, falta la raw. Apretamos Load File y abrimos la raw que hicimos hace un rato.
-Ahora cambiamos la opcion de Image a Raw y esto debería inhabilitar la opciones relacionadas a la imagen y a paleta.
-Tildamos Compress data y le damos a Add Resource. Debería aparecer "tileset_raw" en el panel de la derecha.
-Finalmente apretamos Save Header.
-Buscamos la carpeta "src" de la plantilla y dentro de la carpeta "resources" que está dentro de la misma, grabamos el archivo con el nombre que quieran (siempre y cuando termine en ".h"), yo lo voy a guardar como "tileset.h".
Con eso ya terminamos la parte de los recursos.
Esta va a ser mi imagen:
Ahora lo que sigue se los dejo a ustedes. Obtengan un tileset y una raw. Yo usé sphere.
Una vez tengan las dos cosas vamos a abrir la carpeta de la plantilla y vamos a entrar a la carpeta tools de la plantilla. Allí ejecuten el archivo main_iu.py con python. Para esto van a necesitar tener instalados los módulos: sip, PyQt5 y Pillow.
Los que no tengan idea de que es lo que acabo de decir, descarguen esto y hagan doble click en main.exe
Bueno, en estos momentos deberían de ver este programa que hice:
Es básicamente una herramienta que sirve para transformar los recursos a algo que el compilador de C entienda, podrían tranquilamente insertar las recursos al rom de la forma que están acostumbrados y usar el puntero de la mismas para referirse a ellas. Pero este modo me parece que es mucho mejor. Además así los mismos no se insertan al rom hasta que se inserte la intro completa, por lo que si cambian alguno no desperdician nada de espacio.
Me parece que la herramienta es bastante intuitiva. Lo que tiene que hacer es abrir el archivo que quiera insertar, elegir lo que quieren sacar de ello y agregarlo al header. Y finalmente le dan a guardar.
Yo lo que voy a hacer es:
-Cargar la imagen de mi tileset indexado.
-Selecciono la opción "Image". Lo que va a hacer que se me habiliten las opciones Compress data, Format image data y Format palette data.
-Yo quiero agregar como recurso la informacion de la imagen, comprimida, así que dejo tildado Compress data e Format image data. Y destildo Format palette data.
-En donde dice Resource name, pongo el nombre con el que me voy a referir al recurso. Yo le puse tileset.
-Le doy a Add Resource. Y con eso apareció en el panel de la derecha el nombre "tileset_img" (o el nombre que le hayan puesto).
-Como con la imagen sola no hago nada ahora hay que importar la paleta. Destildo las opciones Compress data (porque una paleta es muy chica literalmente ocupa más espacio si la intentamos comprimir a si la dejamos como está) y Format image data (porque ya agregamos la imagen); y tildamos Format palette data.
-Add Resource y debería aparecer "tileset_pal" en el panel de la derecha.
-Ya agregamos los datos de la imagen, falta la raw. Apretamos Load File y abrimos la raw que hicimos hace un rato.
-Ahora cambiamos la opcion de Image a Raw y esto debería inhabilitar la opciones relacionadas a la imagen y a paleta.
-Tildamos Compress data y le damos a Add Resource. Debería aparecer "tileset_raw" en el panel de la derecha.
-Finalmente apretamos Save Header.
-Buscamos la carpeta "src" de la plantilla y dentro de la carpeta "resources" que está dentro de la misma, grabamos el archivo con el nombre que quieran (siempre y cuando termine en ".h"), yo lo voy a guardar como "tileset.h".
Con eso ya terminamos la parte de los recursos.
Con notepad++ (o el editor de texto que usen) habran el archivo intro.c que está dentro de la carpeta src de la plantilla. Deberían de ver esto:
Vamos a borrar la parte que dice"// Do something" y la parte de "else if (...) {...}". Tal que:
Ahora, abajo de donde dice '#include "headers/important.h"', vamos a escribir '#include "resourcers/tileset.h"' (el nombre del archivo que creamos hace un rato).
Gracias a eso, podemos usar los recursos que acabamos de preparar.
Lo primero que vamos a hacer es cargar la paleta. En este hola mundo vamos a usar los bg's. Para cargar una paleta de los bg's debemos usar la función load_bg_pal.
Cuando yo hice mi raw, puse que todo el tileset use la paleta 0 (si ustedes no modificaron nada, también, es el valor por defecto), así que tengo que cargar mi paleta en esa posición. El nombre que yo le di a la paleta es "tileset_pal", así que debería pasar eso como argumento; PERO lo que necesita la función es el puntero de la paleta, así que debo decirle "&tileset_pal" ("&" es la forma de decirle a C, "dame el puntero de esta cosa"). Y finalmente debo decirle a la función si mi paleta esta comrpimida o no, la mía no lo está así que le digo "false", si la de ustedes si lo está porque son muy malotes y no siguen mi tutorial, pongan "true".
Así que resumiendo, dentro de las llaves del "if" ponemos: "load_bg_pal(0, &tileset_pal, false);". Tal que:
Ya casi está. Ahora lo que viene es cargar los datos de la imagen. Para esto vamos a udar la funcion "load_bg_data". Esta función necesita que le digamos el número de bg donde cargar la imagen (en este caso pueden usar cualquier número del 0 al 3, yo voy a usar el 3, que es el del fondo). Y luego necesitamos parle tanto el puntero del tileset, como el de la raw; o sea, "&tileset_img" y "&tileset_raw" respectívamente.
Resumiendo, después de load_bg_pal escribimos: "load_bg_data(3, &tileset_img, &tileset_raw);". Tal que:
Guardamos los cambios.
¡Y con esto el código está listo!
Código:
#include "headers/important.h"
bool intro_main()
{
if (get_time() == 0) {
// Do something
} else if (get_time() < 2 * SECOND) {
//Do more things
}
if (key_down(KEY_A | KEY_B | KEY_START) || get_time() == 20 * SECOND)
{
return true;
}
inc_timer();
return false;
}
Vamos a borrar la parte que dice"// Do something" y la parte de "else if (...) {...}". Tal que:
Código:
#include "headers/important.h"
bool intro_main()
{
if (get_time() == 0) {
}
if (key_down(KEY_A | KEY_B | KEY_START) || get_time() == 20 * SECOND)
{
return true;
}
inc_timer();
return false;
}
Ahora, abajo de donde dice '#include "headers/important.h"', vamos a escribir '#include "resourcers/tileset.h"' (el nombre del archivo que creamos hace un rato).
Código:
#include "headers/important.h"
#include "resourcers/tileset.h"
bool intro_main()
{
if (get_time() == 0) {
}
if (key_down(KEY_A | KEY_B | KEY_START) || get_time() == 20 * SECOND)
{
return true;
}
inc_timer();
return false;
}
Gracias a eso, podemos usar los recursos que acabamos de preparar.
Lo primero que vamos a hacer es cargar la paleta. En este hola mundo vamos a usar los bg's. Para cargar una paleta de los bg's debemos usar la función load_bg_pal.
Cuando yo hice mi raw, puse que todo el tileset use la paleta 0 (si ustedes no modificaron nada, también, es el valor por defecto), así que tengo que cargar mi paleta en esa posición. El nombre que yo le di a la paleta es "tileset_pal", así que debería pasar eso como argumento; PERO lo que necesita la función es el puntero de la paleta, así que debo decirle "&tileset_pal" ("&" es la forma de decirle a C, "dame el puntero de esta cosa"). Y finalmente debo decirle a la función si mi paleta esta comrpimida o no, la mía no lo está así que le digo "false", si la de ustedes si lo está porque son muy malotes y no siguen mi tutorial, pongan "true".
Así que resumiendo, dentro de las llaves del "if" ponemos: "load_bg_pal(0, &tileset_pal, false);". Tal que:
Código:
#include "headers/important.h"
#include "resourcers/tileset.h"
bool intro_main()
{
if (get_time() == 0) {
load_bg_pal(0, &tileset_pal, false);
}
if (key_down(KEY_A | KEY_B | KEY_START) || get_time() == 20 * SECOND)
{
return true;
}
inc_timer();
return false;
}
Ya casi está. Ahora lo que viene es cargar los datos de la imagen. Para esto vamos a udar la funcion "load_bg_data". Esta función necesita que le digamos el número de bg donde cargar la imagen (en este caso pueden usar cualquier número del 0 al 3, yo voy a usar el 3, que es el del fondo). Y luego necesitamos parle tanto el puntero del tileset, como el de la raw; o sea, "&tileset_img" y "&tileset_raw" respectívamente.
Resumiendo, después de load_bg_pal escribimos: "load_bg_data(3, &tileset_img, &tileset_raw);". Tal que:
Código:
#include "headers/important.h"
#include "resourcers/tileset.h"
bool intro_main()
{
if (get_time() == 0) {
load_bg_pal(0, &tileset_pal, false);
load_bg_data(3, &tileset_img, &tileset_raw);
}
if (key_down(KEY_A | KEY_B | KEY_START) || get_time() == 20 * SECOND)
{
return true;
}
inc_timer();
return false;
}
¡Y con esto el código está listo!
Agregamos un rom limpio de FR (o emerald) en la carpeta de nuestra plantilla, con el nombre de "BPRE.gba" (o "BPEE.gba" si usas emerald). Copiamos la ruta de la carpeta de la plantilla ("C:\ruta\a\la\plantilla\pokemon-intro-template"; y como dije antes deben cambiar las barras pra que funcione en cygwin: "C:/ruta/a/la/plantilla/pokemon-intro-template"). Y abrimos cygwin.
En cygwin escribimos 'cd "C:/ruta/a/la/plantilla/pokemon-intro-template" ', le damos enter. Y ahora escribimos "make" (o en el caso de emerald, "make ROM_CODE=BPEE") y tambien le damos enter.
Van a salir unos mensajes de compilación y cuando termine, en la carpeta de la plantilla debería de haber una carpeta llamada "build/BPRE" (o "build/BPEE" con un rom llamado "rom.gba", lo abrimos con el emulador y...
Felicidades, acaban de hacer su primer intro.
En cygwin escribimos 'cd "C:/ruta/a/la/plantilla/pokemon-intro-template" ', le damos enter. Y ahora escribimos "make" (o en el caso de emerald, "make ROM_CODE=BPEE") y tambien le damos enter.
Van a salir unos mensajes de compilación y cuando termine, en la carpeta de la plantilla debería de haber una carpeta llamada "build/BPRE" (o "build/BPEE" con un rom llamado "rom.gba", lo abrimos con el emulador y...
Felicidades, acaban de hacer su primer intro.
Yo configuré los bg's para que los 4 estén activados, que todos tengan un tamaño de 256x256 y que su posición inicial sea en la esquina superior izquierda.
Si ustedes quieren modificarlo, vean el archivo "bg_utils.c".
Por defecto la intro se inserta en la direccion 0xef0000. Para cambiar la misma simplemente abran el archivo "main.s" y cambien la línea que dice ".org 0x08ef0000" por la dirección en donde quieran insertar la intro. (Si la quieren insertar en 0x1954A10, pongan ".org 0x09954A10"
Si ustedes quieren modificarlo, vean el archivo "bg_utils.c".
Por defecto la intro se inserta en la direccion 0xef0000. Para cambiar la misma simplemente abran el archivo "main.s" y cambien la línea que dice ".org 0x08ef0000" por la dirección en donde quieran insertar la intro. (Si la quieren insertar en 0x1954A10, pongan ".org 0x09954A10"
Una vez hayan terminado con el hola mundo, lo que deberían hacer es ponerse a probar las diferentes funciones que dejo más abajo, total no pierden nada con probar.
La intro se inserta en unos pocos segundos y con un simple parche podrían volver todo a la normalidad. E incluso si son tontos y no hacen un parche, esto no borra el rom anterior sino que crea uno nuevo.
Así que mientras no inserten la intro en algún lugar que sobreescriba algo y por sobre todo borren el rom BPRE.gba, no deberían de tener ningún problema.
También lo que pueden hacer es ver la intro que subí de ejemplo al principio. Ahí básciamente hago de todo, cambio la música, cambio los gráficos de los bg en el medio de la secuencia, uso sprites, muevo sprites, uso animaciones, uso variables, y ya ni me acuerdo si hacía algo más.
Pero el código sigue siendo bastante corto. Aunque no sé si lo hice muy legible... Si no se entiende nada avisen y algún día que tenga tiempo le agrego explicaciones.
SECOND
Es el valor equivalente a un segundo con respecto al reloj. 2 * SECOND sería equivalente a dos segundos. 3 * SECOND a tres... (Esto no es una función, pero no voy a crear una sección nueva por una palabra)
get_time()
Da el valor actual del reloj.
inc_timer()
Incrementa en 1 el reloj.
set_timer(value)
Cambia el valor del reloj.
value: nuevo valor del reloj.
get_var(var_num)
Da el valor de la variable ingresada.
var_num: número de variable.
set_var(var_num, value)
Cambia el valor de una variable.
var_num: número de variable.
value: nuevo valor de la variable.
fadescreen()
Oscurece la pantalla hasta quedar completamente en negro.
fadescreen_white()
Aclara la pantalla hasta quedar completamente en blanco.
unfadescreen()
Deshace el efecto de fadescreen() y fadescreen_white(). Si las mismas no fueron usadas anteriormente, hace un efecto de flash blanco en la pantalla.
key_down(key)
Equivalente a true si se está presionando la tecla ingresada. Equivalente false en caso contrario.
key: nombre de la tecla.
Lista de teclas:
KEY_A
KEY_B
KEY_SELECT
KEY_START
KEY_RIGHT
KEY_LEFT
KEY_UP
KEY_DOWN
KEY_L
KEY_R
key(KEY_A | KEY_B | KEY_START) devolverá true si cualquiera de las teclas A, B y START esta siendo presiondada.
(key(KEY_A) && key(KEY_B) && key(KEY_START)) devolverá verdadero sólo si las tres teclas estan siendo presionadas a la vez.
Es el valor equivalente a un segundo con respecto al reloj. 2 * SECOND sería equivalente a dos segundos. 3 * SECOND a tres... (Esto no es una función, pero no voy a crear una sección nueva por una palabra)
get_time()
Da el valor actual del reloj.
inc_timer()
Incrementa en 1 el reloj.
set_timer(value)
Cambia el valor del reloj.
value: nuevo valor del reloj.
get_var(var_num)
Da el valor de la variable ingresada.
var_num: número de variable.
set_var(var_num, value)
Cambia el valor de una variable.
var_num: número de variable.
value: nuevo valor de la variable.
fadescreen()
Oscurece la pantalla hasta quedar completamente en negro.
fadescreen_white()
Aclara la pantalla hasta quedar completamente en blanco.
unfadescreen()
Deshace el efecto de fadescreen() y fadescreen_white(). Si las mismas no fueron usadas anteriormente, hace un efecto de flash blanco en la pantalla.
key_down(key)
Equivalente a true si se está presionando la tecla ingresada. Equivalente false en caso contrario.
key: nombre de la tecla.
Lista de teclas:
KEY_A
KEY_B
KEY_SELECT
KEY_START
KEY_RIGHT
KEY_LEFT
KEY_UP
KEY_DOWN
KEY_L
KEY_R
key(KEY_A | KEY_B | KEY_START) devolverá true si cualquiera de las teclas A, B y START esta siendo presiondada.
(key(KEY_A) && key(KEY_B) && key(KEY_START)) devolverá verdadero sólo si las tres teclas estan siendo presionadas a la vez.
play_song(song_num)
Comienza la canción ingresada.
song_num: número de canción.
fade_song()
Baja el volumen de la canción hasta que se deje de escuchar.
audio_play(sound)
Comienza el sonido ingresado.
sound: número de sonido. (lista)
play_cry(pkmn_num)
Comienza el cry del pokemon ingresado.
pkmn_num: número de pokemon.
Comienza la canción ingresada.
song_num: número de canción.
fade_song()
Baja el volumen de la canción hasta que se deje de escuchar.
audio_play(sound)
Comienza el sonido ingresado.
sound: número de sonido. (lista)
play_cry(pkmn_num)
Comienza el cry del pokemon ingresado.
pkmn_num: número de pokemon.
clear_bgs()
Borra todo el contenido de los background.
load_bg_data(bg_num, tileset, tilemap)
Carga la imagen formada por el tileset y el tilemap en el bg ingresado.
bg_num: número de bg. Valores: 0 a 3
tileset: puntero al tileset (&nombre_del_tileset_img)
tileset: puntero al tilemap (&nombre_del_tilemap_raw)
load_bg_pal(pal_num, palette, is_compressed)
Carga una paleta de los bg's en la posicion ingresada.
pal_num: posicion a cargar la paleta. Valores: 0 a 15
palette: puntero a la paleta (&nombre_de_la_paleta_pal)
is_compressed: ¿está la la paleta comprimida? Valores: true (sí) o false (no)
move_bg(bg_num, x, y)
Mueve un bg con respecto a su posición.
bg_num: número de bg. Valores: 0 a 3
x: movimiento horizontal.
y: movimiento vertical.
Si los valores ingresados son 0, el bg no se moverá horizontalmente/verticalmente. Si los valores son negativos, se moverá hacia la izquierda/arriba. Y si son positivos, hacia la derecha/abajo. Respectivamente para x e y.
toggle_bg_displayed(bg_num)
Si el bg ingresado esta oculto lo muestra. Si no lo está, lo oculta.
bg_num: número de bg. Valores: 0 a 3
Borra todo el contenido de los background.
load_bg_data(bg_num, tileset, tilemap)
Carga la imagen formada por el tileset y el tilemap en el bg ingresado.
bg_num: número de bg. Valores: 0 a 3
tileset: puntero al tileset (&nombre_del_tileset_img)
tileset: puntero al tilemap (&nombre_del_tilemap_raw)
load_bg_pal(pal_num, palette, is_compressed)
Carga una paleta de los bg's en la posicion ingresada.
pal_num: posicion a cargar la paleta. Valores: 0 a 15
palette: puntero a la paleta (&nombre_de_la_paleta_pal)
is_compressed: ¿está la la paleta comprimida? Valores: true (sí) o false (no)
move_bg(bg_num, x, y)
Mueve un bg con respecto a su posición.
bg_num: número de bg. Valores: 0 a 3
x: movimiento horizontal.
y: movimiento vertical.
Si los valores ingresados son 0, el bg no se moverá horizontalmente/verticalmente. Si los valores son negativos, se moverá hacia la izquierda/arriba. Y si son positivos, hacia la derecha/abajo. Respectivamente para x e y.
toggle_bg_displayed(bg_num)
Si el bg ingresado esta oculto lo muestra. Si no lo está, lo oculta.
bg_num: número de bg. Valores: 0 a 3
load_sprite_pal(palette, tag, is_compressed)
Carga a la paleta de sprites solicitada.
palette: puntero a la paleta (&nombre_de_la_paleta_pal).
tag: un número identificador para la paleta (no es la posicion en donde se cargará).
is_compressed: ¿está la la paleta comprimida? Valores: true (sí) o false (no).
load_sprite(oam_data, graphics, sprite_num, pal_tag, frame_amount, animation_table)
oam_data: puntero a un OamData (ver a continuación) (&nombre_del_oam_data).
graphics: puntero a las imagenes del sprite (debe estar comprimido).
sprite_num: número identifiacdor del sprite. Valores: de 0 a 127.
pal_tag: número identificador de la paleta que usará el sprite.
frame_amount: cantidad de frames que tiene el sprite en total (sin importar si los utiliza o no).
animation_table: puntero a la tabla de animaciones del sprite (ver a continuación) (&nombre_de_la_tabla_de_animaciones). Si el sprite no es animado poner: SPRITE_NO_ANIMATION
Para definir un OamData se debe escribir lo siguiente, ANTES de la funcion intro_main() y remplazando los valores después del signo "=" y antes de la coma por los valores deseados:
x: posición horizontal del sprite.
y: posición vertical del sprite.
affine_mode: dejar siempre en 0.
h_flip: si es 1 refleja el sprite horizontalmente. (no funciona con sprites animados)
v_flip: si es 1 refleja el sprite verticalmente. (no funciona con sprites animados)
size: tamaño del sprite. Puede ser SIZE_8x8, SIZE_16x16, SIZE_32x32 y SIZE_64x64.
Definiendo una tabla de animaciones se puede hacer que un sprite cambie de frames automáticamente. Para definir una tabla de animaciones hay que escribir los siguiente ANTES de la funcion intro_main():
Siendo "nombre_de_la_tabla_de_animaciones" la tabla de animaciones y, animacion_1 y animación_vacía, sus entradas. Las entradas tiene el formato provisto, siendo las llaves internas, la informacion de la animacion (número de tile, tiempo, espejado horizontal, espejado vertical). La animacion_0 mostrará el frame 0 del sprite durante un tiempo de 16 (el mismo no está espejado ni horizontal, ni verticalmente), luego el frame 1 durante un tiempo de 25 (está espejado verticalmente) y la expresion {FRAME_LOOP, 0} indica que la animación funcionará en bucle. En caso de que se use la expresión {FRAME_END, 0} la animacion del sprite terminará. La llaves de dentro de las animaciones deben estar separadas por coma.
Dentro de la tabla de animaciones van los nombres de las animaciones separados por coma.
Por defecto un sprite empezará con la primera animación de la tabla (en este caso, animacion_0).
start_sprite_animation(sprite_num, anim_num)
Inicia la animación de la tabla solicitada.
sprite_num: número del sprite al que se le iniciará la animación.
anim_num: número de animación a iniciar. Teniendo en cuenta el ejemplo anterior, si se ingresa el número 1 el sprite detendrá su animación.
move_sprite(sprite_num, x, y)
Cambia la posición de un sprite.
sprite_num: número del sprite.
x: movimiento horizontal.
y: movimiento vertical.
Si los valores ingresados son 0, el sprite no se moverá horizontalmente/verticalmente. Si los valores son negativos, se moverá hacia la izquierda/arriba. Y si son positivos, hacia la derecha/abajo. Respectivamente para x e y.
change_sprite_frame(sprite_num, frame)
Cambia el frame del sprite ingresado.
frame: nuevo frame, CALCULADO CON RESPECTO AL FRAME ACTUAL, si el un valor negativo retrocederá frames, si es positivo avanzará frames, si es cero no producirá ningún cambio. No funciona con sprites animados.
sprite_num: número del sprite.
toggle_hflip(sprite_num)
Espeja el sprite horizontalmente. No funciona con sprites animados.
sprite_num: número del sprite.
toggle_vflip(sprite_num)
Espeja el sprite verticalmente. No funciona con sprites animados.
sprite_num: número del sprite.
delete_sprite(sprite_num)
Borra un sprite cargado.
sprite_num: número del sprite.
change_sprite_pal(new_pal_tag, sprite_num)
Cambia la paleta de un sprite.
new_pal_tag: número identificador de la paleta.
sprite_num: número del sprite.
Carga a la paleta de sprites solicitada.
palette: puntero a la paleta (&nombre_de_la_paleta_pal).
tag: un número identificador para la paleta (no es la posicion en donde se cargará).
is_compressed: ¿está la la paleta comprimida? Valores: true (sí) o false (no).
load_sprite(oam_data, graphics, sprite_num, pal_tag, frame_amount, animation_table)
oam_data: puntero a un OamData (ver a continuación) (&nombre_del_oam_data).
graphics: puntero a las imagenes del sprite (debe estar comprimido).
sprite_num: número identifiacdor del sprite. Valores: de 0 a 127.
pal_tag: número identificador de la paleta que usará el sprite.
frame_amount: cantidad de frames que tiene el sprite en total (sin importar si los utiliza o no).
animation_table: puntero a la tabla de animaciones del sprite (ver a continuación) (&nombre_de_la_tabla_de_animaciones). Si el sprite no es animado poner: SPRITE_NO_ANIMATION
Para definir un OamData se debe escribir lo siguiente, ANTES de la funcion intro_main() y remplazando los valores después del signo "=" y antes de la coma por los valores deseados:
Código:
const struct OamData [I]nombre_del_oam_data[/I] = {
.x = 196,
.y = 64,
.affine_mode = 0,
.priority = 0,
.h_flip = 0,
.v_flip = 0,
.size = SIZE_32x32,
};
y: posición vertical del sprite.
affine_mode: dejar siempre en 0.
h_flip: si es 1 refleja el sprite horizontalmente. (no funciona con sprites animados)
v_flip: si es 1 refleja el sprite verticalmente. (no funciona con sprites animados)
size: tamaño del sprite. Puede ser SIZE_8x8, SIZE_16x16, SIZE_32x32 y SIZE_64x64.
Definiendo una tabla de animaciones se puede hacer que un sprite cambie de frames automáticamente. Para definir una tabla de animaciones hay que escribir los siguiente ANTES de la funcion intro_main():
Código:
const struct Frame [I]animacion_0[/I][] = {
{0 * FRAME_32x32, 16, 0, 0},
{1 * FRAME_32x32, 25, 0, 1},
{FRAME_LOOP, 0}
};
const struct Frame [I]animacion_vacía[/I][] = {
{FRAME_END, 0}
};
const struct Frame * [I]nombre_de_la_tabla_de_animaciones[/I][] = {
[I]animacion_0[/I],
[I]animación_vacía[/I],
};
Dentro de la tabla de animaciones van los nombres de las animaciones separados por coma.
Por defecto un sprite empezará con la primera animación de la tabla (en este caso, animacion_0).
start_sprite_animation(sprite_num, anim_num)
Inicia la animación de la tabla solicitada.
sprite_num: número del sprite al que se le iniciará la animación.
anim_num: número de animación a iniciar. Teniendo en cuenta el ejemplo anterior, si se ingresa el número 1 el sprite detendrá su animación.
move_sprite(sprite_num, x, y)
Cambia la posición de un sprite.
sprite_num: número del sprite.
x: movimiento horizontal.
y: movimiento vertical.
Si los valores ingresados son 0, el sprite no se moverá horizontalmente/verticalmente. Si los valores son negativos, se moverá hacia la izquierda/arriba. Y si son positivos, hacia la derecha/abajo. Respectivamente para x e y.
change_sprite_frame(sprite_num, frame)
Cambia el frame del sprite ingresado.
frame: nuevo frame, CALCULADO CON RESPECTO AL FRAME ACTUAL, si el un valor negativo retrocederá frames, si es positivo avanzará frames, si es cero no producirá ningún cambio. No funciona con sprites animados.
sprite_num: número del sprite.
toggle_hflip(sprite_num)
Espeja el sprite horizontalmente. No funciona con sprites animados.
sprite_num: número del sprite.
toggle_vflip(sprite_num)
Espeja el sprite verticalmente. No funciona con sprites animados.
sprite_num: número del sprite.
delete_sprite(sprite_num)
Borra un sprite cargado.
sprite_num: número del sprite.
change_sprite_pal(new_pal_tag, sprite_num)
Cambia la paleta de un sprite.
new_pal_tag: número identificador de la paleta.
sprite_num: número del sprite.
Créditos y agradecimientos:
- Shiny Quagsire
- Touched
- FBI
- knizz
- cosarara97
- Nintenlord
- Samu
- Touched
- FBI
- knizz
- cosarara97
- Nintenlord
- Samu
Bueno eso, sería todo. Cualquier problema/recomendación, no duden en postearlo. Y si alguien quiere hacer tutoriales más específicos sobre esto, los invito a que los hagan.
Saludos.
Última edición: