7

TL;dr: 「あるベクトルから別のベクトルへの推力のスムーズな移行を計算する方法がわかりません。」

敵がオープンスペース(壁なし)でプレイヤーを追いかける簡単なゲームをプログラミングしています。敵の x 速度と y 速度を個別に計算し、敵がプレイヤーの方向に進んでいる場合は加速し、間違った方向に進んでいる場合は急速に減速しました (例: EnemyVelocity.x > 0 & player.x <enemy.x) 、次に EnemyVelocity.x - 2.)

敵をかわそうとするゲームプレイはそれなりに楽しいものですが、敵が適切な物理学を使用して動作するようにしたいというのが私の望みです。私が現在行っていることは、敵とプレイヤーの間の角度に基づいて敵に推力を設定させ (宇宙船を考えてください)、推力を最大速度まで加速させます (EnemyVelocity 三角形の辺 c を計算します)。それが起こると、推力を自動的に調整する最善の方法がわかりません。最大速度を設定しないと、敵はうまく加速しますが、プレイヤーを簡単に追い越してしまい、プレイヤーの方向に戻るのに十分な勢いを得るのに長い時間がかかります。

私が実現したいのは、敵がプレイヤーに向かう途中で常に速度を調整し、敵がいる場所をターゲットにすることです (プレイヤーがどこにいるかを敵に予測させたくありません)。次に、プレイヤーを逃した場合、同じ推力と加速の式で速度を再調整し、プレイヤーに送り返したいと思います。

これには 2 つのベクトルが関係すると考えています。1 つは敵が現在移動している場所で、もう 1 つは敵が移動しようとしている場所です (プレイヤーに直接向かうベクトル)。あるベクトルから別のベクトルへの推力のスムーズな移行を計算する方法がわかりません。

ヒント、公式、質問は大歓迎です!ありがとうスタックオーバーフロー。

4

7 に答える 7

2

推力ではなく、速度をスムーズに変化させることで、希望する効果が得られる場合があります。そうすれば、敵がプレーヤーを追い越した場合、敵はすぐに加速を逆転させることができます。これにより、敵は減速し、最終的には進行方向が逆転します。

これは、各反復中に速度を変更し、敵からプレーヤーまでの距離に基づいて少しずつ変更することで実現できます。

while (game_in_progress)
{
    // Distance from enemy to player.  The larger the
    // distance, the greater the acceleration will be.
    delta.x = player.x - enemy.x
    delta.y = player.y - enemy.y

    // Accelerate by changing velocity based on distance,
    // where 'scale' is sufficiently small. (Limit v to
    // some maximum if you choose; likely to be unnecessary.)
    v.x += delta.x * scale
    v.y += delta.y * scale

    // Update the enemy's position.
    enemy.x += v.x
    enemy.y += v.y
}

xとの値を個別に計算するyことで、ベクトル、角度、および同時等式を処理する際の頭痛の種を減らすことができます。

同様に、加速度(推力)は単に速度の変化であり、それは位置の変化であると認識することにより、微積分の代わりに単純な代数のみを使用して離散時間シミュレーションを作成できます。

楽しむ!

于 2009-09-02T01:51:44.250 に答える
2

適切な物理学用語で考える必要があります。速度があり、加速度を追加したいとします。それだけです。加速は、敵をプレイヤーに引き寄せ、オーバーシュートさせ、速度を落として (または向きを変えて)、プレイヤーに向かって戻る速度の緩やかな変化です。

加速度は、d(速度)/時間として測定されます。任意の時点でプレイヤーに向かって加速したいので、すべての間隔 (秒、100 分の 1 秒、または任意の選択) で、敵とプレイヤーの間のベクトルを定数で乗算して速度に追加する必要があります。

Velocity = Velocity + c * (Player-Enemy vector)

定数 c は、プレーヤーに向かって加速する速度と、速度を更新する頻度によって異なります。

敵の速度が際限なく増加し続けないように、敵の最大速度を「制限」したい場合は、そうすることができます。

Velocity = Velocity * (Maximum magniture / |Velocity|)

編集: さらに明確にするために、Velocity を追加することは単にコンポーネント ベクトルを追加することを意味します。そう

Vx = Vx + c * Ax
Vy = Vy + c * Ay

ここで、V は速度、A は加速度です。大きさは として測定されsqrt(Vx^2 + Vy^2)ます。つまり、直角三角形の斜辺です。したがって、敵の最大速度を m にしたい場合は、

Vx = Vx * ( m / sqrt(Vx^2 + Vy^2)
Vy = Vy * ( m / sqrt(Vx^2 + Vy^2)
于 2009-09-02T02:20:29.407 に答える
2

それはすべてニュートンの方程式に戻ります。

F = m * a
s = s_o + v * t + a * t^2 / 2
v = v_o + a * t

この場合F、 は力 (推力)、aは加速度、mは船の質量です。 sは現在位置、s_oは元の位置、vは速度、tは現在の時刻です。

もちろん、これは直線に沿っているので、2 次元または 3 次元に変換したい場合は、計算を行う必要があります。 Fsv、およびaはすべてベクトルです。つまり、それらの方向は等しく重要です。技術的tにはベクトルでもありますが、時間は通常一方向にしか進んでいないため、心配する必要はありません。

2d:
F^2 = F_x^2 + F_y^2 (use Pythagorean theorem to split force into components)
F_x = m * a_x
F_y = m * a_y
s_x = s_o_x + v_x * t + a_x * t^2 / 2
s_y = s_o_y + v_y * t + a_y * t^2 / 2
v_x = v_o_x + a_x * t
v_y = v_o_y + a_y * t

3d:
F^2 = F_x^2 + F_y^2 + F_z^2 (surprisingly, this works)
F_x = m * a_x
F_y = m * a_y
F_z = m * a_z
s_x = s_o_x + v_x * t + a_x * t^2 / 2
s_y = s_o_y + v_y * t + a_y * t^2 / 2
s_z = s_o_z + v_z * t + a_z * t^2 / 2
v_x = v_o_x + a_x * t
v_y = v_o_y + a_y * t
v_z = v_o_z + a_z * t

Fプレーヤーの方向に速度を調整するために、現在の速度をプレーヤーに向けて変更するために、一定の総力 ( ) が得られます。物理学では物事は瞬時には起こりませんが、目標は変化が起こる時間を最小限に抑えることです (「t」)。

これにより、目標速度 (加速度を無視)について、現在位置 ((s_o_x,s_o_y)または(s_o_x,s_o_y,s_o_z)) と対戦相手の現在位置または目標位置 ((s_x,s_y)または)に関する方程式が得られます。(s_x,s_y,s_z)

v_x = (s_x - s_o_x) / t
v_y = (s_y - s_o_y) / t

v_x = (s_x - s_o_x) / t
v_y = (s_y - s_o_y) / t
v_z = (s_z - z_o_y) / t

これを他の方程式に置き換えることができます。

(s_x - s_o_x) / t = v_o_x + a_x * t
(s_y - s_o_y) / t = v_o_y + a_y * t

(s_x - s_o_x) / t = v_o_x + a_x * t
(s_y - s_o_y) / t = v_o_y + a_y * t
(s_z - z_o_y) / t = v_o_z + a_z * t

次に、加速度を解きます (これは、計算しようとしている力に関連しています)。

(s_x - s_o_x) / t^2 - v_o_x / t = a_x
(s_y - s_o_y) / t^2 - v_o_y / t = a_y

(s_x - s_o_x) / t^2 - v_o_x / t = a_x
(s_y - s_o_y) / t^2 - v_o_y / t = a_y
(s_z - z_o_y) / t^2 - v_o_z / t = a_z

これを力の式に代入します。

F_x = m * (s_x - s_o_x) / t^2 - m * v_o_x / t
F_y = m * (s_y - s_o_y) / t^2 - m * v_o_y / t

F_x = m * (s_x - s_o_x) / t^2 - m * v_o_x / t
F_y = m * (s_y - s_o_y) / t^2 - m * v_o_y / t
F_z = m * (s_z - z_o_y) / t^2 - m * v_o_z / t

を解くt

t = (-m * v_o_x +/- sqrt(m^2 * v_o_x^2 - 4 * F_x * m * (s_x - s_o_x))) / 2 / F_x
t = (-m * v_o_y +/- sqrt(m^2 * v_o_y^2 - 4 * F_y * m * (s_y - s_o_y))) / 2 / F_y

t = (-m * v_o_x +/- sqrt(m^2 * v_o_x^2 - 4 * F_x * m * (s_x - s_o_x))) / 2 / F_x
t = (-m * v_o_y +/- sqrt(m^2 * v_o_y^2 - 4 * F_y * m * (s_y - s_o_y))) / 2 / F_y
t = (-m * v_o_z +/- sqrt(m^2 * v_o_z^2 - 4 * F_z * m * (s_z - s_o_z))) / 2 / F_z

時間が収束するはずなので、時間は等しくなります!これにより、各座標 (平面と球) の連立方程式が得られます。複数の可能な値があることに注意してください。ただし、虚数を含むものもあるため、これらのソリューションを削除する必要があります。

(-m * v_o_x +/- sqrt(m^2 * v_o_x^2 - 4 * F_x * m * (s_x - s_o_x))) / 2 / F_x
= (-m * v_o_y +/- sqrt(m^2 * v_o_y^2 - 4 * F_y * m * (s_y - s_o_y))) / 2 / F_y
F^2 = F_x^2 + F_y^2

(-m * v_o_x +/- sqrt(m^2 * v_o_x^2 - 4 * F_x * m * (s_x - s_o_x))) / 2 / F_x
= (-m * v_o_y +/- sqrt(m^2 * v_o_y^2 - 4 * F_y * m * (s_y - s_o_y))) / 2 / F_y
= (-m * v_o_z +/- sqrt(m^2 * v_o_z^2 - 4 * F_z * m * (s_z - s_o_z))) / 2 / F_z
F^2 = F_x^2 + F_y^2 + F_z^2

(F_x,F_y)または座標を解くと、(F_x,F_y,F_z)必要な力が得られます。

ご不明な点がございましたら、または私の計算に誤りがありましたらお知らせください。

于 2009-09-02T04:50:58.653 に答える
1

私はしばらく前に、小惑星を追い詰めてあなたのために撃つ「味方」の船を持った簡単な小惑星ゲームを書きました。基本的に、それは最も近い小惑星を見つけ、それからスムーズにそれに向かって向きを変え、それを追いかけ始めました。悲しいことに、私はもうコードを持っていませんが、メモリが役立つ場合は、毎ターン船を少し動かしたと思います。小惑星が遠くにある場合は加速しましたが、近くにある場合は小惑星の速度に合わせようとしました。実際にはかなりクールで、最小限の代数が含まれていました。

それを行うための最良の方法は、2つのラジアン値を取り、それらの間でlerpして、ラッピングを処理することです。(おそらく、必要に応じて2piを加算または減算することによって)。次に、それを単位ベクトルに変換します。続いて、それを船に加速させたい速度で乗算すると、そこに行きます!

于 2009-09-02T01:58:39.403 に答える
1

簡単な方法の 1 つ (適切な物理学ではありません) は、敵の「望ましい速度」を計算し、敵の現在の速度をそれに合わせて調整し、上にある制限や最小速度に注意することです。

たとえば、私が書いた小さな 2D ゲーム ( http://wordwarvi.sourceforge.net)「熱探知ミサイル」があります。ミサイルが空中で停止して方向転換するのはかなり奇妙に見えます。だから私がしたことは次のとおりです。プレーヤーに向かっている「望ましい速度」を計算します。これは「相似三角形」によって行われます。プレーヤーまでの距離を X と Y で求め、どちらか大きい方で、「目的の (x または y) 速度を可能な限り最大にして、もう一方の速度を「相似三角形」に合うようにスケーリングします。 、それは単なる「望ましい速度」であり、現在の速度ではありません.現在の速度を取得し、「望ましい」速度に向かってゆっくりと (フレームごとに少しずつ) 調整します (ただし、望ましい速度はフレームごとに再計算されます)。 vx と vy の最小値を気にして、空中で停止しないようにします。

ばかげたアルゴリズムですが、問題なく動作します (簡単すぎる、難しすぎる、または非現実的すぎると文句を言う人はいません)。

編集:質問を読み直すと、私の答えはおそらくあなたが求めているものではありません。

于 2009-09-02T03:04:09.227 に答える
1

これを正しく簡単に行うためのヒントがいくつかあります。1) すべてを 2 回または 3 回記述するよりも、ベクトルを使用する方が最も簡単で最も一般的です。2) 力 (A=F/質量なので実質的に加速度) を制御し、速度と位置を動的に進化させると、物事は正しく見えます。

リアルなモーションの基本的なループは次のようになります (CAP はベクトルで、dt はタイムステップです)。

while (motion) {
   A = get_acceleration(X, V, A, X_target, V_targer, A_target)
   V += A*dt       // V is the integral of A
   X += V*dt       // X is the integral of V
}

そして本当に、これはあなたが動的な進化をしているということです。

次に、加速度を決定する方法、つまり write を決定する必要がありますget_acceleration。ここには複数の要因に依存する多くのオプションがあり、実際の追跡者は複数の戦略を採用しています。たとえば、質量に対して推力が大きい場合 (つまり、加速度が大きい場合) は、おそらくターゲットにまっすぐ向かいたいと思うでしょう。ただし、推力に対して質量が大きい場合は、迎撃コースを作成することをお勧めします。ターゲットに近づくにつれて速度を落としたい場合は、|X-X_target|が小さくなったとき (つまり、ターゲットが近づくとき) および/または速度が近づいたときに、加速度を逆にすることができます。また、減衰は物事が振動しないようにするのに役立ちます。このために、加速度に次のような項を追加します-c*(V-V_target). 目指している物理的なルック アンド フィールに一致するものが得られるまで、これらを試してみることをお勧めします。

于 2009-09-03T04:42:04.703 に答える
1

私はこのような問題を専門的に解決してきました。単純なバージョンから始めて解決することをお勧めします。次のステップに進む前に、各ステップで期待どおりの動作が得られることを確認してください。

  1. シーカーは、1 次元の原点で静止しているターゲットをシークします。そうです、一次元です。それは x 軸上で前後に推力することができ、x=0 に到達しようとしています。スラスターには (固体ロケットのように) スロットルがありませんが、シーカーはそれをどちらの方向にも向けることができます。このようにプログラムすると、シーカーは x=0 付近で振動し、毎回オーバーシュートします。
  2. 同じですが、ターゲットは x=0 以外の場所で静止しています。x を絶対ではなく相対にするだけです (つまり、シーカーは、ターゲットの x ではなく、x の違いを気にします)。
  3. ターゲットが移動中 (またはジャンプ中) になりました。シーカーはそれをたどることができるはずです。ターゲットがどのように動くかによって、振動が大きくなったり小さくなったりします。言いたいことがわかるでしょう。
  4. これで二次元。シーカーは常にターゲットに向かって直接推力します。つまり、推力を単純な三角関数で x 成分と y 成分に分割する必要があります。ターゲットを移動すると、シーカーがその周りの軌道に入る可能性があります。
  5. 1 つの次元と静止したターゲットに戻りますが、シーカーはフライバイではなくランデブーを試みています。これは難しい部分です。目標は、距離と速度を同時にゼロにし、オーバーシュートしないようにすることです。そのため、シーカーは自身の制動能力を知る必要があります。x が v^2/2a より小さい場合、シーカーは減速して目標に到達するために目標から離れて推力を逆転させる必要があります。シーカーがターゲットに非常に近いときに突きを停止できるようにするのは良いことです。
  6. ターゲットは再び移動を開始します。かんたんだよ; x と v を絶対ではなく相対にするだけです。
  7. 多次元。これは非常に簡単です。x、y、および z 部分は独立しています。

ここで、1 セント硬貨をオンにすることはできないが、曲がる必要があるシーカーが必要な場合、事態は複雑になります...

于 2009-09-02T14:56:18.983 に答える