Я играю в небольшую 2D танковую башню, где вы поворачиваете танк в середине экрана, нажимаете левую кнопку, а затем немного снаряда перемещается в это место.
Сейчас я нахожусь в точке, где у меня есть текущее местоположение и желаемое местоположение, что мне нужно сделать сейчас, чтобы получить величину этих двух точек, которая должна либо вернуть 1, либо 0.
Это моя функция C ++ VectorClass:
float vector2D::magnitude(vector2D vec2)//<! Vector magnitude
{
float result;
result = (sqrt(x*vec2.x)+(y*vec2.y));
return result;
}
Это код, где я нормализую желаемое и текущее местоположение:
currentPos.x = laserTexture.getSize().x/2.0f;
currentPos.y = laserTexture.getSize().y/2.0f;
desiredPos.x = sf::Mouse::getPosition().x;
desiredPos.y = sf::Mouse::getPosition().y;
normalisedLocation = magnitude(desiredPos - currentPos);
Текущее положение привязано к середине моей лазерной текстуры, которая является фиксированной точкой поворота в середине экрана.
Мое желаемое местоположение — щелчок мышью, который возвращает положение в X и Y (Это работает).
Математика не моя сильная сторона, поэтому, когда дело доходит до программирования такого рода вещей, я борюсь больше, чем другие люди, так что это занимает намного больше времени / я просто придумаю какое-то не очень элегантное решение.
Моя конечная цель состоит в том, чтобы получить нормализованное местоположение, а затем, когда будет нажата левая кнопка мыши, турель-танк выстрелит, и снаряд получит перемещение в нужное место.
Итак, чтобы уточнить:
Спасибо
объявление 1.) «Является ли моя функция величины правильно?»
Нет, у вас есть небольшая ошибка в вашем maginutude()
метод. С уважением:
result = (sqrt(x*vec2.x)+(y*vec2.y));
является
result = sqrt(x*vec2.x)+(y*vec2.y);
является
result = sqrt(x*vec2.x) + (y*vec2.y);
но вы, вероятно, хотели написать это:
result = sqrt((x*vec2.x)+(y*vec2.y));
РЕДАКТИРОВАТЬ:
Я изначально писал что sqrt(x*vec2.x+y*vec2.y)
правильно, но это не так, правильно это:
result = sqrt(vec2.x*vec2.x + vec2.y*vec2.y);
и это потому, что OP хотел рассчитать величину только vec2, нет необходимости использовать this.x
а также this.y
, По этой причине я бы также предложил изменить ваш метод на статический:
static float vector2D::magnitude(vector2D vec2)//<! Vector magnitude
{
return sqrt((vec2.x*vec2.x)+(vec2.y*vec2.y));
}
или используйте только значения экземпляров:
float vector2D::magnitude()//<! Vector magnitude
{
return sqrt((x*x)+(y*y));
}
во втором случае вам необходимо использовать magnitude()
метод как это:
(desiredPos - currentPos).magnitude();
Дальнейшие заметки:
desiredPos
а также currentPos
,(desiredPos - currentPos)
на величину, вы получите нормализованный вектор, который является направлением от currentPos
в desiredPos
,desiredPos
а также currentPos
равны, величина равна нулю, и вы не могу нормализовать вектор.normalisedLocation
переменная. Это расстояние, как указано выше.Объявление 2.) «Правильно ли я нормализую желаемые и текущие позиции?»
Я не уверен, как понять этот вопрос, потому что вы ничего не нормализуете в коде примера. В любом случае, посмотрите на это:
// This is from your code:
currentPos.x = laserTexture.getSize().x/2.0f;
currentPos.y = laserTexture.getSize().y/2.0f;
desiredPos.x = sf::Mouse::getPosition().x;
desiredPos.y = sf::Mouse::getPosition().y;
// Store direction to desired position. Currently length of this vector is
// distance between the two points.
vector2D dirToDesiredPos = (desiredPos - currentPos);
// Calculate distance between the two points.
float dirToDesiredPosDist = magnitude(desiredPos - currentPos);
// Detect whether the distance is zero. Problem is, you cannot compare float
// with zero (computer is not accurate enough) so we compare it with a delta
// value. It should be some small number, for example 0.01f.
// (Note that in this case we don't need to compare it with negative value -
// which would be -0.01f, because distance is always positive or zero.)
if(dirToDesiredPosDist < FLOAT_DELTA)
{
// User clicked on the tank, we cannot shoot!!!
}
else
{
// Following two lines do actuall normalization - direction of this vector
// is unchanged, but it's length is currently 1.
dirToDesiredPos.x /= dirToDesiredPosDist;
dirToDesiredPos.y /= dirToDesiredPosDist;
// Now dirToDesiredPos can be used to calculate to move your bullet to the
// desired location.
}
Однако есть все еще подвох. Это следующие строки:
currentPos.x = laserTexture.getSize().x/2.0f;
currentPos.y = laserTexture.getSize().y/2.0f;
При этом вы вычисляете центр лазерной текстуры, однако это положение корректно, только если лазер визуализируется в позиции [0, 0]. В противном случае вам нужно обновить его так:
currentPos.x = laserTexture.getSize().x/2.0f + laserPos.x;
currentPos.y = laserTexture.getSize().y/2.0f + laserPos.y;
где laserPos
это позиция, где находится ваш лазер.
Норма вектора — это квадратный корень из суммы квадратов его координат. Ваш метод должен быть:
float vector2D::magnitude(vector2D vec2)
{
return sqrt(vec2.x * vec2.x + vec2.y * vec2.y);
}
Величина вашего вектора, то есть его длина, будет
float vector2D::magnitude() const
{
return sqrt(x*x + y*y);
}
(Это гипотенуза прямоугольного треугольника со сторонами x и y.)
Чтобы нормализовать вектор, то есть получить вектор с тем же направлением, но длиной 1, вы делите его координаты на его величину:
vector2D vector2D::normalise() const
{
float length = magnitude();
// Do something suitable to handle the case where the length is close to 0 here...
return vector2D(x / length, y / length);
}
и ваша последняя строка будет
normalisedDirection = (desiredPos - currentPos).normalise();
или более многословный
vector2D direction = desiredPos - currentPos;
normalisedDirection = location.normalise();
(Я переименовал переменную, чтобы уточнить, что мы вычисляем направление, а не местоположение.)
Кроме того, вы можете использовать бесплатные функции:
float magnitude(vector2D v)
{
return sqrt(v.x * v.x + v.y * v.y);
}
vector2D normalise(vector2D v)
{
float length = magnitude(v);
v.x /= length;
v.y /= length;
return v;
}
// ...
normalisedDirection = normalise(desiredPos - currentPos);
Примечание:
У вас есть опечатка в вашей функции, которая делает его очень некорректным:
(sqrt(x*vec2.x)+(y*vec2.y));
выглядит очень похоже
sqrt((x*vec2.x)+(y*vec2.y));
из-за двух скобок в конце, но это на самом деле
sqrt(x * vec2.x) + y * vec2.y;
Чтобы избежать подобных проблем, во-первых: не бойтесь пробела, а во-вторых: не используйте слишком много скобок.
зачем вам нужна величина? вам нужно направление, которое является углом (градусы или радианы). поскольку у вас уже есть базовая позиция танка и желаемое место, где вы щелкнули мышью, из этого вам нужно будет рассчитать, под каким углом находятся эти точки. немного пифагора и тригонометрия, вы можете определить угол, повернуть танк на этот угол, запустить снаряд в том же направлении.