簡體   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