¿Cómo hago para que un objeto en movimiento se detenga suavemente al final de un camino?

8

Hay una docena de formas en que podría formular esta pregunta, pero para mantener mis pensamientos en línea, lo estoy formulando de acuerdo con mi problema en cuestión.

Así que estoy creando una plataforma flotante que me gustaría poder simplemente viajar de un punto designado a otro, y luego regresar al primero, y simplemente pasar entre los dos en línea recta. Sin embargo, solo para hacerlo un poco más interesante, quiero agregar algunas reglas a la plataforma.

  1. Lo estoy codificando para viajar múltiplos de valores de mosaico completos de datos mundiales. Entonces, si la plataforma no es estacionaria, entonces viajará al menos un ancho o altura de mosaico completo.
  2. Dentro de una longitud de mosaico, me gustaría acelerar de una parada a una velocidad máxima dada.
  3. Al llegar a la distancia de una pieza de mosaico, me gustaría que se detuviera en una coordenada de mosaico dada y luego repetir el proceso en reversa.

ingrese la descripción de la imagen aquí

Las dos primeras partes no son demasiado difíciles, esencialmente estoy teniendo problemas con la tercera parte. Me gustaría que la plataforma se detuviera exactamente en una coordenada de mosaico, pero dado que estoy trabajando con la aceleración, parece fácil comenzar simplemente a aplicar la aceleración en la dirección opuesta a un valor que almacene la velocidad actual de la plataforma una vez que alcance la longitud de un mosaico de distancia (suponiendo que el mosaico está viajando más de una longitud de mosaico, pero para mantener las cosas simples, supongamos que lo es), pero entonces la pregunta es ¿cuál sería el valor correcto para que la aceleración se incremente y produzca este efecto? ¿Cómo encontraría ese valor?

TheBroodian
fuente
1
No tengo tiempo para una respuesta completa en este momento, pero eche un vistazo a esto: red3d.com/cwr/steer/gdc99 , específicamente la sección "Llegada". Imite ese comportamiento para reducir la velocidad hasta detenerse y revertirlo para acelerar desde una parada.
MichaelHouse
Marcado como favorito Esa es una gran cantidad de información valiosa que me acaba de iluminar, señor.
TheBroodian
Este tipo de "deseada_velocidad = (velocidad_cortada / distancia) * objetivo_desplazamiento" tiene sentido, pero no exactamente. Una vez que encuentre la deseada_velocidad, ¿la restaré de la velocidad actual del objeto?
TheBroodian
Lo uso para actualizar el valor de aceleración: acceleration = desired_velocity - currentVelocityluego aplique esa aceleración como lo haría normalmente. Crearé una respuesta un poco más mostrando lo que hago.
MichaelHouse

Respuestas:

5

Usando estos comportamientos de dirección como guía. Mirando el comportamiento de llegada:

ingrese la descripción de la imagen aquí

El comportamiento de llegada es idéntico al de búsqueda mientras el personaje está lejos de su objetivo. Pero en lugar de moverse a través del objetivo a toda velocidad, este comportamiento hace que el personaje disminuya la velocidad a medida que se acerca al objetivo, y finalmente se detiene hasta coincidir con el objetivo.

Podemos crear una función "llegar a" como algo similar a esto:

arriveAtPoint(Vector2f position, Vector2f target) {
    float slowing_distance = 1;
    Vector2f target_offset = target - position;
    float distance = target_offset.length();
    float ramped_speed = currentVelocity * (distance / slowing_distance);
    float clipped_speed = Math.min(ramped_speed, currentVelocity);
    targetLinearVelocity = target_offset.scale(clipped_speed / distance);
    acceleration = targetLinearVelocity -linearVelocity;
}

Esto actualizará la aceleración que necesitamos usar para aplicar al objeto en movimiento.

MichaelHouse
fuente
Y solo para aclarar, linearVelocity sería la velocidad a la que nuestro objeto habría estado viajando actualmente después de la actualización anterior.
TheBroodian
Tu fraseo es bastante extraño. Pero, linearVelocity == currentVelocity.
MichaelHouse
3
No estoy de acuerdo con este enfoque porque es demasiado complicado. Es posible hacer esto con una interpolación simple usando ecuaciones de movimiento ( las fórmulas SUVAT ). Un poco de álgebra y puede calcular las entradas necesarias para alcanzar el objetivo deseado con precisión.
Andrew Russell el
1
¿Sería útil si pudieras elaborar eso con una respuesta?
TheBroodian
@ AndrewRussell Me gustaría ver esa respuesta también.
MichaelHouse
5

Eche un vistazo a esta página: http://sol.gfxile.net/interpolation/index.html

Parece que quieres un efecto igual que el paso suave:

gráfico de paso suave

Si tiene el punto más a la izquierda, el punto más a la derecha que debe alcanzar la plataforma, y ​​el tiempo que debe usar para hacer una secuencia completa, algo como esto puede estar bien:

marco foreach:

float smoothstep(float t, int level = 1)
{
    float ret = t;
    for(int i = 0; i < level; ++i)
    {
        ret = pow(ret, 2) * (3 - 2 * ret);
    }
    return ret;
}

currentTime += deltaTime;
if(currentTime > fullTime) currentTime -= fullTime;
float halfTime = fullTime / 2.0;
float t = abs(currentTime - halfTime) / halfTime;
t = smoothstep(t, 1);
platformPosition = rightPoint * t + leftPoint * (1 - t);

Si está utilizando un motor de física, puede hacerlo con impulsos, no debería ser tan difícil de traducir. Si desea un proceso aún más suave, puede aumentar el nivel de paso suave. Múltiples pasos suaves

Gustavo Maciel
fuente
3

Puede usar XnaTweener que proporciona funciones de flexibilización que interpolan valores de un punto a otro de una manera fácil ...

Aquí hay una respuesta con un código basado en el proyecto Xna Tweener y un video que muestra cómo funciona ...

https://gamedev.stackexchange.com/a/26872/8390

[EDITAR]

Debería tener una secuencia de teclas que defina el movimiento de la plataforma, así:

public class MovementKey
{
    public float Time = 0;
    public float Duration;
    public Vector2 Traslation;            // Traslation is relative to previous key
    public TweeningFunction Function;

    internal float GetRatio( float Elapsed )   
    {
        // Always return a value in [0..1] range
        //    0 .. Start position relative to accumulated traslations of previous keys
        //    1 .. Target relative position reached.. then should go to next key if avalaible
        return Function( Elapsed, 0, 1, Duration ); 
    }
}

Y luego puedes manejar el movimiento de esta manera:

public class Movement {

    List<MovementKey> Keys;

    public void Update( float Seconds)
    {

        float ratio;
        if (Playing) Elapsed += Seconds;

        while ( index!= Keys.Count - 1 && Elapsed > Keys[iKey + 1].Time )
        {
            Traslation += Keys[iKey].Traslation;  // Relative
            index++;
        }

       if ( index == Keys.Count - 1 && Elapsed > Keys[iKey].Time + Keys[iKey].Duration )
       {
          ratio = 1;
          if ( DoLoop )
          {
              Elapsed -= (Keys[index].Time + Keys[iKey].Duration);
              Index = 0;
              Traslation = Vector2.zero;
          }
       }
       else {                    
           ratio = Keys[index].GetRatio( Elapsed - Keys[index].Time );
       }

       Position = DefaultPosition + Traslation + ratio * Keys[index].Traslation;        
   }

"DefaultPosition" es la posición de inicio, "Traslation" acumula el movimiento de varias teclas y cada traducción de teclas es relativa a la tecla anterior, por lo que cuando la multiplica por un factor de proporción [0..1] devuelve la traducción relativa interpolada caminada para alcanzar esa clave de la clave anterior ...

Aquí tienes otro video que muestra un movimiento de plataforma definido como se describe aquí ...

http://www.youtube.com/watch?v=ZPHjpB-ErnM&feature=player_detailpage#t=104s

He rehecho este código para que sea fácil de entender ... tal vez tiene algún error ... el código original maneja varias instancias del mismo movimiento pero con algunos retrasos entre cada instancia ... Estoy seguro de que este código puede ser rediseñado para ser más fácil ...

Blau
fuente
Gracias, esto es útil, aunque se está utilizando en lo que parece el contexto de una animación, estoy tratando de traducirlo en mi cabeza a lo que sería más contextual a mi situación actual.
TheBroodian
Estoy perdido. No puedo entender cómo relacionar esto con mi situación actual. oo ;;
TheBroodian
Tienes una animación ... estás tratando de animar en términos de posición ...
Blau
Perdóname, la razón por la que tengo dificultades es porque estoy tratando de poner en práctica esta idea y traducirla a un sistema que funciona en un sistema de velocidad = velocidad * tiempo, mientras que este sistema simplemente empuja la ubicación del objeto procesalmente (No hay nada malo en eso, solo es difícil encontrar la manera correcta de relacionar los dos).
TheBroodian