Passer de A (x, y) à B (x1, y1) à vitesse constante?

21

J'ai actuellement quelque chose comme:

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

Et toutes les 0,01 secondes, je rafraîchis la position de mes objets comme ceci:

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

Cela déplace donc mon objet du point0 au point1 en 1 seconde. Ce dont j'ai besoin, c'est d'avoir les 2 points, pour pouvoir déplacer l'objet du point0, face (dans la direction de) point1 avec une vitesse constante. Ainsi, quand j'ai un point plus proche de mon point initial, l'objet se déplacera vers lui avec la même vitesse que si j'avais un point plus éloigné. Toutes les suggestions sont appréciées. Merci.

Fofole
la source
Duplicata possible: gamedev.stackexchange.com/questions/23430/… Je posterais la même réponse que j'ai donnée à l'autre question. Mais ce serait sans vergogne de ma part.
Gustavo Maciel

Réponses:

26

Je vais utiliser des structures d'algèbre linéaire car il est plus facile de décrire les opérations de cette façon. Dans le cas où vous ne savez pas comment implémenter ces opérations vectorielles, je donnerai une explication rapide à la fin.

Disons donc que vous commencez par ces valeurs: startet endmarquez les points finaux du mouvement, speedest le nombre de pixels qu'il doit déplacer par seconde, et elapsedest la vitesse à laquelle vous mettrez à jour la position de votre objet (certains moteurs fournissent déjà cette valeur pour vous ):

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

La première chose que vous voudrez calculer est la distance entre les deux points et un vecteur normalisé contenant la direction du début à la fin. En outre, vous devez "accrocher" la position de l'objet au startpoint. Cette étape n'est effectuée qu'une seule fois, au début:

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

Ensuite , sur votre méthode de mise à jour, vous déplacez l'objet en ajoutant une multiplication direction, speedet elapsedà sa position. Après cela, pour vérifier si le mouvement est terminé, vous voyez si la distance entre le point de départ et la position actuelle de l'objet est supérieure à la distance initiale que vous avez calculée. Si c'est vrai, nous alignons la position de l'objet sur le point final et arrêtons de déplacer l'objet:

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

Référence des opérations vectorielles rapides

Représentation

Vector2 A = float aX, aY;

Somme / soustraire

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

Multiplier par Scalar (float)

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

Longueur / distance

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

Normaliser

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

Cela devrait être suffisant pour convertir le code ci-dessus en opérations régulières si vous n'avez pas de Vectorclasse à votre disposition.


Exemple de conversion

// 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
la source
1
@Fofole C'est pourquoi j'ai donné l'explication sur les vecteurs à la fin. La réponse était censée être générique. Si vous n'avez pas de classe Vector, utilisez deux flotteurs distincts. Par exemple Vector2 start;devient float startX, startY;. Et vous pouvez facilement calculer la distance manuellement, comme je l'explique à la fin. C'est à dire float dX = bX - aX; float dY = bY - aY; float distance = Math.sqrt(dx*dx+dy*dy);.
David Gouveia
@Fafole Vérifiez l'édition, j'ai ajouté un exemple. Je ne sais pas si j'ai raté quelque chose.
David Gouveia
3 ans plus tard et vous venez de me faire comprendre comment déplacer des objets avec des vecteurs. À votre santé!
Oliver Schöning
3

Créez un vecteur et normalisez-le. Attention, certains pseudo-code avec de mauvais numéros à venir:

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

Cela vous donnera un vecteur comme:

25.96; 85.41

Normalisez maintenant le vecteur et vous recevrez ceci :

0.12; 0.75

De là, c'est le même mouvement qu'avec votre delta.

Policier
la source
2

Copié et collé de ma réponse à: Obtenir des points sur une ligne entre deux points

En pseudocode:

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
la source
Cette réponse a fonctionné le mieux pour mon cas d'utilisation.
shell le