Вычисление угла (линии) между двумя точками на плоскости обтекания - PullRequest
3 голосов
/ 06 октября 2010

ОК, поэтому у меня есть игровое поле 512x512, которое округляется, -32 становится 512 для x и y.

Теперь мне нужно вычислить угол между двумя объектами, у меня есть следующий код в качестве своего рода обходного пути, он работает в большинстве случаев времени, но иногда все равно не получается:

Shooter.getAngle = function(a, b) {
    var ax = a.x;
    var bx = b.x;
    if (a.x < this.width / 4 && b.x > this.width - this.width / 4) {
        ax += this.width;

    } else if (a.x > this.width - this.width / 4 && b.x < this.width / 4) {
        bx += this.width;
    }

    var ay = a.y;
    var by = b.y;
    if (a.y < this.height / 4 && b.x > this.height - this.height / 4) {
        ay += this.height;

    } else if (a.y > this.height - this.height / 4 && b.y < this.height / 4) {
        by += this.height;
    }
    return this.wrapAngle(Math.atan2(ax - bx, ay - by) + Math.PI);
};

Я просто не могу понять, как проецировать a на b так, чтобы упаковка учитывалась правильно.

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

Для пояснения, если игрок движется вправо, ракета должна следовать за ним по краю поля к левой стороне, как это сделал бы другой игрок.

РЕДАКТИРОВАТЬ:

Вот тестовая версия, примеры показывают, что она переносится правильно, но в случаях, когда ей не нужно переносить, она ломается:

function getAngle(a, b) {
    var tx = a.x - b.x;
    var ty = a.y - b.y;

    // actual area goes from -16 to 512 due to the border space that's out of screen
    tx = ((tx + 16) % (480 + 32)) - 16;
    ty = ((ty + 16) % (480 + 32)) - 16;
    var r = Math.atan2(ty, tx) * (180 / Math.PI);

    // example
    // |> b                    a >|
    // a.x = 460
    // b.x = 60

    // missile should go over the right border
    // tx = 400 
    // r = 0
    // missile goes right, OK

    // example2
    // |< a                    b <|
    // a.x = 60
    // b.x = 460

    // missile should go over the left border
    // tx = -400 
    // r = 180
    // missile goes left, OK


    // example3
    // |     a  >>>>  b                  |
    // a.x = 60
    // b.x = 280

    // missile should go right
    // tx = -220
    // r = 180
    // missile goes left, WRONG

    // example4
    // |     b  <<<<  a                  |
    // a.x = 280
    // b.x = 60

    // missile should go left
    // tx = 220
    // r = 0
    // missile goes right, WRONG

    console.log(ty, tx);
    console.log(r);
}

function Point(x, y) {
    this.x = x;
    this.y = y;
}

getAngle(new Point(460, 240), new Point(60, 240));
getAngle(new Point(60, 240), new Point(460, 240));
getAngle(new Point(60, 240), new Point(280, 240));
getAngle(new Point(280, 240), new Point(60, 240));

Кажется, единственный способ заставить его работать, это проверять случаи, когда a.x < width * 0.25 и b.x > width * 0.75 и т. Д., Но это глючит, по крайней мере в версии, которую я выложил выше: /

Ответы [ 2 ]

5 голосов
/ 06 октября 2010

Я бы использовал этот подход: используйте цель в качестве центра вашей системы координат (и правильно оберните координаты ракеты), затем рассчитайте угол.Итак, псевдокод должен быть таким (EDIT2: исправленный код, аналогичная проблема также привела к проблемам в ваших тестах):

// missile.x/y = missile's coordinates
// target.x/y = target's coordinates
temp.x = missile.x - target.x;
temp.y = missile.y - target.y;

// The wrapping code - feel free to adjust,
// from the comments it seems you handle this
// a bit differently
while (temp.x < -240)
  temp.x += 480
while (temp.y < -240)
  temp.y += 480
while (temp.x > 240)
  temp.x -= 480
while (temp.y > 240)
  temp.y -= 480

// Now you can calculate the angle your missile must go,
// it has to fly across the line from temp.x/y to (0,0)

EDIT: я видел видео и думаю, что есть какая-то ошибкав вашем коде, но я не уверен, где.Использование математических функций и углов может быть немного сложнее, потому что обычно математические координаты имеют ось Y, идущую вверх, а экранные координаты имеют ось Y, направленную вниз.

Наилучшим способом сейчас может быть запуск теста некоторых модулей, что-то вродеэто:

// Create a function that returns the angle a missile must
// fly and cares about all the dirty details with wrapping etc.
MissileAngle(missile.x, missile.y, target.x, target.y)
// Now create some tests for it, f.e.:
MissileAngle(missile top left corner, target bottom right corner)
  Expected Result: Northwest
MissileAngle(missile bottom right corner, target top left corner)
  Expected Result: Southeast

Примечание. Я не использовал здесь координаты, потому что они сильно зависят от используемой вами системы координат, и это может на самом деле помочь вам лучше понять проблему (и, конечно,, надеюсь, поможет вам устранить ошибку, по крайней мере, это быстрый способ проверить, работает ли он правильно, без необходимости играть в реальную игру, которая требует больше времени).

0 голосов
/ 06 октября 2010

Просто чтобы сделать очевидное предположение: не должно ли это быть Math.atan2(ay-by,ax-bx)?Извиняюсь, если это была просто опечатка в вашем посте, но я, конечно, вижу, что это вызывает странное поведение в ваших ракетах.

Отредактировано, чтобы добавить: не важно, я только что увидела ваш комментарий.

...