PDA

Ver la versión completa : Controlar velocidad en animaciones de sprites



anibarro
11/09/2005, 10:53
Abro este hilo para ver si alguien puede explicar un poco como se controla la velocidad de las animaciones, le escribi un privado a puck pero los MP son muy cortos y, como me dice el, lo pongo aqui:
Hola muy buenas, estoy intentando hacer alguna cosilla que se parezca a un juego, pero tengo un problema con las animaciones.
El caso es que he creado una estructura para saber el estado del sprite, el fotograma de la animacion en el que esta, posicion, etc, y a la hora de controlar la velocidad de la animacion de un personaje, hago algo como esto al apretar una tecla:

si(joystick_arriba){

personaje.direccion=arriba;
si (personaje.tick_inicial == 0) {personaje.tick_inicial=SDL_GetTicks();}
personaje.tick_actual=SDL_GetTicks();
si ((personaje.tick_inicial-personaje.tick_actual) >= personaje.velocidad_animacion){

ranger_state.pos_anim+=1;
ranger_state.ticks=0;

}
si (personaje.fotograma >2) {personaje.fotograma=0;} //tiene 3 fotogramas esa animacion
personaje.y+=personaje.velocidad;

}
El problema es que cuando llevas un rato jugando, el numero de ticks empieza a ser muy grande, y las variables del struct "tick_inicial" y "tick_actual" se quedan pequeñas para almacenarlo, po lo que se pasan de rango al rato de empezar. Si las pongo de 8 bits se pasan en seguida, si las pongo de 16 bits tardan mas, pero igual se pasan, y no se como solucionar esto.
¿Como haceis para controlar la velocidad en las animaciones? Y si teneis por ahi la estructura que usais para almacenar la info de cada sprite me vendria muy bien. Un saludo ;)

Puck2099
11/09/2005, 11:04
Hola de nuevo,

Bien, yo lo que hago primero es limitar el número de FPS a una cantidad constante. ¿Qué se consigue con eso?, pues evitar "acelerones" o "ralentizaciones" del juego dependiendo del número de enemigos en pantalla, funciones "pesadas", etc.

Una vez tienes los FPS fijos (por ejemplo en mi LK son 60 FPS), pienso cuantos frames dura cada "movimiento" de la animación. Por ejemplo, un personaje puede tener 8 "movimientos" distintos cuando se mueve hacia arriba, y cada uno de esos "movimientos" se repetirá durante 3 frames.

La estructura de mi personaje contiene una variable entera llamada "pos". Esta "pos" se incrementa en cada frame y es la que nos dará el "movimiento" de la animación donde nos encontramos. Me parece que los enteros cuando se desbordan se ponen a 0 y ya está, así que no tengo que hacer más comprobaciones, solo poner la variable a 0 manualmente cuando cambie de animación para que empiece desde la primera.

No sé si me he explicado muy bien, así que voy a buscar el código de mi LK y te pego un fragmento donde más o menos se entienda.

Saludos

jjdrako
11/09/2005, 11:12
los FPS solo se toca en el SDL o tambien se puede en el SDk??

Puck2099
11/09/2005, 11:17
los FPS solo se toca en el SDL o tambien se puede en el SDk??

Se puede hacer en cualquiera de los dos, pero no es una función que te lo controle, sino que te lo tienes que currar a mano.

anibarro
11/09/2005, 11:28
Muchas gracias puck, ya tenia un limitador de FPS, con las SDL que ha portado chui, ha incluido la libreria SDL_framerate, con la que definiendo una variable:
FPSmanager fpsm;
Inicializandola:
SDL_initFramerate(&fpsm);
Y poniendo al principio (antes) del bucle infinito:
SDL_setFramerate(&fpsm,60); //para 60 fps teoricos, que son 120 en mi PC y muchos menos en la GP
Y al final:
SDL_framerateDelay(&fpsm);
Ya limita el framerate. Lo que he hecho es poner una variable de 8bits que suma 1 cada iteracion del bucle principal (para controlar animaciones que cambian cada menos de 1 segundo en PC, cada segundo hace 120 fps si pongo limite 60 en lo de arriba), y otra variable que aumente 1 cada 120 fps en PC (cada 1 segundo aprox) para animaciones u otras cosas mas lentas, lo malo es que hay que ajustarlo para LA GP y para el PC de forma distinta, pero al menos funciona ^^

jjdrako
11/09/2005, 11:28
yo he hecho animaciones, en una variable indico que parte de la animacion tiene que poner, pregunto en un case el numero de la variable y meto en el buffer de pantalla la imagen que tiene que ser y por ultimo con un delay (cogiendo el tick y metiendolo en un while hasta que la diferencia del tick actual con el que he metido en la variable sea el tiempo que yo quiera), le incremento la variable de animacion

a mi me funciona no me he pegado mucho rato la verdad para ver si la variable se desvorda, pero el rato que he estado mirando funciona perfectamente

se que el tick que empiez de 0 cuando se ejecuta el juego se puede inicializar con una instruccion, si eso la vas inicializando y ya esta

a mi me pasa lo que ha puesto puck, al principio la animacion se me acelera pero luego coge su ritmo, si puedes poner como se toca lo del FPS, una buena animacion son 25 fotogramas por segundo pero a ver como se hece bien :)

Puck2099
11/09/2005, 11:34
yo he hecho animaciones, en una variable indico que parte de la animacion tiene que poner, pregunto en un case el numero de la variable y meto en el buffer de pantalla la imagen que tiene que ser y por ultimo con un delay (cogiendo el tick y metiendolo en un while hasta que la diferencia del tick actual con el que he metido en la variable sea el tiempo que yo quiera), le incremento la variable de animacion

¿Pero preguntas en el case por cada "posición" en la animación? Porque como sea así y tengas unas cuantas animaciones te va a salir un listado un poco gordo, ¿no? :p

Saludos

Puck2099
11/09/2005, 11:37
Muchas gracias puck, ya tenia un limitador de FPS, con las SDL que ha portado chui, ha incluido la libreria SDL_framerate, con la que definiendo una variable:
FPSmanager fpsm;
Inicializandola:
SDL_initFramerate(&fpsm);
Y poniendo al principio (antes) del bucle infinito:
SDL_setFramerate(&fpsm,60); //para 60 fps teoricos, que son 120 en mi PC y muchos menos en la GP
Y al final:
SDL_framerateDelay(&fpsm);
Ya limita el framerate. Lo que he hecho es poner una variable de 8bits que suma 1 cada iteracion del bucle principal (para controlar animaciones que cambian cada menos de 1 segundo en PC, cada segundo hace 120 fps si pongo limite 60 en lo de arriba), y otra variable que aumente 1 cada 120 fps en PC (cada 1 segundo aprox) para animaciones u otras cosas mas lentas, lo malo es que hay que ajustarlo para LA GP y para el PC de forma distinta, pero al menos funciona ^^

¿Entoces te funciona ya o necesitas que te pegue algún código o algo? :)

Saludos

Eskema
11/09/2005, 11:45
Pues yo debo ser el mas chapuzas del mundo pq hago una cosa tal q asi para controlar la velocidad de la animacion

Primero declaro un int mov_paraca=0; en el inicio del codigo y luego cada vez q se mueve el personaje ejecuto ese codigo:

if (mov_paraca == 3)
{
Movimiento(paraca->x, paraca->y + 3 , paraca);
mov_paraca = 0;
}
else
mov_paraca++;

Desde luego dais envidia con esas funciones tan curradas y yo aqui en plan chapuza con un bucle cutron xDD

jjdrako
11/09/2005, 11:45
bueno he mencionado lo primero que hice, ahora lo que hago es meter todas las imagenes de la animacion juntas en la misma libreria y la variable lo que hace es con una pequeña multiplicacion ir desplazando las coordenadas de la imagen

Puck2099
11/09/2005, 11:48
bueno he mencionado lo primero que hice, ahora lo que hago es meter todas las imagenes de la animacion juntas en la misma libreria y la variable lo que hace es con una pequeña multiplicacion ir desplazando las coordenadas de la imagen

Eso está mejor, así es como lo hago yo ;)

jjdrako
11/09/2005, 11:49
Pues yo debo ser el mas chapuzas del mundo pq hago una cosa tal q asi para controlar la velocidad de la animacion

Primero declaro un int mov_paraca=0; en el inicio del codigo y luego cada vez q se mueve el personaje ejecuto ese codigo:

if (mov_paraca == 3)
{
Movimiento(paraca->x, paraca->y + 3 , paraca);
mov_paraca = 0;
}
else
mov_paraca++;

Desde luego dais envidia con esas funciones tan curradas y yo aqui en plan chapuza con un bucle cutron xDD
paraca pero para donde :quepalmo::quepalmo:

enkonsierto
11/09/2005, 11:56
Una solución que se me olvidó comentarte anoche, pero que yo la he llegado a usar para que las animaciones sean más lentas, es duplicar los elementos del struct, es algo cutre pero funciona.

algo asi...

[d1, d1, d2, d2, d3, d3, d4, d4...]

Es más sencillo y además si necesitas que otra animación vaya más rápido o más lento puedes duplicar o no los elementos a tu gusto...:D :D :D :D

A ver si esto te funciona... (y no te parece cutre...) :D :D :D

Eskema
11/09/2005, 11:57
Si te bajas la beta disponible en mi web www.telefonica.net/web2/eskematico veras lo del paraca tu mismo, pq no es lo q parece XDDD

P.D archivo main_gp32.rar

anibarro
11/09/2005, 12:13
¿Entoces te funciona ya o necesitas que te pegue algún código o algo? :)

Saludos
Puck me estoy fijando que funciona a medias solo :( Es que es imposible que haya q hacer algo tan lioso solo para esto xD
Ahora, usando una variable "fps" que aumenta 1 cada fotograma, guardo lo que valia "fps" en "ticks", en el momento en que cargo un frame de una animacion. Luego voy mirando lo que vale "fps" y restandole lo que valia "ticks", de forma que me de los "fps" que han pasado y cuando han pasado 3 o 4 fotogramas, cambio de sprite y actualizo la variable "ticks".
El caso es que si cuando cojo el valor de "ticks", "fps" vale por ejemplo 3, y luego voy mirando y cuando "fps" vale 6, los resto, va bien. Pero si "ticks" vale 58 (fps max 60) y luego comparo con "fps" para restar, no funcionara pq valdra menos y la resta sale mal, entonces tengo que hacer una pirula de:
si (ticks>fps) ticks=-(60-.ticks);
Y luego en la resta poner valor absoluto.
Y aun haciendo todo ese galimatias de ifs, se queda pillao a veces pq el contador de fps se desmadra y no se pq :/

¿Eskema puedes explicar un poco que es cada cosa de eso que has puesto? :rolleyes:

anibarro
11/09/2005, 12:16
Una solución que se me olvidó comentarte anoche, pero que yo la he llegado a usar para que las animaciones sean más lentas, es duplicar los elementos del struct, es algo cutre pero funciona.

algo asi...

[d1, d1, d2, d2, d3, d3, d4, d4...]

Es más sencillo y además si necesitas que otra animación vaya más rápido o más lento puedes duplicar o no los elementos a tu gusto...:D :D :D :D

A ver si esto te funciona... (y no te parece cutre...) :D :D :D

Hombre funcionar seguro q funciona, pero lo de ir duplicando es un poco toston, y mas como quieras cambiar los fps por segundo xD Pero gracias, que todas las ideas me vienen bien :brindis:

Eskema
11/09/2005, 12:25
Anibarro en mi web tienes el fuente de mi juego para verlo/usarlo a tu antojo eso si el copyright son 300leros de nada XDD
Dale un vistazo a mi fuente y te explico lo q quieras de el ;)

anibarro
11/09/2005, 12:38
Eskema ya me lo he mirado y hay q ver lo sencillas q son algunas cosas cuando las ves ya pensadas XDD
Segun lo he entendido, tienes un contador para cada animacion, que aumenta en 1 cada vez que se llama a ese movimiento del sprite animado y luego cuando llega a un valor, pasas al siguiente fotograma de la animacion y lo pones a 0 otra vez...una solucionsimple, rapida y que funciona, eso necesitaba yo jaja muchas gracias, voy a probar a ver ;)

Probado y va perfectooo :brindis:

Eskema
11/09/2005, 12:47
Exactamente, es como dices, si llegas al tope a 0 y a empezar otra vez, pero claro los "maestros" no usan estas chapuzas XDDD.

¿Has usado el sonido? pq no se como iniciarlo, no consigo q se oiga nada de nada, solo ruido

chipan
11/09/2005, 14:22
La manera que uso yo para hacer animar es un poco chapuzas pero bastante flexible; accedo a los elementos de la struct con la division entera del contador para acceder y los fotogramas que quiero que dure cada gráfico de la animacion.
digamos que si quiero que cada fotograma dure 4 frames y uso la variable "contador1" como índice para acceder a la struct, hago que "contador1" aumente 1 en cada fotograma y accedo a la struct con la variable "contador1/4".
No me explico muy bien pero supongo que me entendereis.

Puck2099
11/09/2005, 14:25
La manera que uso yo para hacer animar es un poco chapuzas pero bastante flexible; accedo a los elementos de la struct con la division entera del contador para acceder y los fotogramas que quiero que dure cada gráfico de la animacion.
digamos que si quiero que cada fotograma dure 4 frames y uso la variable "contador1" como índice para acceder a la struct, hago que "contador1" aumente 1 en cada fotograma y accedo a la struct con la variable "contador1/4".
No me explico muy bien pero supongo que me entendereis.

Sí, es lo mismo que hago yo :)

Y cuando son animaciones cíclicas pues uso el módulo: contador1/4%3*ancho

chipan
11/09/2005, 14:50
Ah bueno! si lo haces tu así retiro lo de que es una forma chapucera de hacerlo.

D_Skywalk
12/09/2005, 09:30
Bueno yo la verdad que tampoco se si esta es la mejor forma pero yo lo que tengo es una estructura de animaciones que contiene: un bitmap, un enlaze al siguiente frame (el ultimo enlaza al 1o) y un temporizador (u8) que indica el tiempo al cambio.

Por cada actor tengo un puntero que voy moviendo conforme llegue el temporizador a su fin, asi siempre va dando vueltas sin tener que comprobar nada, y solo mirando si es el momento de cambiar o "paso luego a ver" xD

Concepto de la estructura de una animacion.


[*PUNTERO*]
|-----¬
v
[A] -> [B] -> [C] -> [D] ¬
^ |
|-----------------------|


Un Saludo

jjdrako
12/09/2005, 11:08
jo que ganas tienen algunos de usar punteros, yo mira que hago antes cualquier rodeo a usar punteros, siempre suele haber problemas con ellos y te comes mucho la cabeza para quitarte el error :D

oankali
12/09/2005, 11:45
Pues yo utilizo el sistema indicado por anibarro en su primer ejemplo y personalmente es el que encuentro más correcto, porqué cada objeto animado tiene sus propias propiedades, con sus ticks iniciales y actuales, y el tiempo a transcurrir entre cada frame de la animación a no confundir con los frames a la que va el juego.
A mí no me da el problema que comenta, pero programo con el SDK oficial y el tipo de variable que utilizo es int, o sea 32 bits con lo que hay más que suficiente para partidas de hasta 68 años de duración sin dar problemas, partiendo de la base que cada tick dura 1 milisegundo.
Pero para no tener problemas de velocidad de procesador, la velocidad de animación de mis objetos la indico en milisegundos y tengo una macro que me pasa de milisegundos a ticks y viceversa en función de la velocidad del procesador.
También se puede utilizar el reloj en tiempo real pero lo mejor que puedes obtener es una resolución de 1/64 segundos (si no recuerdo mal).

Oankali.

D_Skywalk
12/09/2005, 11:56
Si entiendes lo que es y como funciona un puntero, y tambien entiendes de estructuras de datos, listas, etc... Siempre te sera mas simple usar ese tipo de sistemas que andar con contadores.

Ademas trabajar con memoria siempre requiere menos ciclos y comprobaciones que trabajar con enteros, comprobar si es mayor menor, etc... consume muchos ciclos.

De la forma que te he contado solo haces:


¿Se cambia el frame? --> No [FIN]
|
v
Si
[Miactor->ani++]
[FIN]


Un Saludo

oankali
12/09/2005, 12:18
Las dos soluciones son debatibles.
En el caso de contadores, es mucho más sencilla la inicialización al no tratar con punteros, teniendo la posibildad de inicializar las estructuras directamente en el código C. Pero luego necesitas gestionar los límites de la animación con una variable que contenga el número de frames de la animación.
En el caso de los punteros, la inicialización és mucho más complicada, ya que solo la puedes hacer en tiempo de ejecución gestionando la memória dinámica. Pero luego, el paso de un frame a otro se hace de manera mucho más directa, con la posibilidad además de poder indicar propiedades diferentes para cada frame. Es más rápida pero ocupa más memória.

Personalmente, utilizo mucho los punteros, aunque para este caso no lo he hecho nunca, no se me había pasado por la cabeza. Con punteros bien hechos, sueles tener soluciones, en mi opinión, bastante más estéticas,

Y si quieres usar punteros pero sin tener que gestionarlo todo, ya existen librerías que lo hacen como mi librería list.h que encontrarás en mi web aquí: www.nekanium.com/gp32 (http://www.nekanium.com/gp32)

Oankali.