Passando de A (x, y) para B (x1, y1) com velocidade constante?

21

Atualmente, tenho algo como:

float deltaX = point0.getX() - point1.getX();
float deltaY = point0.getY() - point1.getY();

E a cada 0,01 segundo, atualizo minha posição dos objetos da seguinte maneira:

object.setPosition(object.getX()-deltaX/100,object.getY()-deltaY/100);

Então isso move meu objeto do ponto0 para o ponto1 em 1 segundo. O que eu preciso é ter os 2 pontos, para poder mover o objeto do ponto0, enfrentando (na direção do) ponto1 com uma velocidade constante. Assim, quando eu tenho um ponto mais próximo do meu ponto inicial, o objeto se move em direção a ele com a mesma velocidade que faria se eu tivesse um ponto mais distante. Todas as sugestões são apreciadas. Obrigado.

Fofole
fonte
Possível duplicata: gamedev.stackexchange.com/questions/23430/… Gostaria de postar a mesma resposta que dei à outra pergunta. Mas isso seria vergonhoso da minha parte.
Gustavo Maciel

Respostas:

26

Usarei algumas estruturas de álgebra linear, pois é mais fácil descrever as operações dessa maneira. Caso você não saiba como implementar essas operações de vetor, darei uma explicação rápida no final.

Então, digamos que você comece com esses valores: starte endmarque os pontos finais do movimento, speedé quantos pixels ele deve mover por segundo e elapsedé a taxa na qual você atualizará a posição do seu objeto (alguns mecanismos já fornecem esse valor para você ):

Vector2 start = new Vector2(x1, y2);
Vector2 end = new Vector2(x2, y2);
float speed = 100;
float elapsed = 0.01f;

A primeira coisa que você deseja calcular é a distância entre os dois pontos e um vetor normalizado que contém a direção do início ao fim. Além disso, você deve "ajustar" a posição do objeto ao startponto. Esta etapa é realizada apenas uma vez, no início:

float distance = Vector2.Distance(start, end);
Vector2 direction = Vector2.Normalize(end - start);
object.Position = start;
moving = true;

Em seguida, em seu método de atualização, você mover o objeto, adicionando uma multiplicação de direction, speede elapsedpara a sua posição. Depois disso, para verificar se o movimento terminou, você vê se a distância entre o ponto inicial e a posição atual do objeto é maior que a distância inicial calculada. Se isso for verdade, ajustamos a posição do objeto ao ponto final e paramos de movê-lo:

if(moving == true)
{
    object.Position += direction * speed * elapsed;
    if(Vector2.Distance(start, object.Position) >= distance)
    {
        object.Position = end;
        moving = false;
    }
}

Referência Rápida de Operações de Vetor

Representação

Vector2 A = float aX, aY;

Soma / Subtração

A+B = a.x + b.x; a.y + b.y;
A-B = a.x - b.x; a.y - b.y;

Multiplique por escalar (flutuador)

A*float = a.x*float; a.y*float;

Comprimento / Distância

length(A) = sqrt(a.x*a.x + a.y*a.y)
distance(A,B) = length(B-A)

Normalizar

normalize(A) = a.X/length(A); a.Y/length(A);

Isso deve ser suficiente para converter o código acima em operações regulares, se você não tiver uma Vectorclasse disponível.


Exemplo de conversão

// Your Variables
float startX, startY, endX, endY;
float speed = 100;
float elapsed = 0.01f;

// On starting movement
float distance = Math.sqrt(Math.pow(endX-startX,2)+Math.pow(endY-startY,2));
float directionX = (endX-startX) / distance;
float directionY = (endY-startY) / distance;
object.X = startX;
object.Y = startY;
moving = true;

// On update
if(moving == true)
{
    object.X += directionX * speed * elapsed;
    object.Y += directionY * speed * elapsed;
    if(Math.sqrt(Math.pow(object.X-startX,2)+Math.pow(object.Y-startY,2)) >= distance)
    {
        object.X = endX;
        object.Y = endY;
        moving = false;
    }
}
David Gouveia
fonte
11
@Fofole É por isso que expliquei os vetores no final. A resposta deveria ser genérica. Se você não tem uma classe Vector, use dois carros alegóricos separados. Por exemplo, Vector2 start;torna-se float startX, startY;. E você pode calcular facilmente a distância manualmente, como explico no final. Ou seja float dX = bX - aX; float dY = bY - aY; float distance = Math.sqrt(dx*dx+dy*dy);.
David Gouveia
@Fafole Verifique a edição, adicionei um exemplo. Não tenho certeza se eu perdi alguma coisa.
David Gouveia
3 anos depois e você me fez entender como mover objetos com vetores. Felicidades!
Oliver Schöning
3

Crie um vetor e normalize-o. Atenção, algum pseudo-código com números errados à frente:

Vector = new Vector(point0.getX() - point1.getX(), point0.getY() - point1.getY());

Isso lhe dará um vetor como:

25.96; 85.41

Agora normalize o vetor e você receberá este :

0.12; 0.75

A partir daqui, é o mesmo movimento do seu delta.

Bobby
fonte
2

Copiado e colado da minha resposta para: Obter pontos em uma linha entre dois pontos

No pseudocódigo:

speed_per_tick = 0.05 //constant speed you want the object to move at
delta_x = x_goal - x_current
delta_y = y_goal - y_current
goal_dist = sqrt( (delta_x * delta_x) + (delta_y * delta_y) )
if (dist > speed_per_tick)
{
    ratio = speed_per_tick / goal_dist
    x_move = ratio * delta_x  
    y_move = ratio * delta_y
    new_x_pos = x_move + x_current  
    new_y_pos = y_move + y_current
}
else
{
    new_x_pos = x_goal 
    new_y_pos = y_goal
}
Tristan
fonte
Essa resposta funcionou melhor para o meu caso de uso.
shell