Como faço para que um objeto em movimento pare sem problemas no final de um caminho?

8

Há uma dúzia de maneiras pelas quais eu poderia formular essa pergunta, mas para manter meus pensamentos alinhados, eu estou formulando isso de acordo com o meu problema em questão.

Então, eu estou criando uma plataforma flutuante que eu gostaria de poder simplesmente viajar de um ponto designado para outro e, em seguida, retornar ao primeiro e simplesmente passar entre os dois em uma linha reta. No entanto, apenas para torná-lo um pouco mais interessante, quero adicionar algumas regras à plataforma.

  1. Estou codificando para viajar com múltiplos valores de bloco inteiros de dados mundiais. Portanto, se a plataforma não estiver estacionária, ela percorrerá pelo menos uma largura ou altura do ladrilho inteiro.
  2. Dentro do comprimento de um bloco, eu gostaria que ele acelerasse de uma parada para uma determinada velocidade máxima.
  3. Ao atingir a distância do comprimento de um bloco, eu gostaria que ele diminuísse até uma determinada coordenada de bloco e repita o processo ao contrário.

insira a descrição da imagem aqui

As duas primeiras partes não são muito difíceis, basicamente estou tendo problemas com a terceira parte. Gostaria que a plataforma parasse exatamente em uma coordenada de bloco, mas como estou trabalhando com aceleração, parece fácil simplesmente aplicar a aceleração na direção oposta a um valor que armazena a velocidade atual da plataforma assim que atingir o comprimento de um bloco de distância (supondo que o bloco esteja viajando mais do que um comprimento de bloco, mas, para simplificar, vamos assumir que sim) - mas a questão é: qual seria o valor correto para a aceleração aumentar para produzir esse efeito? Como eu encontraria esse valor?

TheBroodian
fonte
11
Não tenho tempo para uma resposta completa no momento, mas dê uma olhada no seguinte: red3d.com/cwr/steer/gdc99 , especificamente na seção "Chegada". Imite esse comportamento para diminuir a velocidade e reverter para acelerar a partir de uma parada.
MichaelHouse
Marcado como favorito. Essa é uma riqueza de informações valiosas para as quais você acabou de me esclarecer, senhor.
TheBroodian
Esse tipo de "desejada_velocidade = (velocidade cortada / distância) * destino_offset" faz sentido, mas não exatamente. Depois de encontrar a velocidade desejada, subtraí-a da velocidade atual do objeto?
TheBroodian
Eu o uso para atualizar o valor da aceleração: em acceleration = desired_velocity - currentVelocityseguida, aplique essa aceleração como faria normalmente. Vou criar uma resposta mais adiante, mostrando o que faço.
Michaelhouse

Respostas:

5

Usando esses comportamentos de direção como um guia. Observando o comportamento de chegada:

insira a descrição da imagem aqui

O comportamento de chegada é idêntico ao que procurar enquanto o personagem está longe de ser o alvo. Mas, em vez de passar pelo alvo a toda velocidade, esse comportamento faz com que o personagem desacelere à medida que se aproxima do alvo, eventualmente diminuindo a velocidade para uma parada coincidente com o alvo.

Podemos criar uma função "chegar a" como algo semelhante a este:

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

Isso atualizará a aceleração que precisamos usar para aplicar ao objeto em movimento.

MichaelHouse
fonte
E apenas para esclarecimento, linearVelocity seria a velocidade na qual nosso objeto estaria viajando atualmente após a atualização anterior?
#
Seu fraseado é bem estranho. Mas linearVelocity == currentVelocity.
MichaelHouse
3
Não concordo com essa abordagem, pois ela é complicada demais. É possível fazer isso com uma interpolação simples usando equações de movimento ( as fórmulas SUVAT ). Um pouco de álgebra e você pode calcular as entradas necessárias para atingir um alvo desejado com precisão.
Andrew Russell
11
Seria útil se você pudesse elaborar isso com uma resposta?
TheBroodian
@AndrewRussell Eu gostaria de ver essa resposta também.
MichaelHouse
5

Dê uma olhada nesta página: http://sol.gfxile.net/interpolation/index.html

Parece que você deseja um efeito como o passo suave:

gráfico smoothstep

Se você tiver o ponto mais à esquerda, o ponto mais à direita que a plataforma deve atingir e o tempo que ela deve usar para fazer uma sequência completa, algo como isto pode estar bem:

quadro 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 você estiver usando um mecanismo de física, poderá fazê-lo com impulsos, não deve ser tão difícil de traduzir. Se você deseja um processo ainda mais suave, pode aumentar o nível da etapa suave. Passo suave múltiplo

Gustavo Maciel
fonte
3

Você pode usar o XnaTweener, que fornece funções facilitadoras que interpolam valores de um ponto para outro de maneira fácil ...

Aqui está uma resposta com algum código baseado no projeto Xna Tweener e um vídeo mostrando como ele funciona ...

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

[EDITAR]

Você deve ter uma sequência de chaves que defina o movimento da plataforma, assim:

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 então você pode lidar com o movimento desta maneira:

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" é a posição inicial, "Traslation" acumula o movimento de várias teclas e cada tradução de tecla é relativa à tecla anterior; portanto, quando você a multiplica por um fator de proporção [0..1], ele retorna a tradução relativa interpolada percorrida. para acessar essa chave da chave anterior ...

Aqui você tem outro vídeo que mostra um movimento da plataforma definido como descrito aqui ...

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

Eu refiz esse código tentando facilitar a compreensão ... talvez tenha algum bug ... o código original lida com várias instâncias do mesmo movimento, mas com alguns atrasos entre cada instância ... tenho certeza que esse código pode ser redesenhado para ser mais fácil ...

Blau
fonte
Obrigado, isso é útil, embora esteja sendo usado no que parece ser o contexto de uma animação, estou tentando traduzi-lo na minha cabeça para o que seria mais contextual à minha situação atual.
TheBroodian
Estou perdido. Não consigo descobrir como relacionar isso à minha situação atual. oo ;;
TheBroodian
Você tem uma animação ... você está tentando animar em termos de posição ...
Blau
Perdoe-me, a razão pela qual estou tendo dificuldades é porque estou tentando inicializar essa ideia e traduzi-la em um sistema que funcione em um sistema velocidade = velocidade * tempo, enquanto esse sistema simplesmente cutuca a localização do objeto processualmente (nada de errado nisso, apenas difícil de encontrar a maneira correta de relacionar os dois).
TheBroodian