12

宇宙に船がある 2D ゲームを実装しています。

そのために、Box2D を Lua でラップする LÖVE を使用しています。しかし、私の質問は、私よりも物理学をよく理解している人なら誰でも答えることができると信じています。そのため、疑似コードが回答として受け入れられます。

私の問題は、2D 物理学が有効な世界で宇宙船を適切に動かす方法がわからないことです。より具体的には:

大量の船がm初期位置にあり{x, y}ます。の初期速度ベクトルを持ちます{vx, vy}( にすることができます{0,0})。

目標は のポイントです{xo,yo}{vxo, vyo}船は、最短の軌道をたどって、の速度 (またはそれに近い速度) を持つ目標に到達する必要があります。

頻繁に呼び出される関数がありますupdate(dt)(つまり、1 秒あたり 30 回)。この機能では、船はそれ自体に「インパルス」を適用することで、その位置と軌道を変更できます。インパルスの大きさは 2 進数です。特定の方向に適用することも、まったく適用しないこともできます)。コードでは、次のようになります。

function Ship:update(dt)
  m = self:getMass()
  x,y = self:getPosition()
  vx,vy = self:getLinearVelocity()
  xo,yo = self:getTargetPosition()
  vxo,vyo = self:getTargetVelocity()
  thrust = self:getThrust()

  if(???)
    angle = ???
    self:applyImpulse(math.sin(angle)*thrust, math.cos(angle)*thrust))
  end
end

1つ目???は、場合によっては(おそらく)「衝動に駆られず」、船を「漂流」させた方がよいことを示すためのものです。2 番目???の部分は、与えられた dt で衝撃角を計算する方法で構成されます。

私たちは宇宙にいるので、空気摩擦などは無視できます。

とてもいいことですが、これをコーディングしてくれる人を探しているわけではありません。私の問題が明確に理解できるように、コードをそこに置きました。

私が必要としているのは戦略、つまりこれを攻撃する方法です。私は基本的な物理学をいくつか知っていますが、専門家ではありません。たとえば、この問題には名前がありますか? そのようなこと。

どうもありがとう。

編集: ベータ版はこれに対する有効な戦略を提供し、Judge は親切にもそれを LÖVE のコメントで直接実装しました。

EDIT2:さらにグーグルで調べた後、 openSteerも見つかりました。それは C++ 上にありますが、私がふりをしたことを行います。この質問にたどり着く人にはおそらく役立つでしょう。

4

6 に答える 6

9

これはモーションプランニングと呼ばれるもので、簡単なことではありません。

最適でない軌道を取得する簡単な方法を次に示します。

  1. 止まる。速度がゼロになるまで、速度の方向と反対の推力を適用します。
  2. 船を x0 と v0 に到達させるスタンディング スタートからの安定した推力である、最初のレグとは逆になる最後のレグを計算します。開始点は、x0 から |v0|^2/(2*thrust) の距離になります。
  3. その開始点に到達します (そして、最後のレグを作ります)。ある立ち位置から別の立ち位置に移動するのは簡単です。途中まで押し込み、停止するまで後方に押し込みます。

最適な軌道への迅速で汚いアプローチが必要な場合は、反復アプローチを使用できます。上記の非最適なアプローチから始めます。これは推力角の時系列です。次に、そのシーケンスを少し変えてみて、目標に近づくシーケンスの母集団を維持します。最悪のものを拒否し、最良のものを試してみてください。勇気があれば、これを遺伝的アルゴリズムにすることができます。運が良ければ、コーナーを丸め始めます。

正確な答えが必要な場合は、変分法を使用してください。私はそれにひびを入れます。成功したら、ここに答えを投稿します。

編集:これは、より単純な問題に対する正確な解決策です。

任意の方向に向けることができる推力の代わりに、{+X、+Y、-X、-Y} 方向を向く 4 つの固定スラスターがあるとします。任意の時点で、最大で +/-X の 1 つと最大で 1 つの +/-Y を起動します (+x と -X を同時に起動しても意味がありません)。したがって、X と Y の問題は独立しています (X と Y の間で推力を共有する必要があるため、元の問題にはありません)。ここで、1 次元の問題を解いて、それを 2 回適用する必要があります。

最良の弾道は、一方向に突き出し、次に反対方向に突き出し、最初の方向に戻らないことです。(コースティングは、他の軸の解が自分の解よりも長くかかる場合にのみ有効なので、時間をつぶすことができます。) 最初に速度の問題を解いてください。(WLOG)目標速度が初期速度よりも大きいとします。目標速度に到達するには、持続時間の推力 (+) の期間が必要です

T = (Vf - Vi)/a

(Vf: 最終速度、Vi: 初速度、a: 推力の大きさを使用しています。)

それだけだとロケ地が出てこないことに気づきます。実際の最終的な場所は

X = (Vi + Vf)T/2

したがって、次の修正を追加する必要があります。

D = Xf - X = Xf -(Vi+Vf)T/2

位置を正しくするために、その前に一方向に推力の期間を追加し、その後に反対方向に同じ期間を追加します。これにより、最終的な速度はそのまま残りますが、いくらかの変位が得られます。この最初の期間 (および 3 番目の期間) の期間が t の場合、そこから得られる変位は次のようになります。

d = +/-(at^2 + atT)

+/- は、+ の次に - を押すか、- の次に + を押すかによって異なります。+だとします。二次方程式を解きます。

t = (-aT + sqrt(a^2 T^2 + 4 a D))/2a

これで完了です。

于 2010-04-01T14:26:57.873 に答える
4

追加情報がない場合、宇宙船に作用し、最終的にその軌道を決定する 3 つの力があると推測できます。

  • 衝動」: [ユーザー/プログラム制御] 力。
    ユーザー (またはプログラム) はこれを完全に制御しているように見えます。つまり、インパルスの方向とその推力を制御します (おそらく 0 から最大の範囲内で)。
  • なんらかの外力: 重力と呼んでください...
    そのような力はいくつかのソースによって駆動される可能性がありますが、私たちはその結果として生じる結合力に関心があるだけです: 与えられた時間と空間で、この外力は与えられた強さで船に作用し、方向。ユーザー/プログラムはこれらを制御できません。
  • 慣性: これは、船の現在の速度と方向に関連しています。通常、この力により、船は現在の速度で現在の方向に進みます。慣性を制御する他の [宇宙時代] パラメーターがあるかもしれませんが、一般的に、それは速度と船の質量の両方に比例します (直観的には、現在の速度が小さいか、および/または質量が小さい場合)

どうやら、ユーザー/プログラムは (制限内で) 最初の力のみを制御します。
質問から、当面の問題が次のとおりであるかどうかは不明です。

  • [問題 A] システムのダイナミクスを発見する (および/またはこれらのダイナミクスの変化に適応する) プログラムを作成すること。
    また..
  • [問題 B] 最終的に船に適用される複合力を計算するために使用できるモデル (数式) を提案する: ユーザー制御のインパルスと他の 2 つのシステム/物理駆動力の「重み付けされた」合計。

後者の質問である問題 B は、より簡単かつ簡潔に説明できるので、次のモデルを提案しましょう。

Constant Parameters:
  ExternalForceX   = strength of the external force in the X direction
  ExternalForceY   = id. Y direction
  MassOfShip       = coeficient controlling 
Variable Parameters:
  ImpulseAngle     = direction of impulse
  ImpulseThrust    = force of thrust
Formula:
  Vx[new] = (cos(ImpulseAngle) * ImpulseThrust) + ExternalForceX  + (MassOfShip * Vx[current])
  Vy[new] = (sin(ImpulseAngle) * ImpulseThrust) + ExternalForceY  + (MassOfShip * Vy[current])

上記のモデルは、一定の外力 (強さと方向の両方に関して一定) を想定していることに注意してください。つまり、表示されている領域から比較的離れた重力場に似ています (サッカー場の範囲内で考えられる地球の重力と同じように)。表示領域のスケールが外力のソースに比べて大きい場合は、上記の式の中間項を修正して、以下を含むようにする必要があります。 ソースの中心と電流の間の角度に基づく三角関数係数位置および/またはソースの中心と現在の位置の間の距離に基づく[反比例]係数。
同様に、船の質量は一定であると仮定されます。たとえば、空のときの船の質量に基づいて、ゲームが進行するにつれて燃料の重量が削除/追加される変数である可能性があります。

さて...上記のすべては、システムのダイナミクスがゲームデザイナーによって制御されることを前提としています:基本的に、言及されたパラメーターの値のセットを選択し、式の計算に少し複雑さを追加する可能性があります(また、適切なスケーリングを保証します)通常、表示領域内に船を「保持」します)。

代わりに、システムダイナミクスがゲームに簡単にプログラムされ(そして非表示/ランダムであると想定され)、当面のタスクは、船を駆動するインパルスの方向と推力値を漸進的に決定するプログラムを作成することであるとしたらどうでしょう。ターゲットでの速度が getTargetVelocity() にできるだけ近くなるように、ターゲットの目的地を設定しますか? これが「問題A」です。

このタイプの問題は、 PID コントローラーで対処できます。簡単に言えば、このようなコントローラーは、以下に大まかに定義された 3 つの重み付けされた要因に基づいて、アクションの量 (このゲームの場合は適用するインパルス角度と推力の量) を「決定」します。

  • 現在の値が「設定点」からどれだけ離れているか: これは P=PID の比例部分です。
  • どのくらいの速さで「設定値」に近づいているか: これは PID の D=Derivative 部分です
  • 「設定値」からどのくらいの時間、どれだけ離れているか: これは、PID の I=Intergral 部分です。

たとえば、あまり洗練されていないコントローラーでは、比例係数のみを使用できます。これにより振動が発生し、設定値の両側で振幅が大きくなることがあります (「本来あるべき場所から X ユニット離れています。ハンドルを引っ張ってアクセルを踏んでみましょう」)。このような設定値のオーバーシュートは、デリバティブ ファクターによって緩和されます (「はい、まだあるべき場所にはいませんが、最後にチェックしてからの進歩は非常に大きいです。少し速度を落としたほうがよいでしょう」) . 最後に、積分部分は、比例部分と微分部分の組み合わせに関してすべてが等しいという事実を考慮に入れています。長い間「軌道から外れた」かどうかに応じて、より小さなまたはより大きなアクションが適切になります。そして、これまでずっと軌道から外れてきました(例.

宇宙船ゲームの特定のニーズに合わせて PID コントローラーを実装する詳細について議論することができます。アイデアは、できることのフレーバーを提供することでした。

于 2010-04-01T16:15:14.890 に答える
1

現在の位置から目的地まで初速度で移動するには、最短経路と現在の速度の正規化された差に沿って推力を適用します。角度は特に必要ありません。

-- shortest path minus initial velocity
dx,dy = x0 - x - vx, y0 - y - vy

-- normalize the direction vector
magnitude = sqrt(dx*dx + dy*dy)
dx,dy = dx/magnitude, dy/mangitude

-- apply the thrust in the direction we just calculated
self:applyImpulse(thrust*dx, thrust*dy)

非常に複雑になるため、これはターゲット速度を考慮していないことに注意してください。

この貼り付けビンで 2D ベクトルを処理するための非常に小さな Lua モジュールがあります。よろしければご利用ください。上記のコードは次のようになります。

d = destination - position - velocity
d:normalize()
d = d * thrust
self:applyImpulse(d.x, d.y)
于 2010-04-01T14:24:57.143 に答える
0

燃料を排出していますか?あなたがいる場合、あなたの質量は時間とともに変化します。

推力は反力です。これは、質量の変化率に、宇宙船に対する排気の速度を掛けたものです。

外力はありますか?もしそうなら、これらはインパルス計算に入る必要があります。

質量が放出されず、外力もない魔法の推力を仮定しましょう。

インパルスには運動量の単位があります。それは、時間の経過に伴う力の積分です。

まず、API が「推力」と「衝動」と呼んでいるものを正確に理解する必要があります。スカラー (数値) を乗じた推力を与える場合、applyImpulse は、単位が一致しないため、それをインパルスとして使用できるように、入力に対して別の処理を行う必要があります。

あなたの「推力」が力であると仮定すると、その推力に時間間隔 (1/30 秒) を掛けて衝動を得て、コンポーネントを分割します。

私があなたの質問に答えているかどうかわかりませんが、物理学を少し理解するのに役立つことを願っています.

于 2010-04-01T14:40:42.493 に答える
0

船の速度を目標速度ベクトルに平行な成分と垂直な成分に分けると、より簡単に考えることができます。

垂直軸に沿って考えると、船はできるだけ早く目標位置に一直線になり、そこにとどまろうとします。

平行軸に沿って、目標速度に近づける方向に加速する必要があります。(明らかに、その加速によって目標地点から遠ざかる場合は、何をすべきかを決定する必要があります。目標地点を通過してから、ダブルバックしますか?)

私はそれらの 2 つを別々に扱い、おそらく最初に垂直に扱います。それが機能したら、それが十分にうまくいかない場合は、船に垂直と平行の間のインテリジェントな角度を発射させる方法があるかどうかを考え始めることができます.

(編集:また、言及するのを忘れていましたが、これは、垂直方向に大きくオフセットされているが平行方向にはあまりオフセットされていないシナリオに対処するために、いくらかの調整が必要です。ここでの重要な教訓は、コンポーネントを取得することです。決定の基礎となる有用な数値です。)

于 2010-04-01T14:53:50.593 に答える
-1

あなたの角度は逆接線です反対/隣接

角度 = InvTan(VY/VX)

ドリフトしたいということについて何を話しているのかわからない??

于 2010-04-01T14:06:00.650 に答える