Registrarse

[pokeemerald] Animaciones Afines (AffineAnim)

Estado
Cerrado para nuevas respuestas.

Kaktus

Miembro insignia
Miembro insignia
El objetivo de este post es tratar de entender cómo funcionan las animaciones afines de pokeemerald.

Antes que nada, definir el concepto de afinidad. Todos aquellos que hayan tenido dibujo técnico de asignatura (que es donde yo aprendí este concepto) sabrán a qué me refiero cuando hablo de una afinidad, pero como sé que muchos de vosotros no habéis pasado aún por ahí, o directamente no lo habéis dado, os dejo por aquí una breve explicación, que asumiré que entendéis, ya que yo he intentando escribirlo con mis propias palabras, y es que realmente esa explicación es sencilla, concisa, orgásmica y correcta.

San Google dijo:
La Afinidad es una transformación geométrica plana, en la cual los puntos relacionados o transformados se denominan afines, y cumplen las siguientes condiciones:

Afinidad (I)


  • La recta que une dos puntos afines siempre es paralela a una dirección dada, la dirección de la afinidad.
  • Dos rectas afines se cortan siempre en un punto de una recta fija llamada eje de la afinidad.

Se define la razón de la afinidad k como la constante que relaciona las longitudes de segmentos afines, y también es la relación entre los segmentos que unen puntos afines con el eje (siguiendo la dirección de la afinidad).

Si k = -1 y la dirección de afinidad es perpendicular al eje, la afinidad es una simetría axial.
Para mi esta explicación es orgásmica, pero tengo que cumplir con lo prometido

Tras leerme de nuevo la definición (para comprobar si realmente era correcta) leí lo de la simetría axial, y tras haber estado toqueteando un poco previamente, me he dado cuenta que realmente estamos tratando con simetrías axiales (respecto al eje X y al eje Y), pues hasta el momento no he encontrado ningún parámetro para poder definir la dirección de afinidad.

Por lo que he podido comprobar experimentalmente, el eje de simetría cae en el centro del sprite, por lo que esta "afinidad de plástico" no afectará a la posición del sprite en la pantalla.

Yo tengo poca información que aportar, aparte de la teórica porque aún no he indagado, y sólo he estado haciendo el tonto con el comando

Código:
AFFINEANIMCMD_FRAME(escalaEnX, escalaEnY, rotacion, duracion)
Que podemos encontrar en la l. 450 aproximadamente del archivo "src/main_menu.c", en la que podemos modificar la afinidad aplicada al sprite del prota en el final de la intro del Prof.Birch.

Código:
static const union AffineAnimCmd sSpriteAffineAnim_PlayerShrink[] = {
    AFFINEANIMCMD_FRAME(-2, -2, 0, 0x30),
    AFFINEANIMCMD_END
};
Conforme investigue, iré comentando este post (no creo que actualice este primer mensaje porque se me hace mucho más pesado si no que comentaré en un nuevo mensaje los avances que haga, pero igual me animo)

¡Recordad que vosotros también podéis aportar a la investigación, ya sea con descubrimientos, o con más teoría de utilidad ^^!
 

Kaktus

Miembro insignia
Miembro insignia
¡Buenas!

He avanzado con la investigación.

Para empezar, explicaré como realizar una escala del sprite (aumentar o disminuir su tamaño)

Lo primero será considerar los parámetros de

Código:
#define AFFINEANIMCMD_FRAME(_xScale, _yScale, _rotation, _duration)
Como bien podemos ver en su definición, hay cuatro. La escala en X, en Y, la rotación, y la duración. ¿Pensáis que iban a ser tan buenos de ponernos las escalas directamente, la rotación en grados, y la duración en segundos? Para nada.

Empezaremos por saber que a más "_xScale" y "_yScale", más rápido aumentará su tamaño, esto no quiere decir que vaya a escalar a ese tamaño o algo por el estilo. Si usamos un valor positivo, como "16", la escala será de aumento, si usamos un valor negativo como "-32" será de reducción.

Debemos saber que el valor de escalado y la duración van estrictamente ligados, y me he molestado en sacar una especie de fórmula algo genérica que nos sirve para escalados básicos.

Primero, acortaré las variables para hacer más cómoda la fórmula (aunque es de lo más sencillita).

Código:
d = _duration
x = _xScale
k
La d, será el valor que le daremos a _duration, la x será el que le daremos a _xScale, y por último, la k será la escala que queramos darle, por ejemplo, si queremos que sea dos veces más grande que el sprite original, k = 2. Si queremos que sea 2/3 del original, k = 2/3 (aunque no recomiendo mucho este valor, la verdad, no quedará homogéneo)

Una vez sabemos esto, a continuación la fórmula (que podréis despejar para saber el valor que más os interese, o podréis darle valores directamente para saber la duración)


OJO.- Si el resultado de la fórmula os da un valor con decimales, os recomiendo que optéis por usar otros valores que den un resultado visual similar, pero que no de decimales, ya que los floats no se procesarán como tal. Podéis jugar con la velocidad de escalado.

OJO.- Yo usaré la fórmula que veréis a continuación, porque voy a trabajar con un sprite que por defecto, es cargado con un tamaño de 1x1 pixel, y hay una cierta variación en la fórmula para que pueda escalarlo a su tamaño natural, concrétamente esta. Pero si vosotros cargáis el sprite directamente con su tamaño original, tenéis que usar la anterior. Una vez le haya aplicado esta fórmula para darle un escalado a su tamaño original, ya se puede aplicar la fórmula anterior.


Bien, ahora, debemos saber que antes de usar el AFFINEANIM, deberemos usar esto (al menos a mi sin esto, no me funciona):

Código:
AFFINEANIMCMD_FRAME(_xScale, _yScale, 0, 0),
Y luego, ya, escribir la transformación que queramos hacer.

Por ejemplo, digamos que hemos hecho que el sprite se cargue con unas dimensiones de 1x1, y lo que queremos hacer es aumentar su tamaño al original, bien pues queremos que k = 1, una velocidad en x e y de unos 16 (por defecto), así que, vamos a calcular la duración necesaria:

d = (240/16)*1 = 15

Bien, pues tendremos que el bloque completo de animación afín, nos quedará así.

Código:
static const union AffineAnimCmd gSpriteAffineAnim_85B1EA0[] =
{
    AFFINEANIMCMD_FRAME(16, 16, 0, 0),
    AFFINEANIMCMD_FRAME(16, 16, 0, 15),
    AFFINEANIMCMD_END,
};
Y el resultado, será este:


A ver IK, no me la líes, que tú ahí no has modificado nada, así es como estaba.
Vale, pues vamos a probar a reducirlo a la mitad.

Ahora queremos que k = 1/2, y X e Y sean = 16, así que...

d = (240/16) * 1/2 = 7.5

Oops... Tenemos un resultado que no queremos, tiene decimales, así que... ¿Qué podemos hacer?

Fácil, reducimos la velocidad (_xScale e _yScale) al doble, que es lo que se necesita para aumentar el valor de d, ya que son inversamente proporcionales.

Ahora tenemos que k = 1/2 y x = 8...

d = (240/8) * 1/2 = 15

¡Bien! tenemos un resultado entero, ahora a adaptar parámetros:

Código:
static const union AffineAnimCmd gSpriteAffineAnim_85B1EA0[] =
{
    AFFINEANIMCMD_FRAME(8, 8, 0, 0),
    AFFINEANIMCMD_FRAME(8, 8, 0, 15),
    AFFINEANIMCMD_END,
};

Análogamente para aumentarlo.

Ahora, para rotarlo, deberemos saber que un valor de 4, es proporcional a girarlo 90º, y que por tanto, 16, es proporcional a darle un giro completo.

Aclarar que también podéis usar el signo positivo o negativo en la rotación para indicar hacia donde rotará (positivo, sentido antihorario, negativo, sentido horario)

Bien, a continuación, os dejaré una pequeña secuencia a modo de "ejercicio" para que intentéis pensar qué ocurrirá:

Código:
    AFFINEANIMCMD_FRAME(16, 16, 0, 0),
    AFFINEANIMCMD_FRAME(16, 16, 0, 15),
    AFFINEANIMCMD_FRAME(16, 16, 0, 16),
    AFFINEANIMCMD_FRAME(-16, -16, -4, 16),
    AFFINEANIMCMD_END,

Y hasta aquí mi investigación, que creo que ha cubierto de una forma bastante decente el cómo funcionan las animaciones afines en pokeemerald.

¡A ver si me dais algo de feedack! <3
 
Estado
Cerrado para nuevas respuestas.
Arriba