Come posso fare in modo che un oggetto in movimento si arresti senza problemi alla fine di un percorso?


8

Ci sono una dozzina di modi in cui potrei formulare questa domanda, ma per mantenere i miei pensieri in linea, lo sto formulando in linea con il mio problema a portata di mano.

Quindi sto creando una piattaforma mobile che mi piacerebbe poter viaggiare da un punto designato all'altro, quindi tornare al primo e passare semplicemente tra i due in linea retta. Tuttavia, solo per renderlo un po 'più interessante, voglio aggiungere alcune regole alla piattaforma.

  1. Lo sto codificando per viaggiare multipli di interi valori di piastrelle dei dati del mondo. Quindi, se la piattaforma non è ferma, viaggerà almeno per l'intera larghezza o altezza della piastrella.
  2. Entro una piastrella, vorrei che acceleri da una fermata a una data velocità massima.
  3. Al raggiungimento della distanza di una piastrella, vorrei che si rallentasse fino a raggiungere una determinata coordinata di piastrelle e quindi ripetere il processo al contrario.

inserisci qui la descrizione dell'immagine

Le prime due parti non sono troppo difficili, essenzialmente sto avendo problemi con la terza parte. Vorrei che la piattaforma si fermasse esattamente alle coordinate di una piastrella, ma dato che sto lavorando con l'accelerazione, sembrerebbe facile semplicemente iniziare ad applicare l'accelerazione nella direzione opposta a un valore che memorizza la velocità corrente della piattaforma quando raggiunge la lunghezza di una piastrella di distanza (supponendo che la piastrella percorra più di una lunghezza di piastrella, ma per mantenere le cose semplici, supponiamo solo che lo sia) - ma allora la domanda è: quale sarebbe il valore corretto per accelerare l'incremento da cui produrre questo effetto? Come troverei quel valore?


1
Non ho tempo per una risposta completa al momento, ma dai un'occhiata a questo: red3d.com/cwr/steer/gdc99 , in particolare la sezione "Arrivo". Imita quel comportamento per rallentare fino all'arresto e invertirlo per accelerare da un arresto.
MichaelHouse

Segnalibro. È una ricchezza di informazioni preziose a cui mi hai appena illuminato, signore.
TheBroodian,

Questo tipo di "desiderato_velocità = (velocità_distinta / distanza) * target_offset" ha un senso, ma non esattamente. Una volta trovata desiderata_velocità, per sottrarla dalla velocità corrente dell'oggetto?
TheBroodian,

Lo uso per aggiornare il valore dell'accelerazione: acceleration = desired_velocity - currentVelocityquindi applica tale accelerazione come faresti normalmente. Creerò una risposta un po 'più avanti mostrando ciò che faccio.
MichaelHouse

Risposte:


5

Utilizzando questi comportamenti di guida come guida. Guardando il comportamento di arrivo:

inserisci qui la descrizione dell'immagine

Il comportamento all'arrivo è identico da cercare mentre il personaggio è lontano dal suo bersaglio. Ma invece di muoversi attraverso il bersaglio alla massima velocità, questo comportamento fa rallentare il personaggio mentre si avvicina al bersaglio, rallentando infine fino a fermarsi in coincidenza con il bersaglio.

Possiamo creare una funzione "arriva a" come qualcosa di simile a questo:

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;
}

Ciò aggiornerà l'accelerazione che dobbiamo usare per applicare l'oggetto in movimento.


E solo per chiarimenti, linearVelocity sarebbe la velocità con cui il nostro oggetto avrebbe viaggiato attualmente dopo l'aggiornamento precedente?
TheBroodian,

Il tuo fraseggio è piuttosto strano. Ma linearVelocity == currentVelocity.
MichaelHouse

3
Non sono d'accordo con questo approccio sulla base del fatto che è troppo complicato. È possibile farlo con una semplice interpolazione usando le equazioni del movimento ( le formule SUVAT ). Un po 'di algebra e puoi calcolare gli input necessari per colpire con precisione un obiettivo desiderato.
Andrew Russell,

1
Sarebbe utile se potesse elaborarlo con una risposta?
TheBroodian,

@AndrewRussell Vorrei vedere anche quella risposta.
MichaelHouse

5

Dai un'occhiata a questa pagina: http://sol.gfxile.net/interpolation/index.html

Sembra che tu voglia un effetto proprio come il smoothstep:

grafica liscia

Se hai il punto più a sinistra, il punto più a destra che la piattaforma dovrebbe raggiungere e il tempo che dovrebbe usare per fare una sequenza completa, qualcosa del genere potrebbe essere ok:

telaio 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);

se stai usando un motore fisico, puoi farlo con impulsi, non dovrebbe essere così difficile da tradurre. Se si desidera un processo ancora più fluido, è possibile aumentare il livello graduale. Smoothstep multiplo


3

Puoi usare XnaTweener che fornisce funzioni di andamento che interpolano i valori da un punto all'altro in modo semplice ...

Ecco una risposta con un codice basato sul progetto Xna Tweener e un video che mostra come si comporta ...

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

[MODIFICARE]

Dovresti avere una sequenza di tasti che definisce il movimento della piattaforma, in questo modo:

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 ); 
    }
}

E quindi puoi gestire il movimento in questo modo:

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" è la posizione iniziale, "Traslation" accumula il movimento di più tasti e ogni traslazione dei tasti è relativa alla chiave precedente, quindi quando la moltiplichi per un fattore di rapporto [0..1] restituisce la traslazione relativa interpolata percorsa per raggiungere quella chiave dalla chiave precedente ...

Ecco un altro video che mostra un movimento della piattaforma definito come descritto qui ...

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

Ho rifatto questo codice cercando di renderlo facile da capire ... forse ha qualche bug ... il codice originale gestisce diverse istanze dello stesso movimento ma con alcuni ritardi tra ogni istanza ... Sono sicuro che questo codice può essere riprogettato per essere più semplice ...


Grazie, questo è utile, anche se viene utilizzato in quello che sembra il contesto di un'animazione, sto cercando di tradurlo nella mia testa in quello che sarebbe più contestuale alla mia situazione a portata di mano.
TheBroodian,

Mi sono perso. Non riesco a capire come collegarlo alla mia situazione attuale. oo ;;
TheBroodian,

Hai un'animazione ... stai cercando di animare in termini di posizione ...
Blau,

Perdonami, il motivo per cui ho delle difficoltà, è perché sto cercando di avviare questa idea e tradurla in un sistema che funziona su un sistema di velocità = velocità *, mentre questo sistema spinge semplicemente la posizione dell'oggetto proceduralmente (niente di sbagliato in questo, solo difficile trovare il modo corretto di mettere in relazione i due).
TheBroodian,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.