Почему мой объект движется быстрее на 45 градусов, чем на 90 градусов?

32

В моей игре есть объекты, которые движутся быстрее на 45 градусов, чем на 90 градусов.

Каждый объект имеет

  • Точка (х, у) позиция
  • Направление Vector2D (x, y)
  • Int скорость

И что я делаю во время обновления, так это то, что новая позиция рассчитывается как:

position.x += direction.x * speed
position.y += direction.y * speed

Как мне это исправить? Я хочу, чтобы он двигался с одинаковой скоростью под любым углом.

Jason94
источник
8
Нормализуйте вектор направления перед использованием; проблема решена.
замедленная
1
Пришлось нормализовать гугл :) нашел этот полезный
Jason94
И если вы используете пользовательский ввод для управления этим объектом, помните о блокировке в 12,3,6,9 направлениях, как описано здесь для разработчиков XNA: xona.com/2010/05/03.html . Это может быть что-то, что вы хотите (например, в игре RPG) или нет (например, в игре в стиле Geometry Wars).
Ксонатрон
в старой игре Descent это была фича .
Дж. Холмс
@ 32bitkid Да, смотрите также Doom straferunning
bobobobo

Ответы:

55

Это можно объяснить с помощью теоремы Пифагора , которая имеет следующую формулу:

a² + b² = c²

В вашем случае при движении вправо вы используете (x: 1, y: 0), что дает нам

c² = 1 + 0 = 1
c = sqrt(1) = 1.00

При движении вверх и вправо вы используете (x: 1, y: 1), что дает нам

c² = 1 + 1 = 2
c = sqrt(2) = 1.41

Итак, как вы можете видеть, длина по диагонали больше, чем длина по кардинальным осям.

Как уже упоминали другие, вы должны просто нормализовать ваш вектор направления. Если вы используете XNA, это делается так:

var normalizedDirection = direction;
normalizedDirection.Normalize();
position += normalizedDirection * speed
Уильям Мариажер
источник
Я даю вам +1 за вашу помощь в моем вопросе :)
Мартин.
12

Нормализуйте вектор направления перед использованием.

Как объяснил MindWorX, это может быть просто понято, если вы беспокоитесь о своих векторах направления, которые могут причинить вам горе, убедитесь, что они являются единичными векторами (величина / длина 1).

Length(Vector2(1, 1)) == 1.4142135623730951 // first hint of grief
Length(Vector2(1, 0)) == 1

Vector2(1, 1) * 2 == Vector2(2, 2)
Vector2(1, 0) * 2 == Vector2(2, 0)

Length(Vector2(2, 2)) = 2.8284271247461903 // second hint
Length(Vector2(2, 0)) = 2

Если нормализовано:

normal(Vector2(1, 1)) == Vector2(0.707107, 0.707107)
Length(Vector2(0.707107, 0.707107)) == 1 // perfect
deceleratedcaviar
источник
14
Не полезный ответ. Если бы спрашивающий знал, что означает «нормализовать вектор направления», он бы не задал вопрос.
Кристофер Джонсон
@KristopherJohnson было не ясно, спрашивающий не знает, как нормализовать вектор. Хотя спрашивающий кажется достаточно изобретательным, чтобы это все равно не имело значения.
замедленная
2
@KristopherJohnson: если спрашивающий не знал, что означает «нормализовать вектор направления», ему просто нужно ввести это в Google, добавить название своего языка и получить код с пояснениями.
Ли Райан
6

Как вы рассчитываете свое направление? Если 45 градусов (1,1), то это, безусловно, будет быстрее, чем 90 градусов (1,0).

Я предлагаю вам использовать что-то вроде этого:

direction.x = Math.Cos(angleInRadians);
direction.y = Math.Sin(angleInRadians);

Чтобы получить угол в радианах, вам нужно умножить свои градусы на PI / 180или даже лучше, используйте MathHelper. Например.

angleInRadians = 45.0 * Math.PI / 180.0; // first method
angleInRadians = MathHelper.ToRadians(45f); //second method
bummzack
источник
6

Джейсон,

Вместо того, чтобы иметь три атрибута объекта,

  • Точка (х, у) позиция
  • Направление Vector2D (x, y)
  • Int скорость

часто намного проще объединить направление и скорость в вектор скорости. Тогда у вас есть только два атрибута,

  • Точка (х, у) позиция
  • Vector2D (x, y) скорость

Обновление позиции

Когда вам нужно обновить позицию объекта, это так просто:

position.x += velocity.x * Δt;
position.y += velocity.y * Δt;

где Δtваша дельта времени - или разница во времени - или шаг по времени.

Обновление позиции и скорости

Это также очень легко справиться с ускорением (например, от силы тяжести). Если у вас есть вектор ускорения, вы можете обновить скорость и положение вместе следующим образом:

position.x += (velocity.x * Δt) + (0.5 * acceleration.x * Δt * Δt);
position.y += (velocity.y * Δt) + (0.5 * acceleration.y * Δt * Δt);

velocity.x += acceleration.x * Δt;
velocity.y += acceleration.y * Δt;

(Это в основном формула s = vt + ½at² из физики 101.)

Применяя скорость

Если вы хотите применить заданную скорость в некотором нормализованном направлении, вы можете установить скорость следующим образом:

velocity.x = normalizedDirection.x * speed;
velocity.y = normalizedDirection.y * speed;

Получение скорости

И если вам нужно сделать обратное - вывести скорость и направление из заданного вектора скорости - вы можете просто использовать теорему Пифагора или .Length()метод:

speed = velocity.Length();

И как только скорость известна, нормализованное направление может быть вычислено путем деления скорости на скорость (будьте осторожны, чтобы не делить на ноль):

if (speed != 0) {
    normalizedDirection.x = velocity.x / speed;
    normalizedDirection.y = velocity.y / speed;
} else {
    normalizedDirection.x = 0;
    normalizedDirection.y = 0;
}
Тодд Леман
источник