2D игровой алгоритм для вычисления необходимой скорости маркера для достигания целевого показателя?

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

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

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

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

9
задан Philipp Lenssen 9 July 2010 в 13:53
поделиться

5 ответов

Использование векторов может сделать математику вокруг этого немного проще. Sylvester кажется многообещающей реализацией векторов в 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)); 
}
3
ответ дан 4 December 2019 в 13:44
поделиться

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

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

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

По расстоянию между исходной точкой пули и точкой пересечения (и ранее рассчитанному времени) вы можете рассчитать скорость пули.

0
ответ дан 4 December 2019 в 13:44
поделиться

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

1
ответ дан 4 December 2019 в 13:44
поделиться

Некоторые физические соображения

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

Поэтому вы должны решить ВЕКТОРНОЕ уравнение

Positionbullet [ time=t1 > t0 ] == Positiontarget [ time=t1 > t0 ] -- (Eq 1)

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

Positionobject [ t ] = Positionobject [ t0 ] + Speedobject * ( t - t0 )

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

Xbullet [ t0 ]. + SpeedXbullet * ( t - t0 ) = Xtarget [ t0 ] + SpeedXtarget * ( t - t0 )

Поэтому для времени столкновения имеем

( tCollision - t0 ) = (xtarget [ t 0 ] - xпуля [ t0 ] ) / (SpeedXbullet - SpeedXtarget) -- (Eq 2)

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

Sign ( xtarget[ t0 ] - xпуля[ t0 ] ) = Sign ( SpeedXbullet - SpeedXtarget ) -- (Eq 3)

Что говорит нам о том очевидном факте, что если объект движется быстрее другого и в том же направлении, то в конце концов они столкнутся.

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

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

Расстояние [ Positiontarget [ tCollision - t0 ] - Позицияпуля [ t0 ] ] < BulletRange -- (Eq 4)

Что все еще допускает бесконечные решения, но ограниченные верхним значением для времени столкновения, заданным тем фактом, что цель может покинуть дистанцию.
Далее, расстояние задается

Distance[v,u]= +Sqrt[ (Vx-Ux)^2 + (Vx-Vy)^2 ]

Таким образом, Eq 4 становится,

(Xtarget[tCollision - t0]). - Xbullet[t0])2 + (Ytarget[tCollision - t0] - Ybullet[t0])2 < BulletRange2 -- (Eq 5)

Заметим, что { Xbullet[t0] , Ybullet[t0} является положением башни.

Теперь, подставляя в Eq 5 значения для положения цели:

(Xtarget[t0] + SpeedXtarget * (t-t0) - Xbullet[t0])2 + (Ytarget[t0) + SpeedYtarget * (t-t0) - Ybullet[t0])2 < BulletRange2 -- (Eq 6)

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

Dxt0 = Xtarget[t0] - Xbullet[t0]

и

Dyt0 = Ytarget[t0] - Ybullet[t0]

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

(Dtx0 + SpeedXtarget * (t-t0) )2 + (Dty0 + SpeedYtarget * (t-... t0))2 < BulletRange2 -- (Eq 7)

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

Теперь вызов

Speedtarget 2 = SpeedXtarget 2 + SpeedYtarget 2

и.

H = Dtx0 * SpeedXtarget + Dty0 * SpeedYtarget


TCollision Max = t0 - ... ( H +/- Sqrt ( BulletRange2 * Speedtarget 2 - H2 ) ) / Speedtarget 2

Таким образом, вам нужно произвести столкновение ДО этого времени. Знак квадратного корня должен быть взят таким образом, чтобы время было больше t0

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  

SpeedXbullet = ( Xцель [ t0 ] - Xпуля [ t0 ] ) / ( tСтолкновение - t0 ) + SpeedXцель

и

SpeedYbullet = ( Ytarget [ t0 ] - Yпуля [ t0 ] ) / ( tCollision - t0 ) + SpeedYtarget

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

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

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

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

NewBulletRange = BulletRange + RTarget + RTower

Пули неограниченной дальности

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

5
ответ дан 4 December 2019 в 13:44
поделиться

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

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)

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

6
ответ дан 4 December 2019 в 13:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: