繁体   English   中英

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

[英]2D game algorithm to calculate a bullet's needed speed to hit target?

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

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

可能它看起来不错,子弹将从originSprite的外部开始(或者一些定义的半径,虽然我猜起始于originSprite中心也可以工作),但它的子弹中心会尝试击中targetSprite的中心或者所以。 请注意,这个世界上没有引力或任何东西。 (也许我应该使用角度和速度来获得我的精灵变量,但现在我正在使用speedX和speedY ...)

非常感谢!

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

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

一些物理洞察力

1)目标是“点对象”

所以你必须解决VECTOR方程

位置项目符号 [time = t 1 > t 0 ] ==位置目标 [时间= t 1 > t 0 ] - (公式1)

位置由运动(也是VECTOR)方程给出

位置对象 [t] =位置对象 [t 0 ] +速度对象 *(t - t 0

现在,子弹能够达到目标的条件是等式1具有x和y的解。 让我们写下x的等式:

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 目标 ) - (公式2)

因为我们需要t> t 0的解决方案,这意味着拦截就足够了>

符号(x target [t 0 ] - x bullet [t 0 ])= Sign(SpeedX bullet - SpeedX 目标 ) - (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.

从式2中,您可以看到,对于给定的SpeedX 目标 ,存在 t和SpeedX 项目符号的 无限解 (如其他答案中已经指出的那样),因此我认为您的规范并不完整。

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.
所以你还需要另一个约束:

距离[位置目标 [t 碰撞 - t 0 ] - 位置项目符号 [t 0 ]] <BulletRange - (公式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.
此外,距离由下式给出

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

那么,Eq 4变成,

(X target [t Collision - t 0 ] - X bullet [t 0 ]) 2 +(Y target [t Collision - t 0 ] - Y bullet [t 0 ]) 2 <BulletRange 2 - (Eq 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 < BulletRange 2 - (Eq 6)

调用初始距离:

Dxt0 = X target [t 0 ] - X bullet [t 0 ]

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

等式6变为

(Dtx0 + SpeedX 目标 *(tt 0 )) 2 +(Dty0 + SpeedY 目标 *(tt 0 )) 2 <BulletRange 2 - (Eq 7)

这是在t-t0中要求解的二次方程。 积极的解决方案将为我们提供最大的碰撞时间。 之后目标将超出范围。

现在打电话

速度目标 2 = SpeedX 目标 2 + SpeedY 目标 2

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


T 碰撞最大值 = t 0 - (H +/- Sqrt(BulletRange 2 *速度目标 2 - H 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 0

 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 Collision - t 0 )+ SpeedX target

SpeedY bullet =(Y 目标 [t 0 ] - Y bullet [t 0 ])/(t 碰撞 - t 0 )+ SpeedY 目标

2)目标和塔是“广泛物体”

现在,对于目标是半径为R的圆的情况进行推广是微不足道的。你得到的,相当于子弹的“扩展范围”。 那个扩展只是R.

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

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

NewBulletRange = BulletRange + R 目标 + R

无限范围子弹

如果您确定某些特殊项目符号不应具有范围(和检测)限制,则仍然存在屏幕边界约束。 但要解决这个问题要困难一些。 如果你需要这种弹丸,请留言,我会尝试做一些数学运算。

使用向量可以使围绕这个的数学看起来更简单。 西尔维斯特似乎是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)); 
}

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

我假设目标将以恒定速度在直线上移动。

如果子弹的方向速度都是可变的(即你试图计算子弹的speedXspeedY ),那么有无数的解决方案。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM