Nuestro protagonista y la cinemática

Started by Fede, February 05, 2012, 08:07:14 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Fede

 Saludos filibusteros.

Después leer el hilo de "Comportamiento 2D por herencia", http://forum.bennugd.org/index.php?topic=484.msg50425#new , comerme el tarro de mala manera con el ejemplo parecido que trae Bennu: "Plataform.prg", y costarme un 'güevo' medio comprenderlo...


Os presento otro loco hilo de mi cosecha.

Así que..., si os gustó "El hilo del pixel art", http://forum.bennugd.org/index.php?topic=2205.0, no os podéis perder este nuevo hilo titulado: "Nuestro protagonista y la cinemática".

En él vamos a intentar mostrar cómo podemos simular comportamientos físicos en el movimiento de nuestro personaje protagonistas de la forma más sencilla que se me ocurra, y aquí veremos:
Aceleración, desaceleración, saltos parabólicos, rebotes y demás detalles que se me vayan ocurriendo sobre la marcha, para hacer más atractivo el manejo de nuestro personaje por su mundo imaginario.

Para éste y en sucesivos ejemplos nos valdremos de un mapa de durezas y los frames  de la animación del protagonista.
Estos van en el fichero "graficos.fpg". El número 500 pertenecerá al fondo que utilizaremos como mapa de durezas.
También adjuntaré un fichero prg con el programa que utilizaré de ejemplo.

Irá lo más comentado posible e intentaré que sean lo más claro y fácil que pueda.

Empezaremos por lo más fácil:

Movimiento rectilíneo uniforme

Esto es lo que todos sabemos hacer, incrementamos o decrementamos la coordenada en cuestión, en una cantidad fija, para mover nuestro personaje.

Esto es:

X=X + incremento.


Este ejemplo es  el más simple que se me ha ocurrido.

Nuestro protagonista aparece en mitad de la pantalla y lo podemos mover de izquierda a derecha con la velocidad que marque la variable 'iVelocidad'.

No tiene ningún tipo de comprobación de colisiones ni nada de nada. Estas ya las meteremos más adelante.


Ejemplo1:
   
    loop
        if (key(_LEFT)) //Si pulsa izquierda decrementamos x en iVelocidad.
            x=x-iVelocidad;
        end
        if (key(_RIGHT)) //Si pulsa derecha incrementamos x en iVelocidad.
            x=x+iVelocidad;
        end
        frame;
    end


Al incrementar X con un valor constante se consigue una velocidad constante.

Movimiento rectilíneo uniformemente acelerado.

La cosa se complica, queremos que nuestro personaje incremente su velocidad uniformemente hasta un máximo dado.

Esto es, cuando pulsemos una tecla, empezará a correr cada vez más hasta llegar a un máximo.

Ejemplo 2.


    loop
        iNoPulsada=0;    //Número de teclas sin pulsar a 0.
        if (key(_LEFT)) //Si pulsa izquierda decrementamos x en iVelocidad.
            x=x-iVelocidad;
            iKey=_LEFT;    //Actualizamos tecla en curso.
        else
            iNoPulsada++;    //Si no, esta tecla no ha sido pulsada.
        end
        if (key(_RIGHT)) //Si pulsa derecha incrementamos x en iVelocidad.
            x=x+iVelocidad;
            iKey=_RIGHT;
        else
            iNoPulsada++;
        end
        if ((iNoPulsada==2)or(iKey!=iLastKey))    // Si las 2 teclas no han sido pulsadas
                                                //o la ultima tecla es diferente de la primera.
                                                //Esto es, se ha cambiado de tecla en la iteración.
            iLastKey=-1;
            iVelocidad=iVelocidadInicial;    //Si soltamos las teclas volvemos a la aceleración incial.
            iContador=0;    //Iniciamos también la espera en el incremento de la velocidad. (Aceleracion)
        end
        iLastKey=iKey;//Una vez pasada la iteración, actualizamos la varible "Ulima tecla).

        if((iVelocidad<iVelocidadMax)and(iContador==iFramesEspera))
        //No hemos llegado a la velocidad máxima y además toca incrementar.
            iVelocidad++;
            iContador=0;    //Inicializamos la espera.
        end
        iContador++;
        frame;
    end

 
Vamos a explicar las variables una por una.

            iVelocidadInicial=1;


Nos indica el número de píxeles en que se incrementará X en cada frame en la primera iteración. Inicialmente el prota avanzará un pixel cada frame.

             iVelocidad=iVelocidadInicial;

IVelociadad será la velocidad que llevara el prota en la iteración en curso. Inicialmente vale iVelocidadInicial, o sea, que en la primera iteración se moverá un pixel. Que es lo vale iVelocidadInicial.

             iVelocidadMax=7;             //Incremento máximo.

Esta será la máxima velocidad a la que pueda llegar el protagonista.El incremento de X máximo será de 7 píxeles.

             iFramesEspera=10;

Cantidad de frames que deben de pasar para poder incrementar iVelocidad. Esta variable se puede considerar como la de aceleración.

             iLastKey=-1;

¿Cuál fue la última tecla pulsada? Por defecto, -1, o sea, no hubo tecla.

             iKey;

Tecla pulsada.

   iNoPulsada=0;

Cantidad de teclas no pulsadas. En este caso, si es 2, es que no se ha pulsado ninguna tecla en este frame.

   iContador;

Número de frames que llevamos esperando. Cuando alcance iFramesEspera se incrementará iVelocidad.


Explicando el algoritmo resumimos que:

Si se pulsa una tecla, empieza el proceso de movimiento de aceleración del prota.

La velocidad ira incrementado cada 10 frames hasta llegar a un tope máximo.

Si se sueltan todas la teclas, o se cambia de tecla, se reinicia el proceso de aceleración. El personaje frena en seco y vuelva a comenzar a acelerar.

Los valores de ivelocidad serían:

1111111111 2222222222 ... 6666666666 7777777777

En el próximo post haremos que el personaje frene poco a poco, y no de golpe, al cambiar o soltar las teclas.



Sugerencias, comentarios y críticas constructivas son bienvenidas.

Si quieres ser sabio, aprende a interrogar razonablemente, a escuchar con atención, a responder serenamente y a callar cuando no tengas nada que decir.

Outlaw

Simplemente excelente, bravo Fede! Gracias por el gran aporte! Karmazo!
"Life is cheap when the bounty is high"

SplinterGU

fede, hay algo que no veo tengas en cuenta... si usamos una misma secuencia de grafica de animacion para un persona (de mas de 1 grafico por direccion), si este personaje acelera (a traves de incrementos de X o Y, en lugar de frames) no va a poder usar la misma cantidad de graficos en la animacion, deberian saltar cuadros en base a la velocidad, para que no parezca que el personaje va patinando o resbalandose por donde se mueve...

para esto, yo hice un codigo para alguien (creo que para momia o algun otro) cuando estaban haciendo pruebas con el gran proyecto bennugd, donde mostraba exactamente eso, y se saltaban graficos de la animacion en base a la velocidad, lo que hacia que la misma secuencia grafica se podia usar perfectamente para caminar y para correr, sin que parezca que el personaje iba patinando.

momia o quien sea, si tienen ese codigo, seria bueno lo posteen aca, yo no lo tengo (no soy de guardar codigos) o no se donde lo tengo.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Fede

 Gracias Outlaw. :D

Splinter...

No había pensado en eso que comentas todavía, pero se agradece la anotación.
Si alguien tiene el código y soy capaz de comprenderlo, lo utilizaré para futuros post. Por ahora intento que todo sea 'superfacil', he intentaré ir pasito a pasito.

Todo esto me lo estoy currando para mi propio juego, así que pensé que como más o menos pasamos todos por el mismo mal trago, sería interesante ir haciendo minitutos de los pasitos que estoy dando. Así aprendemos todos. :D
Si quieres ser sabio, aprende a interrogar razonablemente, a escuchar con atención, a responder serenamente y a callar cuando no tengas nada que decir.

Futu-block

eso que dice esplinter se puede hacer de varias formas jugando con los graficos; mexplico:
·se usa dos tipos de animacion del personaje, una para andar y otra para correr, o
·cuando anda el personaje hacemos que cambie de animacion cada tantos frames y cuando corra cada tantos/velocidad, por ejemplo; a ser mayor la velocidad el resultado es mas pequeño (si, habrá que redondear) y por consiguiente mas rapido

jodere, me estoy rayando hasta yo, porque intento explicar lo esplicado, no deberia ser tan especifico, sino ir mas al grano :D

(empanada mental tengo ultimamente por el frio :( )

Fede

 Hola de nuevo chicos.
Independientemente de lo que comenta Splinter sobre la animación del personaje, aquí os traigo el tercer ejemplo:
Movimiento rectilíneo con aceleración y desaceleración.
En este ejemplo manejamos el personaje de la siguiente manera:
  -Acelera desde una velocidad mínima a una máxima cuando le pulsamos.
  -Si se suelta la tecla, se frena con la misma constancia que aceleró.
  -Si se pulsa la tecla contraria, se frena el doble de rápido y cambia de sentido.

Veamos el proceso por trozos:

iStatusKey=0;    //Inicializamos la variable 'Estado de las teclas' a 0.

La variable 'iStatusKey' es la encargada de comunicar los cambio en la intención del movimiento del protagonista.

   -Si vale '1' nos comunica que la tecla pulsada es la misma que la de la anterior iteración y que debemos de seguir acelerando, si podemos.
  -Si vale'2' es que no se ha pulsado ninguna tecla y el muñeco deberá desacelerar en el caso de que estuviera en movimiento.
  -Si vale '3' se pretende invertir el movimiento del personaje, por lo tanto debe de frenar más rápidamente.


                   if (key(_LEFT))
                          iKey=_LEFT; //Actualizamos tecla en curso.
                   else
                         iStatusKey++;   //Si no, esta tecla no ha sido pulsada.
                   end
                   if (key(_RIGHT))
                         iKey=_RIGHT; //Actualizamos tecla en curso.
                   else
                         iStatusKey++;   //Si no, esta tecla no ha sido pulsada.
                   end

'iKey' contiene la tecla en curso. Con 'iStatusKey' vamos contando cuantas teclas no se han pulsado.


                   if ((iLastKey!=iKey)and(iVelocidad>0))
                         //Hemos cambiado de teclas y el prota está en movimiento.
                         iKey=iLastKey;  //Anulamos el cambio de tecla.
                         iStatusKey=3;          //Indicamos que el prota debe frenar.
                   else
                         //Si el prota no está en movimiento actualizamos iLastKey.
                         iLastKey=iKey;
                   end


  'iLastKey' contiene la anterior tecla pulsada.


En este fragmento decidimos si el personaje pretenda cambiar de dirección en pleno movimiento.
Si resulta que la última tecla pulsada es diferente de la actual y además el personaje está en movimiento, actualizamos 'iStatusKey' a 3 para indicar que debemos frenar más de lo normal. Además abortamos la pulsación de la tecla actual igualándola a la anterior.

En caso contrario, damos la tecla por buena y actualizamos la anterior a su valor.

Siguiente trozo:


                   if(iContadorFrames==iFramesEspera)//Debemos actuar en este frame.
                         iContadorFrames=0;   //Inicializamos la espera.
                         switch (iStatusKey)
                                case 2:     // No se está pulsando ninguna tecla.
                                      if(iVelocidad>0)
                                      //Si estamos en movimiento, desaceleramos.
                                            iVelocidad--;
                                      end
                                end
                                case 1:     // Se está pulsando una tecla y es la misma que en la iteración anterior.
                                      if(iVelocidad<iVelocidadMax)
                                      //No hemos llegado a la velocidad máxima, incrementamos velocidad.
                                            iVelocidad++;
                                      end
                                end
                                case 3:     // Se está pulsando una tecla pero hemos cambiado de dirección. Hay que frenar.
                                      if(iVelocidad>0)//Frenamos 'iFreno' veces más rapido que aceleramos.
                                      //No hemos llegado a la velocidad máxima.
                                            if(iVelocidad>iFreno-1)
                                                  iVelocidad=iVelocidad-iFreno;
                                            else
                                                  iVelocidad=0;
                                            end
                                      end
                                end
                         end
                   end

  Este trozo se activa cuando pasan cada 'iFramesEspera'. Cada cierto número de frames compruebo si tengo que cambiar 'iVelocidad' dependiendo que como estén las teclas en 'iStatusKey'.

Tenemos 3 casos:

'iStatusKey' vale 2: No se está pulsando ninguna tecla. El personaje desacelera si está en movimiento.
'iStatusKey' vale 1: La tecla pulsada es la misma que la vez anterior, o bien es la primera vez que se pulsa. Esto último nos da igual. Sencillamente nos limitamos a incrementar 'iVelocidad' si no ha llegado a su máximo.
'iStatusKey' vale 3: Queremos cambiar la dirección del prota que posiblemente esté en movimiento y que va en dirección contraria. Aplicaremos una reducción más drástica que cuando no se pulsa ninguna tecla y vendrá dada por la variable 'iFreno'. 'iFreno' vale 2, con lo que frena el doble de rápido que acelera.

Y por último:

                   if(iVelocidad>0)//iVelocidad es mayor que 0, hay que mover el muñeco.
                         switch (iKey)
                                case _LEFT:
                                      X=X-iVelocidad;
                                end
                                case _RIGHT:
                                      X=X+iVelocidad;
                                end
                         end
                   end



Tras todos los anteriores cálculos y comprobaciones que hemos visto en los otros bloques de código, este trozo actualiza al personaje. Si la velocidad es mayor que 0 movemos el personaje dependiendo de la dirección indicada en 'iKey'.

...


Bien. Esto es todo por ahora.
Si a alguien se le ocurre otros algoritmos o comentarios sobre el que he escrito, se los agradecería. Pero por favor, sin añadir funciones nuevas. Busco otros enfoques u optimizaciones sin complicar la cosa.

En el próximo animaremos al personaje teniendo en cuenta su velocidad. Voy a estudiar lo que comenta Splinter, a ver que sale.  ;D


Saludos.
Si quieres ser sabio, aprende a interrogar razonablemente, a escuchar con atención, a responder serenamente y a callar cuando no tengas nada que decir.

Fede

Quote from: Futublock on February 05, 2012, 08:57:25 PM
eso que dice esplinter se puede hacer de varias formas jugando con los graficos; mexplico:
·se usa dos tipos de animacion del personaje, una para andar y otra para correr, o
·cuando anda el personaje hacemos que cambie de animacion cada tantos frames y cuando corra cada tantos/velocidad, por ejemplo; a ser mayor la velocidad el resultado es mas pequeño (si, habrá que redondear) y por consiguiente mas rapido

jodere, me estoy rayando hasta yo, porque intento explicar lo esplicado, no deberia ser tan especifico, sino ir mas al grano :D

(empanada mental tengo ultimamente por el frio :( )

Si Futu, eso lo tengo que estudiar. Gracias.

Y lo de las explicaciones. PFFFFF, XXXDDDD

El que te conozca sabe que va intrínseco en tí.  ;D

Y menos mal que no has usado el Gaditano. XXXXDDDD
Si quieres ser sabio, aprende a interrogar razonablemente, a escuchar con atención, a responder serenamente y a callar cuando no tengas nada que decir.

Futu-block


BlySntK

Fede... tardarás mucho en explicar los saltos parabólicos, o el salto normal rectilíneo hacia arriba? Siento imponer impaciencia xD Pero casualmente hoy estoy empezando, por mi cuenta a trabajarme las plataformas xD Qué coincidencia, jajajaja

Estoy probando los códigos anteriores, lo de andar es simple, ya lo tengo hecho, ahora me falta hacer funcionar las aceleración (estoy en ello)
Esnucándote contra la pared no sé si conseguiré mucho, mejor lo pruebo y salímos de dudas ^_^
-------------------------------------------------------
Blaisantka Games > (Official developer web site)

Fede

Pues siento mucho decirte que sí.  ;D

Porque antes de eso hay que implementar por lo menos las colisiones, y todavía me queda un poco.

Calculo que un par de semanas, depende del tiempo que tenga libre. :P


Ve haciendo el tuyo y así por lo menos podemos comparar e intercambiar impresiones.  :D


Si quieres ser sabio, aprende a interrogar razonablemente, a escuchar con atención, a responder serenamente y a callar cuando no tengas nada que decir.

BlySntK

Sin problema... He ido probando el código tuyo, y no sé si es que yo lo estoy poniendo mal el inicio de las variables o qué, supongo que seré yo... Pero no me va bien :S Porque no me acelera progresivamente... Se queda quieto en el mismo lugar en que está y el personaje se mueve (como tengo una animación, lo uso con el for y, se mueve pero la animación sólo)...
Esnucándote contra la pared no sé si conseguiré mucho, mejor lo pruebo y salímos de dudas ^_^
-------------------------------------------------------
Blaisantka Games > (Official developer web site)

Fede

#11
Si te has descargado el ejemplo, y sin tocarlo, te va bien, está claro que al modificarlo para adaptarlo al movimiento del personaje has tocado algo.  ;D

Si no consigues ver que le pasa, puedes corgarlo para que lo veamos. (O me lo mandas por privado, si el juego es un secreto.  8) )

Edito:

Me acabo de bajar el Bennu (No lo tenía en este ordenador) y el Ejemplo 3, y va perfectamente.
Si quieres ser sabio, aprende a interrogar razonablemente, a escuchar con atención, a responder serenamente y a callar cuando no tengas nada que decir.

BlySntK

xDDDD Vaaaaaaaale, lo he hecho mal en el sentido de que lo he hecho con código a parte, :P Sorry, lo haré con tus ejemplos xD EEEEEEJEM xD
Esnucándote contra la pared no sé si conseguiré mucho, mejor lo pruebo y salímos de dudas ^_^
-------------------------------------------------------
Blaisantka Games > (Official developer web site)

Fede

No passssa nada.  ;D

Es que entendí por tu mensaje que sólo tocando las variables iniciales ya no funcionaba.

Tu a tu rollo. Y si necesitas ayuda pa eso estamos.  8)
Si quieres ser sabio, aprende a interrogar razonablemente, a escuchar con atención, a responder serenamente y a callar cuando no tengas nada que decir.