Переход от A (x, y) к B (x1, y1) с постоянной скоростью?

21

В настоящее время у меня есть что-то вроде:

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

И каждые 0,01 секунды я обновляю положение моих объектов следующим образом:

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

Так что это перемещает мой объект из точки 0 в точку 1 за 1 секунду. Что мне нужно, так это иметь 2 точки, чтобы иметь возможность перемещать объект из точки 0 в направлении (в направлении) точки 1 с постоянной скоростью. Таким образом, когда у меня есть точка ближе к моей начальной точке, объект будет двигаться к ней с той же скоростью, что и у меня, если у меня будет более удаленная точка. Любые предложения приветствуются. Благодарю.

Fofole
источник
Возможный дубликат: gamedev.stackexchange.com/questions/23430/… Я бы отправил тот же ответ, что и на другой вопрос. Но это было бы бесстыдно с моей стороны.
Густаво Масиэль

Ответы:

26

Я буду использовать некоторые линейные алгебраические структуры, поскольку таким образом описать операции проще. В случае, если вы не знаете, как реализовать эти векторные операции, в конце я дам краткое объяснение.

Допустим, вы начинаете с этих значений: startи endотмечаете конечные точки движения, speedсколько пикселей должно двигаться в секунду, и elapsedскорость, с которой вы будете обновлять позицию вашего объекта (некоторые движки уже предоставляют это значение для вас ):

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

Первое, что вы хотите вычислить, это расстояние между обеими точками и нормализованный вектор, содержащий направление от начала до конца. Также вы должны «привязать» положение объекта к startточке. Этот шаг выполняется только один раз, в начале:

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

Затем на вашем методе обновления, вы перемещаете объект, добавив умножение direction, speedи elapsedего позиции. После этого, чтобы проверить , если движение закончится, вы видите , если расстояние между начальной точкой и текущим положением объекта является больше , чем начальное расстояние Вы вычислили. Если это так, мы привязываем позицию объекта к конечной точке и прекращаем перемещение объекта:

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

Справочник по быстрым векторным операциям

Представление

Vector2 A = float aX, aY;

Сумма / Вычесть

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

Умножить на Скаляр (float)

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

Длина / Расстояние

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

Нормализовать

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

Этого должно быть достаточно для преобразования приведенного выше кода в обычные операции, если у вас нет Vectorкласса, доступного для вас.


Пример конвертации

// 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;
    }
}
Дэвид Гувея
источник
1
@Fofole Вот почему я дал объяснение векторов в конце. Ответ должен был быть общим. Если у вас нет класса Vector, используйте два отдельных плавающих элемента. Например Vector2 start;становится float startX, startY;. И вы можете легко рассчитать расстояние вручную, как я объясню в конце. То есть float dX = bX - aX; float dY = bY - aY; float distance = Math.sqrt(dx*dx+dy*dy);.
Дэвид Гувейя
@Fafole Проверьте редактирование, я добавил пример. Не уверен, что я что-то пропустил.
Дэвид Гувея
3 года спустя, и вы только что заставили меня понять, как перемещать объекты с помощью векторов. Ура!
Оливер Шенинг,
3

Создайте Вектор и нормализуйте его. Внимание, впереди некоторый псевдокод с неправильными номерами:

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

Это даст вам такой вектор:

25.96; 85.41

Теперь нормализуйте вектор, и вы получите это :

0.12; 0.75

Отсюда это то же движение, что и с вашей дельтой.

Бобби
источник
2

Скопировано и вставлено из моего ответа на: Получите очки на линии между двумя точками

В псевдокоде:

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
}
Тристан
источник
Этот ответ работал лучше всего для моего варианта использования.
ракушка