Movimiento independiente del marco


11

He leído otros dos hilos aquí sobre el movimiento: Movimiento basado en el tiempo Vs ¿Movimiento basado en la velocidad de fotogramas? , y ¿ Cuándo debo usar un paso de tiempo fijo o variable?

pero creo que me falta una comprensión básica del movimiento independiente del marco porque no entiendo de qué están hablando ninguno de esos hilos.

Estoy siguiendo los tutoriales SDL de lazyfoo y encontré la lección independiente del marco. http://lazyfoo.net/SDL_tutorials/lesson32/index.php

No estoy seguro de lo que la parte de movimiento del código está tratando de decir, pero creo que es esto (corríjame si me equivoco): para tener un movimiento independiente del marco, necesitamos averiguar qué tan lejos está un objeto ( ej. sprite) se mueve dentro de un cierto período de tiempo, por ejemplo 1 segundo. Si el punto se mueve a 200 píxeles por segundo, entonces necesito calcular cuánto se mueve dentro de ese segundo multiplicando 200 pps por 1/1000 de segundo.

¿Está bien? La lección dice:

"velocidad en píxeles por segundo * tiempo desde el último fotograma en segundos. Entonces, si el programa se ejecuta a 200 fotogramas por segundo: 200 pps * 1/200 segundos = 1 píxel"

Pero ... pensé que estábamos multiplicando 200 pps por 1/1000 de segundo. ¿Qué es este negocio con cuadros por segundo?

Agradecería si alguien me pudiera dar una explicación un poco más detallada sobre cómo funciona el movimiento independiente del marco.

Gracias.

ADICIÓN:

SDL_Rect posRect;
posRect.x = 0;
posRect.y = 0;

float y, yVel;
y = 0;
yVel = 0;

Uint32 startTicks = SDL_GetTicks();

bool quit = false;
SDL_Event gEvent;

while ( quit == false )
{
    while ( SDL_PollEvent( &gEvent ) )
    {
        if ( gEvent.type == SDL_QUIT )
            quit = true;
    }

    if ( y <= 580 )
    {
        yVel += DOT_VEL;
        y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
        posRect.y = (int)y;
    }

    startTicks = SDL_GetTicks();
    SDL_BlitSurface( bg, NULL, screen, NULL );
    SDL_BlitSurface( dot, NULL, screen, &posRect );
    SDL_Flip( screen );
}

Ese es el código que mueve un punto por la pantalla. Creo que tengo todo correcto hasta ahora. Se mueve hacia abajo en la pantalla, pero sucede algo extraño que no puedo explicar. Se supone que el punto permanece en y = 580 cuando llega a ser mayor que ese valor de y. Sin embargo, cada vez que ejecuto el programa, el punto terminará en una ubicación diferente, lo que significa un poco más de 580, por lo que el punto está a la mitad o más de la mitad de la pantalla (el punto tiene 20 píxeles, pantalla dimensiones 800x600). Si hago algo como hacer clic y mantener presionada la barra de título del programa, y ​​luego soltarlo, el punto desaparece de la pantalla. ¿Cómo es que es variable cada vez? En cuanto al problema de la barra de título, creo que es porque cuando me aferro a la barra de título, el temporizador todavía se está ejecutando y el tiempo transcurrido aumenta, resultando en una distancia mayor, el punto se mueve en el siguiente cuadro. ¿Está bien?


Su adición es en realidad otra pregunta. Debe hacer una segunda pregunta en lugar de agregarla a su pregunta actual. Sin embargo, se puede responder fácilmente: simplemente calcule el movimiento y, por ejemplo. yMovement = (yVel * (SDL_GetTicks() - startTicks)/1000.f);luego hacer:if(y + yMovement <= 580){ y += yMovement; } else { y = 580; }
bummzack

Respuestas:


10

NOTA: Todas las fracciones están destinadas a ser flotadores.

El movimiento independiente del marco funciona basando el movimiento fuera del tiempo. Obtiene la cantidad de tiempo transcurrido desde el último fotograma (por lo tanto, si hay 60 fotogramas en un segundo, cada fotograma lleva 1.0 / 60.0 segundos, si todos los fotogramas tomaron la misma cantidad de tiempo) y descubra cuánto movimiento se traduce como.

Si desea que su entidad mueva una cierta cantidad de espacio durante una unidad de tiempo específica (diremos 100 píxeles por cada segundo de tiempo), puede averiguar cuántos píxeles debe mover por cuadro multiplicando la cantidad de movimiento por segundo (100 píxeles) por la cantidad de tiempo transcurrido en segundos (1.0 / 60.0) para determinar cuánto movimiento debe tener lugar en el cuadro actual.

Funciona descubriendo cuánto movimiento debe realizar por cuadro utilizando la cantidad de tiempo transcurrido y una velocidad que se define con alguna unidad de tiempo (son preferibles segundos o milisegundos). Entonces su cálculo podría verse así:movementPerSecond * (timeElapsedInMilliseconds / 1000.0)

Espero que haya tenido algún tipo de sentido para ti.

Quiero mover a mi chico 200 píxeles a la derecha cada segundo. Si el cuadro actual se ejecuta 50 milisegundos después del cuadro anterior, entonces debería mover a mi chico una fracción de la velocidad previamente especificada (que era 200 píxeles). Debería moverlo 50/1000 de la distancia porque solo ha pasado 1/20 (50/1000 = 1/20) de tiempo. Por lo tanto, tendría sentido moverlo solo 10 píxeles (si ocurrieran 19 cuadros más, separados por 50 milisegundos, entonces la cantidad total de movimiento en ese segundo sería 200 píxeles, la cantidad que deseamos).

La forma en que funciona el movimiento independiente de cuadros es que los cuadros generalmente ocurren en pasos de tiempo variables (hay una cantidad diferente de tiempo que tiene lugar entre cuadros posteriores). Si constantemente movemos una entidad una distancia constante cada cuadro, entonces el movimiento se basa en la velocidad de cuadro. Si hay mucho tiempo entre fotogramas, el juego parecerá moverse demasiado lento y si no hay mucho tiempo entre fotogramas, el juego parecerá ir rápido. (muy poco tiempo entre cuadros = muchos cuadros = más movimiento) Para superar esto, usamos una velocidad en términos de tiempo y hacemos un seguimiento del tiempo entre cuadros. De esa manera, sabemos cuánto tiempo ha pasado desde la última vez que actualizamos la posición y cuánto más debemos mover la entidad.

Fotogramas por segundo: esta es la cantidad de fotogramas que tienen lugar por segundo. Por lo general, una velocidad de fotogramas es cuántas veces se dibuja / representa el juego por segundo o cuántas veces se completa el ciclo del juego por segundo.

Paso de tiempo variable de verso fijo: se refiere a la cantidad de tiempo entre cuadros. Por lo general, el tiempo entre cuadros no será constante. Ciertos sistemas / núcleos como la física necesitarán alguna unidad de tiempo para simular / ejecutar algo. Por lo general, los sistemas de física son más estables / escalables si el paso de tiempo es fijo. La diferencia entre los pasos de tiempo fijo / variable está en los nombres. Los pasos de tiempo fijos son lo que parecen: pasos de tiempo que ocurren a una velocidad fija de tiempo. Los pasos de tiempo variable son pasos de tiempo que ocurren a velocidades de tiempo variables / diferentes.


En el ejemplo que da, 50 milisegundos es el tiempo para cada cuadro, ¿correcto? ¿Y eso fue calculado por 1000 / FPS? Entonces, ¿el movimiento que necesita para hacer cada cuadro es píxeles por segundo * 50/1000?
ShrimpCrackers

hm, sin embargo, me di cuenta de que los milisegundos para cada período de tiempo probablemente serían variables, ¿no? Algo así como getTicks () - startTicks siempre sería diferente y no constante.
ShrimpCrackers

@ Omni: si especifica la distancia en "píxeles por segundo", no puede usar milisegundos ... debería ser 1.0 / 60.0, no 1000/60, lo que resultaría en algo completamente diferente.
bummzack

@ShrimpCrackers sí, el tiempo transcurrido cambia. Imagine una PC más antigua que no es capaz de generar 60 fps. Todavía quieres que el juego se ejecute a la misma velocidad (pero no a los mismos fps) en esa máquina.
bummzack

entonces, en el tutorial de lazyfoo, ¿qué significa 1000 en deltaticks / 1000.f? FPS? 1000 milisegundos? Estoy un poco confundido en este momento. Parece que FPS es necesario para determinar el tiempo requerido para cada cuadro, pero que en realidad no se calcula en el movimiento.
ShrimpCrackers

7

En la dinámica de cuadros, su código para (por ejemplo) mover una entidad se vería así:

x = x + speedPerFrame

Si desea ser independiente del marco, podría verse así:

x = x + speedPerSecond * secondsElapsedSinceLastFrame

gracias, eso tiene sentido. Tengo otra pregunta arriba.
ShrimpCrackers

1

En cuanto a la pregunta adicional.

Su punto se detiene en diferentes lugares cada vez porque no verifica el límite (y> 580) cuando lo mueve. Solo deja de actualizarlo una vez que es pasado 580.

En el último fotograma antes de cruzar 580, podría comenzar desde 579 o podría estar en 570 o podría estar en 100. También podría estar avanzando 1 píxel hacia adelante o 1000, dependiendo de cuánto tiempo tardó en ejecutarse el último fotograma.

Simplemente cambie su condición IF a algo como esto y debería estar bien.

if ( y <= 580 )
{
    yVel += DOT_VEL;
    y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
    if( y > 580 )
    {
        y = 580;
    }
    posRect.y = (int)y;
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.