2D 游戏算法来计算子弹击中目标所需的速度?

发布于 2024-09-08 18:31:42 字数 494 浏览 1 评论 0原文

我有一个相当简单的鸟瞰 2D 游戏,其中塔精灵通过向移动精灵射击子弹来防御它们。我的问题:如果子弹始终具有相同的定义速度,如何计算子弹到达其移动目标所需的子弹速度?

我正在使用 JavaScript 并拥有这些精灵变量(以及其他变量): sprite.x,sprite.y,sprite.width,sprite.height,sprite.speedX(即速度),sprite.speedY ...所以我有对象originSprite,targetSprite和bulletSprite,它们都具有这些类型的值,并且我需要设置正确的bulletSprite速度值。

也许为了看起来不错,子弹将从 originSprite 的外部开始(或某个定义的半径,尽管我猜从 originSprite 中心开始也可以),但它的子弹中心会尝试击中 targetSprite 的中心或所以。请注意,这个世界上没有重力或任何东西。 (也许我应该使用角度和速度来设置精灵变量,但现在我使用的是 speedX 和 speedY...)

非常感谢!

I have a rather simple bird's-view 2D game where tower sprites defend against incoming moving sprites by shooting a bullet at them. My question: How do I calculate the needed bullet speed for the bullet to reach its moving target, provided that the bullet will always have the same defined speed?

I'm using JavaScript and have these sprite variables (among others):
sprite.x, sprite.y, sprite.width, sprite.height, sprite.speedX (i.e. velocity), sprite.speedY... so I have the objects originSprite, targetSprite and bulletSprite, all with these type of values, and I need to set the right bulletSprite speed values.

Probably for it to look good, the bullet would start at the outside of the originSprite (or some defined radius, though I guess starting from the originSprite center would also work), but its bullet center would try hit into the center of the targetSprite or so. Note there's no gravity or anything in this world. (Perhaps I should have my sprites variables using angle and velocity but right now I'm using speedX and speedY...)

Thanks so much!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

握住我的手 2024-09-15 18:31:42

将目标精灵视为二维房间中的一条直线,其中:

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)

那么它取决于您用给定的值求解这些方程并寻求时间的最小值。

Treat the targets sprite as a straight line in a 2 dimensional room where:

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

As your bullet have constant speed you also know:

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

Then you can also calculate a straight line for the bullet:

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

And you know that both lines interset somewhere:

A(time) = B(time)

Then it's up to you to solve those equations with your given values and seek a minimum for time.

深府石板幽径 2024-09-15 18:31:42

一些物理洞察力

1)对于“点对象”的目标

所以你必须求解VECTOR方程

位置项目符号 [ time=t1 > t0 ] == 位置目标 [ time=t1 > > t0 ] -- (Eq 1)

其中位置由运动(也是矢量)方程给出

位置对象 [ t ] = 位置object [ t0 ] + Speedobject * ( t - t0 )

现在,子弹能够击中目标的条件是方程1有x和y的解。让我们写下 x 的方程式:

Xbullet [ t0 ] + SpeedXbullet * ( t - t0 ) = X目标 [ t0 ] + SpeedX目标 * ( t - t0 )

因此,对于碰撞时间,我们有

( tCollision - t0 ) = (xtarget [ t 0 ] - x项目符号 [ t0 ] ) / (SpeedX项目符号 - SpeedX目标 ) -- (Eq 2)

因为我们需要 t > 的解t0,这意味着有一个截距就足够了>

符号 ( x目标[ t0 ] - x项目符号[ t0 ] ) = 符号( SpeedXbullet - SpeedXtarget ) -- (Eq 3)

这告诉我们一个明显的事实,如果一个物体比另一个物体移动得更快,并且朝同一方向,它们最终会发生碰撞。

从方程 2 中,您可以看到,对于给定的 SpeedX目标 存在无限解(如前所述)在其他答案中)对于 t 和 SpeedXbullet,所以我认为您的规格不完整。

<代码>
我想(正如我在另一个答案中所做的评论中所述)在“塔防”类游戏中思考,你的子弹射程有限。

所以你还需要另一个约束:

Distance [ Positiontarget [ tCollision - t0 ] - Positionbullet [ t0 ] ] < BulletRange -- (Eq 4)


这仍然允许无限的解决方案,但受到碰撞时间上限值的限制,因为目标可能会放弃范围。

此外,距离由下式给出:

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

因此,方程 4 变为,


(X目标[t碰撞 - t0] - X子弹[t0 >])2 + (Y目标[t碰撞 - t0] - Y子弹< /sub>[t0])2 < BulletRange2 --(等式 5)

请注意, { Xbullet[t0] 、 Ybullet[t0} 是塔位置。

现在,将方程 5 中的目标位置值替换为:


(X目标[t0] + SpeedX目标 * (tt0) - X子弹< /sub>[t0])2 + (Y目标[t0] + SpeedY目标 * (tt0) - Y项目符号[t0])2 < BulletRange2 --(等式 6)

调用初始距离:

Dxt0 = Xtarget[t0] - Xbullet[t0]


Dyt0 = Ytarget[t0] - Ybullet[t0]

公式 6 变为


(Dtx0 + SpeedX目标 * (tt0) )2 + (Dty0 + SpeedY目标 * (tt<子>0))2 < BulletRange2 -- (方程 7)

这是一个在 t-t0 内求解的二次方程。正解将为我们提供碰撞所允许的最长时间。之后目标将超出范围。

现在调用

Speedtarget 2 = SpeedXtarget 2 + SpeedYtarget 2

H = Dtx0 * SpeedX目标 + Dty0 * SpeedY目标


T最大碰撞 = t0 - ( H
+/- Sqrt ( BulletRange2 * 速度目标 2 - H2 ) ) / 速度目标 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 ] - Ybullet [ t0 ] ) / ( tCollision - t0 ) + SpeedYtarget

2)对于目标和塔是“广泛的对象”

现在,概括一下目标是半径为 R 的圆的情况是很简单的。您得到的相当于子弹的“扩展射程”。该扩展名就是 R。

因此,将 BulletRange 替换为 (BulletRange + R),您将得到最大允许碰撞时间的新方程。

如果您还想考虑大炮的半径,则适用相同的考虑因素,给出“双倍扩展射程”

NewBulletRange = BulletRange + R目标 + R

无限射程子弹

如果您决定某些特殊项目符号不应具有射程(和检测)限制,则仍然存在屏幕边框约束。但解决起来有点困难。如果您需要这种射弹,请发表评论,我会尝试做一些数学计算。

Some physical insight

1 ) For the target being a "Point Object"

So you have to solve the VECTOR equation

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

Where the positions are given by the motion (also VECTOR) equations

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

Now, the condition for the bullet to be able to reach the target is that the Eq 1 has solutions for x and y. Let's write down the equation for x:

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

So for the collision time we have

( tCollision - t0 ) = (xtarget [ t 0 ] - xbullet [ t0 ] ) / (SpeedXbullet - SpeedXtarget) -- (Eq 2)

As we need solutions with t > t0, that means that for having an intercept is enough that>

Sign ( xtarget[ t0 ] - xbullet[ t0 ] ) = Sign ( SpeedXbullet - SpeedXtarget ) -- (Eq 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.

From Eq 2, you can see that for a given SpeedXtarget there exist infinite solutions (as already pointed out in other answers) for t and SpeedXbullet, so I think your specifications are not complete.


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.

So you need also another constraint:

Distance [ Positiontarget [ tCollision - t0 ] - Positionbullet [ t0 ] ] < BulletRange -- (Eq 4)


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.

Further, the distance is given by

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

So, Eq 4 becomes,


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

Note that { Xbullet[t0] , Ybullet[t0} is the tower position.

Now, replacing in Eq 5 the values for the target position:


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

Calling the initial distances:

Dxt0 = Xtarget[t0] - Xbullet[t0]

and


Dyt0 = Ytarget[t0] - Ybullet[t0]

Equation 6 becomes


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

Which is a quadratic equation to be solved in t-t0. The positive solution will give us the largest time allowed for the collision. Afterwards the target will be out of range.

Now calling

Speedtarget 2 = SpeedXtarget 2 + SpeedYtarget 2

and

H = Dtx0 * SpeedXtarget + Dty0 * SpeedYtarget


TCollision Max = t0 - ( H
+/- Sqrt ( BulletRange2 * Speedtarget 2 - H2 ) ) / Speedtarget 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 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 = ( Xtarget [ t0 ] - Xbullet [ t0 ] ) / ( tCollision - t0 ) + SpeedXtarget

and

SpeedYbullet = ( Ytarget [ t0 ] - Ybullet [ t0 ] ) / ( tCollision - t0 ) + SpeedYtarget

2 ) For the target and tower being "Extensive Objects"

Now, it is trivial to generalize for the case of the target being a circle of radius R. What you get, is the equivalent of an "extended range" for the bullets. That extension is just R.

So, replacing BulletRange by (BulletRange + R) you get the new equations for the maximum allowed collision time.

If you also want to consider a radius for the cannons, the same considerations apply, giving a "double extended range

NewBulletRange = BulletRange + RTarget + RTower

Unlimited Range Bullets

In the case that you decide that some special bullets should not have range (and detection) limitations, there is still the screen border constraint. But it is a little more difficult to tackle. Should you need this kind of projectile, leave a comment and I'll try to do some math.

毁梦 2024-09-15 18:31:42

使用向量可以使数学看起来更简单一些。 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)); 
}

Using vectors can make the math around this seem a little simpler. Sylvester seems to be a promising implementation of vectors in JavaScript, but for the purpose of my example, I'll write my own vector functions. I'm also going to assume .x / .y are measured top/left corner.

// 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)); 
}
停顿的约定 2024-09-15 18:31:42

计算射击者与目标之间的距离:dist = sqrt((xt - xs)^2 + (yt - ys)^2)
将 x 和 y 距离除以上述距离:nx = (xt - xs)/dist; ny = (yt - ys)/dist;(向量归一化)
将结果乘以一个因子即可得到每个时间单位的 n 个像素,即。每个方向的速度。它应该在所需的方向上提供恒定的速度。

Compute the distance between shooter and target: dist = sqrt((xt - xs)^2 + (yt - ys)^2)
Divide the x and y distances by the above one: nx = (xt - xs)/dist; ny = (yt - ys)/dist; (normalization of the vector)
Multiply the results by a factor to get n pixels per time unit, ie. a speed in each direction. It should give a constant speed in the wanted direction.

稚然 2024-09-15 18:31:42

我假设目标将以匀速直线移动。

如果子弹的方向都是可变的(即您尝试计算子弹的speedXspeedY),则有无限个许多解决方案。

如果设置固定方向,只需使子弹和目标的两条线相交即可。根据目标当前点与交点之间的距离(以及目标的速度),您可以计算出目标到达该交点所需的时间。

根据子弹原点和交点之间的距离(以及之前计算的时间),您可以计算出子弹的速度。

I assume that the target will move on a straight line with constant velocity.

If both the direction and the speed of the bullet are variable (i.e. you try to calculation speedX and speedY for the bullet), there are infinitely many solutions.

If you set a fixed direction, you simply intersect the two lines of the bullet and the target. From the distance between the current point of the target and the intersection point (and the target's speed) you can calculate the time the target will take to reach this intersection point.

From the distance between the origin of the bullet and the intersection point (and the previously calculated time) you can calculate the speed of the bullet.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文