2D игровой алгоритм для расчета необходимой скорости пули, чтобы поразить цель? - PullRequest
9 голосов
/ 09 июля 2010

У меня довольно простая 2D-игра с высоты птичьего полета, где спрайты башен защищаются от входящих движущихся спрайтов, стреляя в них пулями. Мой вопрос: как рассчитать необходимую скорость пули, чтобы пуля достигла своей движущейся цели, при условии, что пуля всегда будет иметь одинаковую заданную скорость?

Я использую JavaScript, и у меня есть эти переменные спрайта (среди прочих): sprite.x, sprite.y, sprite.width, sprite.height, sprite.speedX (то есть скорость), sprite.speedY ... поэтому у меня есть объекты originSprite, targetSprite и bulletSprite, все с этими типами значений, и я Нужно установить правильные значения скорости bulletSprite.

Вероятно, для того, чтобы он выглядел хорошо, пуля должна начинаться с внешней стороны originSprite (или некоторого определенного радиуса, хотя я полагаю, что начиная с центра originSprite также будет работать), но ее центр пули будет пытаться попасть в центр targetSprite или около того. Обратите внимание, что в этом мире нет гравитации или чего-то еще. (Возможно, у меня должны быть мои переменные спрайтов, использующие угол и скорость, но сейчас я использую speedX и speedY ...)

Большое спасибо!

Ответы [ 5 ]

6 голосов
/ 09 июля 2010

Рассматривайте спрайт целей как прямую линию в двухмерной комнате, где:

A(time) = (sprite.positionX + sprite.speedX * time, sprite.positionX + sprite.speedX * time)

Поскольку ваша пуля имеет постоянную скорость, вы также знаете:

bullet.speedX^2 + bullet.speedY^2 = bullet.definedSpeed^2

Тогда вы также можетевычислите прямую линию для пули:

B(time) = (bullet.positionX + bullet.speedX * time, bullet.positionX + bullet.speedX * time)

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

A(time) = B(time)

Тогда вам решать эти уравнения с заданными значениями и искатьминимум для time.

5 голосов
/ 09 июля 2010

Некоторая физическая проницательность

1) Для цели, являющейся «точечным объектом»

Таким образом, вы должны решить векторное уравнение

Позиция пуля [время = t 1 > t 0 ] == Позиция цель [время = t 1 > т 0 ] - (уравнение 1)

Где позиции задаются уравнениями движения (также ВЕКТОРА)

Позиция объект [т] = Позиция объект 0 ] + Скорость объект * (т - т 0 )

Теперь условием, чтобы пуля могла достичь цели, является то, что уравнение 1 имеет решения для x и y. Запишем уравнение для х:

X bullet [t 0 ] + SpeedX bullet * (t - t 0 ) = X target [t 0 ] + SpeedX target * (t - t 0 )

Итак, на время столкновения у нас есть

(t Столкновение - t 0 ) = (x target [t 0 ] - x bullet [t 0 ]) / (SpeedX bullet - SpeedX target ) - (Eq 2)

Поскольку нам нужны решения с t> t 0 , это означает, что для перехвата достаточно, чтобы>

Знак (x цель [t 0 ] - x bullet [t 0 ]) = Знак (SpeedX bullet - SpeedX target ) - (Уравнение 3)

Which tells us the evident fact that if an object is moving faster than the other, and in the same direction, they will eventually collide.

Из уравнения 2 видно, что для данной цели SpeedX target существуют бесконечные решения (как уже указывалось в других ответах) для t и SpeedX bullet , поэтому я думаю, что ваши спецификации не полны.

I guess (as stated in a commentary I made in another answer) thinking in a "tower defense" kind of game, that your bullets have a limited range.
Так что вам нужно еще одно ограничение:

Расстояние [Позиция цель Столкновение - т 0 ] - Позиция пуля 0 ]]

Which still permits infinite solutions, but bounded by an upper value for the Collision time, given by the fact that the target may abandon the range.
Далее расстояние определяется как

Расстояние [v, u] = + Sqrt [(Vx-Ux) ^ 2 + (Vx-Vy) ^ 2]

Итак, уравнение 4 становится,

цель Столкновение - т 0 ] - Х пуля 0 ]) 2 + (Y цель [t Столкновение - t 0 ] - Y bullet [t 0 ]) 2 2 - (уравнение 5)

Обратите внимание, что {X bullet [t 0 ], Y bullet [t 0 } - это положение башни.

Теперь, заменив в уравнении 5 значения для целевой позиции:

(X target [t 0 ] + SpeedX target * (tt 0 ) - X bullet [t 0 ]) 2 + (Y target [t 0 ] + SpeedY target * (tt 0 ) - Y bullet [t 0 ]) 2 2 - (уравнение 6)

Называя начальные расстояния:

Dxt0 = X цель [t 0 ] - X bullet [t 0 ]

и

Dyt0 = Y target [t 0 ] - Y bullet [t 0 ]

Уравнение 6 становится

(Dtx0 + SpeedX target * (tt 0 )) 2 + (Dty0 + SpeedY target * (tt 0 )) 2 2 - (уравнение 7)

Какое квадратное уравнение решается в t-t0. Положительное решение даст нам наибольшее время, отведенное для столкновения. После этого цель будет вне диапазона.

Сейчас звонит

Скорость цель 2 = СкоростьX цель 2 + Скорость Y цель 2

и

H = Dtx0 * SpeedX цель + Dty0 * SpeedY цель


T Максимальное столкновение = t 0 - (H +/- Sqrt (BulletRange 2 * Скорость цель 2 - В 2 )) / скорость цель 2

So you need to produce the collision BEFORE this time. The sign of the square root should be taken such as the time is greater than t<sub>0</sub></p> <pre><code>After you select an appropriate flying time for your bullet from the visual effects point of view, you can calculate the SpeedX and SpeedY for the bullet from

SpeedX bullet = (X target [t 0 ] - X bullet [t 0 ]) / (t Столкновение - t 0 ) + SpeedX target

и

SpeedY bullet = (Y target [t 0 ] - Y bullet [t 0 ]) / (т Столкновение - т 0 ) + Скорость Y цель

2) Для цели и башни, являющейся «Обширными объектами»

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

Итак, заменив BulletRange на (BulletRange + R), вы получите новые уравнения для максимально допустимого времени столкновения.

Если вы также хотите учесть радиус для пушек, примените те же соображения, давая «двойной расширенный диапазон»

NewBulletRange = BulletRange + R Target + R Башня

Пули с неограниченным радиусом действия

В случае, если вырешите, что некоторые особые маркеры не должны иметь ограничений по дальности (и обнаружению), все еще есть ограничение границы экрана. Но это немного сложнее для решения. Если вам нужен такой вид снаряда, оставьте комментарий, и я постараюсьсделать математику.

3 голосов
/ 09 июля 2010

Использование векторов может сделать математику вокруг немного более простой. Сильвестр представляется многообещающей реализацией векторов в JavaScript, но для целей моего примера я напишу свои собственные векторные функции.Я также собираюсь предположить, что .x / .y измеряется в верхнем / левом углу.

// this is a "constant"  - representing 10px motion per "time unit"
var bulletSpeed = 10; 
// calculate the vector from our center to their center
var enemyVec = vec_sub(targetSprite.getCenter(), originSprite.getCenter());
// measure the "distance" the bullet will travel
var dist = vec_mag(enemyVec);
// adjust for target position based on the amount of "time units" to travel "dist"
// and the targets speed vector
enemyVec = vec_add(enemyVec, vec_mul(targetSprite.getSpeed(), dist/bulletSpeed));
// calculate trajectory of bullet
var bulletTrajectory = vec_mul(vec_normal(enemyVec), bulletSpeed);
// assign values
bulletSprite.speedX = bulletTrajectory.x;  
bulletSprite.speedY = bulletTrajectory.y;  

// functions used in the above example:

// getCenter and getSpeed return "vectors"
sprite.prototype.getCenter = function() { 
  return {
    x: this.x+(this.width/2), 
    y: this.y+(this.height/2) 
  }; 
};

sprite.prototype.getSpeed = function() { 
  return {
    x: this.speedX, 
    y: this.speedY 
  }; 
};

function vec_mag(vec) { // get the magnitude of the vector
  return Math.sqrt( vec.x * vec.x + vec.y * vec.y); 
 }
function vec_sub(a,b) { // subtract two vectors
  return { x: a.x-b.x, y: a.y-b.y };
}
function vec_add(a,b) { // add two vectors
  return { x: a.x + b.x, y: a.y + b.y };
}
function vec_mul(a,c) { // multiply a vector by a scalar
  return { x: a.x * c, y: a.y * c };
}
function vec_div(a,c) { // divide == multiply by 1/c
  return vec_mul(a, 1.0/c);
}
function vec_normal(a) { // normalize vector
  return vec_div(a, vec_mag(a)); 
}
1 голос
/ 09 июля 2010

Вычислить расстояние между стрелком и целью: dist = sqrt((xt - xs)^2 + (yt - ys)^2)
Разделите расстояния x и y на указанное выше: nx = (xt - xs)/dist; ny = (yt - ys)/dist; (нормализация вектора)
Умножьте результаты на коэффициент, чтобы получить n пикселей за единицу времени, т.е. скорость в каждом направлении. Он должен давать постоянную скорость в нужном направлении.

0 голосов
/ 09 июля 2010

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

Если оба направления и скорость пули являются переменными (то есть вы пытаетесь вычислить speedX и speedY для пули), существует бесконечно много решений.

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

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

...