Registrarse

[C] FR, E | Creando una introducción personalizada

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.

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 :D

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:
Código:
expresión1; expresión2;
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ódigo:
expresión1; 
expresión2;
C ignora los saltos de línea, los espacios y las tabulaciones. Acomoden el código como les sea más facil comprenderlo.

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").

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):
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:

Código:
if ( "condición" ) {
	funcion();
}
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:
Código:
if ( 4 < 5 ) {
	funcion();
}
Mientras que esto, no:
Código:
if ( ((4 + 5) > 8) && (4 == 5) ) {
	funcion();
}
(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.


Hay veces que dependiendo de una condición queremos hacer o una cosa u otra. Para eso existen los if...else

Código:
if ( "condición" ) {
	funcion1();
} else {
	funcion2();
	funcion3();
}
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.

Y por si la cosa es todavía más complicada, podemos hacer cosas como esto.

Código:
if ( "condición1" ) {
	funcion1();
} else if ( "condicion2" ) {
	funcion2();
} else if ( "condicion3" ) {
	funcion3();
} else {
	funcion4();
}
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.

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:
Código:
#define ID_SPRITE_BULBASAUR 1
#define ID_PALETA_BULBASAR 7
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.

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.


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:
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;
}
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:
Código:
    if (get_time() == 0) {
            // Do something
    } else if (get_time() < 2 * SECOND) {
        //Do more things
    }
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é :D
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();
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).
Código:
    if (key_down(KEY_A | KEY_B | KEY_START) || get_time() == 20 * SECOND)
    {
        return true;
    }
Y finalmente esto:
Código:
	return false;
Es lo opuesto a return true, le dice al juego que la intro todavía continua.


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 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.


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:

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;
}
Guardamos los cambios.
¡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.

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"

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.

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.

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

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:

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, 
};
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():

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],
};
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.


Créditos y agradecimientos:
- Shiny Quagsire
- 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.

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.
 
Última edición:

Omega

For endless fight
Miembro del equipo
Moderador/a
Respuesta: [FR] Creando una introducción personalizada

Aportazo!!!
Puedes apostar que lo probare HOY mismo, solo espero no hacerme lio con C que soy nuevo en esa area.

Gracias! :boogie:
 

Kaiser de Emperana

Called in hand
Respuesta: [FR] Creando una introducción personalizada

Ωmega;390257 dijo:
Aportazo!!!
Puedes apostar que lo probare HOY mismo, solo espero no hacerme lio con C que soy nuevo en esa area.

Gracias! :boogie:
Mi objetivo era que el tuto tenga lo menos que ver con programación posible. No vas a hacer practicamente nada de C, simplemente seguir la sintaxis un poco (que básicament es separar las cosas por punto y coma, no es que sea muy complicado xD).
O sea, obviamente lo podrías hacer, pero me encargué de que se puedan hacer las cosas importantes con simplemente una o dos líneas de código.

Por eso es que no expliqué ni bucles, ni tipos, ni funciones, ni nada.

Como digo en el tuto, el escribir el código es hasta más facil que hacer un script. Si se quiere, lo dificil sería el pensar como se puede hacer la cinemática :p
 

Katherine

Omnipresente
Miembro de honor
Respuesta: [FR] Creando una introducción personalizada

Grandísimo tutorial, súper bien explicado y con unas clases de programación muy básica incluidas, todo en uno xD. Encima con el detalle de funciones predefinidas para simplificarlo todavía más.
Se agradece mucho. Si a alguien más que usarlo, quiere aprender como hacer esto por uno mismo tan solo puede ver como está hecha esta plantilla (lo ideal sería saber C orientado a RH antes de eso).

¡Muchas gracias! Miau revoir~.
 

Bugrhak

A long time ago I used to call myself "Subzero".
Respuesta: [FR] Creando una introducción personalizada

Ufff esto está realmente excelente!
Hace mucho buscaba algo así, o por lo menos quitar la intro esa que viene en los juegos de pokémon.
Esto es sin duda por lejos mejor, me encanta! :D
Muy muy bueno!
 

L!no

GBA Developer
Respuesta: [FR] Creando una introducción personalizada

Uff men que aportazo!
Lamento no poder usarlo hoy pero estoy de viaje, y me acabas de simplificar la vida con el compilador de código C a ASM. me servirá muchísimo.

Enviado desde mi SM-G313ML mediante Tapatalk
 

Kaiser de Emperana

Called in hand
Respuesta: [FR] Creando una introducción personalizada

Uff men que aportazo!
Lamento no poder usarlo hoy pero estoy de viaje, y me acabas de simplificar la vida con el compilador de código C a ASM. me servirá muchísimo.
Creo que simplemente te expresaste mal, pero por las dudas lo comento xD
El compilador no te va a dar un código en assembler, sino que te va a dar un binario directamente. Pero si te interesa tener algo similar a un código fuente en assembler, ya sea para debuggear, para ver como se compiló alguna función o lo que sea que quieras.
Estando en el directorio de la plantilla, podés ejecutar este comando para sacar algo similar a un código en assembler:
Código:
arm-none-eabi-objdump -d build/linked.o > dis.txt
Así te va a aparecer un archivo "dis.txt" que tiene el código en assembler y las direcciones en donde se insertaría.
 
Última edición:

pikachu240

Junior C# Developer
Respuesta: [FR] Creando una introducción personalizada

Es muy interesante, la verdad es que cuando vi que se hacia en c me quede un poco D: (cuando vi el de ShinyQuagsire)y eso que soy programador xD la verdad es que cuando pienso en un programa no pienso en una intro es por eso que me tira pa'tras si me dijeras un programa para hacer intros luego ya hablariamos el mismo idioma :D

En un futuro me gustaría hacer ese programa si logro entender como va xD (si me ayudas iré más rápido)

por cierto como pasas de c a bin?

pd:Entiendo que una intro pueda ser un programa pero me mola pensar más en un programa para hacer intros :)

pd2:Me gusta tu aporte aunque a priori me eche atrás con el c
 

jiangzhengwenjz

Usuario mítico
Re: [FR] Creando una introducción personalizada

My repo should be useful:

https://github.com/jiangzhengwenjz/HeartGold_anime


It's a demake of heartgold intro.
What you need is devkitARM, armips, make, a 'build' folder and bpre0.gba in a 'base' folder.

It's a semi-manufactured project, so don't try to use it in your hack, as many parts are not done, and will never be done. Just learn from the codes.

My way to modify the intro is quite different from the master Shiny Quagsire's, as I mostly inherits the way in which the original game did the intro.
 
Última edición:

H.B.P

Emperador Kaktiácero
Miembro de honor
Respuesta: [FR] Creando una introducción personalizada

Un tutorial muy bien explicado y organizado, el curro es admirable, es una pena que aún se requiera un nivel mínimo de programación en C para no perderse, pero lo has simplificado lo mejor que pudiste. Aparte de utilizarlo en la introducción, sería muy tentador utilizar algo como ésto dentro de la propia partida.

Special thanks to @jiangzhengwenjz, he's as colaborative and nice as always!
 

kakarotto

Leyenda de WaH
Re: [FR] Creando una introducción personalizada

Es un aportazo interesantisimo, solo me queda decirte que chapeau!

Pd: podria adaptarse a emerald??
 

Lunos

Enfrentando a La Organización
Miembro insignia
Re: [FR] Creando una introducción personalizada

My repo should be useful:
https://github.com/jiangzhengwenjz/HeartGold_anime
It's a demake of heartgold intro.
What you need is devkitARM, armips, make, a 'build' folder and bpre0.gba!
Aclaración: Para poder probar el codigo de jiang en su estado actual, se debe modificar la ruta hacia la ROM bpre0.gba en el archivo insertion.asm, Linea 5. Por cierto, aqui una demostración.

ON: Ya dejé mi like apenas lo vi, como tal me parece impresionante ver una pieza de codigo en C que solo esté aqui en Wahack. Sin embargo, podria estar bien postearlo en PokeCommunity en algun punto.

En cualquier caso, gran trabajo Kaiser, luce sencillo de usar y tiene pinta de que se pueden crear escenas muy interesantes.
 

Kaiser de Emperana

Called in hand
Respuesta: Re: [FR] Creando una introducción personalizada

La intro de jiangzhengwenjz es muy buen aporte para los que se quieran adentrar un poco más en el C hacking. Pero les aviso que los que no sepan programar en C y lo único que hayan hecho es seguir mi tuto. No van a entender absolutamente nada de lo que el hizo.
De todos modos les invito a que la vean.


Es muy interesante, la verdad es que cuando vi que se hacia en c me quede un poco D: (cuando vi el de ShinyQuagsire)y eso que soy programador xD la verdad es que cuando pienso en un programa no pienso en una intro es por eso que me tira pa'tras si me dijeras un programa para hacer intros luego ya hablariamos el mismo idioma :D

En un futuro me gustaría hacer ese programa si logro entender como va xD (si me ayudas iré más rápido)

por cierto como pasas de c a bin?

pd:Entiendo que una intro pueda ser un programa pero me mola pensar más en un programa para hacer intros :)

pd2:Me gusta tu aporte aunque a priori me eche atrás con el c
He de preguntarte. ¿Cómo pensás que se haría una intro sin programar? xD
A mí se me ocurren dos formas: importando un video y programando una animación. El primero en gba es como medio demente por la cantidad de espacio que ocuparía y por la limitación de 256 colores, estaría genial que alguien lo haga, pero medio complicado (además que para hacer el video, salvo que te quiera poner a vos en la piscina como intro, tendrías que hacer la animación primero). Y la segunda es lo que estamos haciendo, un guión de lo que pasa en la intro (cargar imagen, comenzar a reproducir la música, aclarar la pantalla, cargar otra imagen, cambiar el frame de una imagen, mover una imagen,..)
Hacer un programa ue haga una intro... Y... Más que hacer una especie de interfaz para escribir el código apretando botones, como en RPG Maker, mucho más no creo que se pueda hacer.
Si te interesa ver como propuse yo hacerlo arriba tenes mi tuto que creo que tiene todo bastante bien explicado. Y si tenes una duda más puntual no dudes en preguntarme

Sobre como se obtiene el bin desde C, con las herramientas de devkitARM. En realidad el proceso es el mismo que se hace para los programas de computadora.
El compilador (gcc) genera un object file desde el código fuente en C. El ensamblador (as) hace lo mismo pero con el código en assembler. El linker (ld) junta todos los object files en la dirección de rom que le especifiques y te da otro object file más definitivo.
Y después con objcopy podrías tranformar el object file ya en un binario e insertarlo en el rom con un editor hexadecimal.

En esta plantilla yo usé armips, que es un porgrama que no se del todo como es que funciona. Pero básicamente es un ensamblador que hace la parte del objcopy y lo inserta en el rom directamente. No hace nada que no podríamos hacer sin el, pero ahorra trabajo.


★★Helix Boo★★;390314 dijo:
Un tutorial muy bien explicado y organizado, el curro es admirable, es una pena que aún se requiera un nivel mínimo de programación en C para no perderse, pero lo has simplificado lo mejor que pudiste. Aparte de utilizarlo en la introducción, sería muy tentador utilizar algo como ésto dentro de la propia partida.

Special thanks to @jiangzhengwenjz, he's as colaborative and nice as always!
No denigren la programación en C con mi tutorial y no hagan parecer esto dificil mencionando programación en C xD
Para los que sigan sin creerme, pueden ver el código de la intro de jiangzhengwenjz y compararlo con el que expliqué yo. El programó la intro, yo preparé un sistema para que puedan hacer todo como si se tratase de un script, escribiendo un conjunto de líneas que cada una hace una cosa determinada. En mi tuto no menciono siquiera variables xD

Sobre lo de usarlo para otras cosas. Lo van a poder hacer, pero van a tener que investigar (o preguntarme / postear una duda) un par de cosas. Ya que, por ejemplo, para hacer un menú personalizado, hay que tener en cuenta otras cosas.

Es un aportazo interesantisimo, solo me queda decirte que chapeau!

Pd: podria adaptarse a emerald??
La respuesta es sí, pero debería de ver unas cosas. La razón por la que usé FR es porque en cuanto a documentación de las funciones del rom está más completo.
En principio creo que cambiar los offsets de los BPEE.ld debería de bastar. Cuando tenga más tiempo voy a intentar pasarlo a emerald.

Aclaración: Para poder probar el codigo de jiang en su estado actual, se debe modificar la ruta hacia la ROM bpre0.gba en el archivo insertion.asm, Linea 5. Por cierto, aqui una demostración.

ON: Ya dejé mi like apenas lo vi, como tal me parece impresionante ver una pieza de codigo en C que solo esté aqui en Wahack. Sin embargo, podria estar bien postearlo en PokeCommunity en algun punto.

En cualquier caso, gran trabajo Kaiser, luce sencillo de usar y tiene pinta de que se pueden crear escenas muy interesantes.
La única razón por la que no está posteado en pokecommunity es porque tendría que traducirlo y sinceramente me da mucha pereza.
 

jiangzhengwenjz

Usuario mítico
Re: [FR] Creando una introducción personalizada

Aclaración: Para poder probar el codigo de jiang en su estado actual, se debe modificar la ruta hacia la ROM bpre0.gba en el archivo insertion.asm, Linea 5. Por cierto, aqui una demostración.

ON: Ya dejé mi like apenas lo vi, como tal me parece impresionante ver una pieza de codigo en C que solo esté aqui en Wahack. Sin embargo, podria estar bien postearlo en PokeCommunity en algun punto.

En cualquier caso, gran trabajo Kaiser, luce sencillo de usar y tiene pinta de que se pueden crear escenas muy interesantes.
Well done, I've corrected my post. I haven't included a ReadMe file yet, as the repo was created for archive purpose several months ago instead of sharing. (The reason is that it's soooooo ugly- -, and the semi-manufactured project is not useful in any situation)
 
Última edición:

Kariago

hackrom novato
Respuesta: [FR] Creando una introducción personalizada

Uno de los mejores aportes que he visto!!! Muchas felicidades y muchas gracias por compartir con nosotros este gran tutorial!!! :D Sin duda me será de mucha ayuda ¡Gracias totales!
 

pikachu240

Junior C# Developer
Respuesta: [FR] Creando una introducción personalizada

Me interesa eso de hacer rutinas asm con c creo que es un paso importante para desarrollar juegos chulos :) porque no es lo mismo un lenguaje de alto nivel que es comprensible por las personas que uno de bajo como el asm que ese lo entiende solo los que estan muy metidos en el tema del rom hacking.

Sobre como se podria hacer quizás e podria hacer fotograma por fotograma moviendo poco a poco los sprites creando movimiento de forma visual y simple...ya pondre alguna propuesta mas seria en forma de app :) necesito entender un poco mas como va pero mas o menos tengo una idea :D
 

H.B.P

Emperador Kaktiácero
Miembro de honor
Respuesta: Re: [FR] Creando una introducción personalizada

No denigren la programación en C con mi tutorial y no hagan parecer esto dificil mencionando programación en C xD
Bueno, quizás me he expresado mal, he dicho C más bien a modo de referencia (y diría que éste y Perl son muy básicos), pero más bien hay que tener nociones de programación básica en general, hay aspectos y comandos básicos que no se aprenden con el típico editor de scripts que usa el 98% de la gente, como XSE, y el tema de las variables debería ser la última de nuestras preocupaciones en comparación.
 
Respuesta: [FR] Creando una introducción personalizada

no entendi bien mi pregunta aqui es como animo una sprite porque no le entiendo entendi lo del backgroun pero no se como meter una sprite anima ni que se mueva y en tu tutorial de funciones no lo comprendo mucho porque no se casi nada de c ¿podrias explicarmelo de forma simple? se agradeceria mucho
 

Kaiser de Emperana

Called in hand
Re: Respuesta: [FR] Creando una introducción personalizada

no entendi bien mi pregunta aqui es como animo una sprite porque no le entiendo entendi lo del backgroun pero no se como meter una sprite anima ni que se mueva y en tu tutorial de funciones no lo comprendo mucho porque no se casi nada de c ¿podrias explicarmelo de forma simple? se agradeceria mucho
Por favor, usá signos de puntuación, que se hace complicado el entenderte si escribís de esta forma.

Antes de intentar insertar un sprite animado, lo primero sería el entender como insertar un sprite.
Siguiendo esta parte del tutorial:
Kaiser de Emperana dijo:
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 dafinir un OamData se escribir lo siquiente, 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, 
};
x: posicion horizontal del sprite.
y: posicion 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.
Si entendiste la parte de los background, significa que sabés como insertar recursos. Un ejemplo simple de mostrar un sprite, sería:
Código:
#include "headers/important.h"
#include "resourcers/tileset.h"

const struct OamData [I][COLOR="DarkOrange"]nombre_del_oam_data[/COLOR][/I] = {
    .x = 196, 
    .y = 64,
    .affine_mode = 0,
    .priority = 0,
    .h_flip = 0,
    .v_flip = 0,
    .size = SIZE_32x32, 
};


bool intro_main()
{
    
    if (get_time() == 0) {
        load_sprite_pal(&paleta, [COLOR="Red"]55[/COLOR], true);
        load_sprite(&[I][COLOR="DarkOrange"]nombre_del_oam_data[/COLOR][/I], &imagen_sprite, [COLOR="Blue"]0[/COLOR], [COLOR="Red"]55[/COLOR], 1, SPRITE_NO_ANIMATION);
        
    }
    
    
    if (key_down(KEY_A | KEY_B | KEY_START) || get_time() == 20 * SECOND)
    {
        return true;
    }
    
    inc_timer();
    return false;
}
Siendo 0 y 55 simplemente dos números cualquiera.
¿Así se entiende mejor?

Si me mostrás algo que pruebe que estás intentando hacerlo y no estás preguntando por preguntar, te sigo ayudando; caso contrario, no :)
(No te lo tomes a mal, tan sólo es que da esa sensación, y yo estoy gastando de mi tiempo para ayudarte)

Saludos!
 
Respuesta: Re: Respuesta: [FR] Creando una introducción personalizada

Por favor, usá signos de puntuación, que se hace complicado el entenderte si escribís de esta forma.

Antes de intentar insertar un sprite animado, lo primero sería el entender como insertar un sprite.
Siguiendo esta parte del tutorial:


Si entendiste la parte de los background, significa que sabés como insertar recursos. Un ejemplo simple de mostrar un sprite, sería:
Código:
#include "headers/important.h"
#include "resourcers/tileset.h"

const struct OamData [I][COLOR="DarkOrange"]nombre_del_oam_data[/COLOR][/I] = {
    .x = 196, 
    .y = 64,
    .affine_mode = 0,
    .priority = 0,
    .h_flip = 0,
    .v_flip = 0,
    .size = SIZE_32x32, 
};


bool intro_main()
{
    
    if (get_time() == 0) {
        load_sprite_pal(&paleta, [COLOR="Red"]55[/COLOR], true);
        load_sprite(&[I][COLOR="DarkOrange"]nombre_del_oam_data[/COLOR][/I], &imagen_sprite, [COLOR="Blue"]0[/COLOR], [COLOR="Red"]55[/COLOR], 1, SPRITE_NO_ANIMATION);
        
    }
    
    
    if (key_down(KEY_A | KEY_B | KEY_START) || get_time() == 20 * SECOND)
    {
        return true;
    }
    
    inc_timer();
    return false;
}
Siendo 0 y 55 simplemente dos números cualquiera.
¿Así se entiende mejor?

Si me mostrás algo que pruebe que estás intentando hacerlo y no estás preguntando por preguntar, te sigo ayudando; caso contrario, no :)
(No te lo tomes a mal, tan sólo es que da esa sensación, y yo estoy gastando de mi tiempo para ayudarte)

Saludos!
Creo que sigo sin entender ¿:. mira esto es lo que logre hacer
 
Arriba