web-dev-qa-db-ja.com

単純な物理ベースの動き

私は、いくつかの基本的な物理コードを使用してオブジェクトを最高速度に加速しようとしている2Dゲームに取り組んでいます。

これがその擬似コードです:


const float acceleration = 0.02f;
const float friction     = 0.8f;  // value is always 0.0..1.0
      float velocity     = 0;
      float position     = 0;

move()
{
   velocity += acceleration;
   velocity *= friction;
   position += velocity;
}

これは、質量や実際の摩擦に依存しない非常に単純化されたアプローチです(コード内の摩擦は、動きに対して作用する一般的な力にすぎません)。 「速度* =摩擦;」としてうまく機能します。パーツは、速度が特定のポイントを超えないようにします。しかし、私が少し迷っているのは、この最高速度と加速および摩擦との関係です。

私がやりたいのは、最高速度とそれに到達するのにかかる時間を設定し、それらを使用して加速度と摩擦の値を導き出すことです。

つまり、


const float max_velocity = 2.0; 
const int   ticks;       = 120; // If my game runs at 60 FPS, I'd like a 
                                // moving object to reach max_velocity in 
                                // exactly 2 seconds.
const float acceleration = ?
const float friction     = ?
30
Radek

最近、ドラッグを使用した発射体の動きのモデリングに関する作業を行ったので、この質問は非常に興味深いものでした。

ポイント1:基本的には 明示的/順方向オイラー反復 を使用して位置と速度を更新しています。ここで、状態の新しい値はそれぞれ古い値の関数である必要があります。このような場合は、位置最初を更新してから、速度を更新する必要があります。

ポイント2:抗力摩擦の影響 には、より現実的な物理モデルがあります。 1つのモデル( Adam Liss によって提案された)には、速度に比例する抗力(ストークスの抗力として知られ、一般に低速の状況に適用されます)が含まれます。私が以前に提案したものは、速度の二乗に比例する抗力を含みます(二次抗力として知られ、一般に高速の状況に適用されます)。最大速度の式をどのように推定するか、および最大速度に効果的に到達するために必要な時間について、それぞれについて説明します。それらはかなり関与しているので、完全な派生は控えます。


ストークスの抗力:

速度を更新するための方程式は次のようになります。

velocity += acceleration - friction*velocity

これは次の微分方程式を表します。

dv/dt = a - f*v

この積分テーブル の最初のエントリを使用して、解を見つけることができます(t = 0でv = 0と仮定):

v = (a/f) - (a/f)*exp(-f*t)

最大(つまり終端)速度はt >> 0のときに発生するため、方程式の第2項はゼロに非常に近く、次のようになります。

v_max = a/f

最大速度に到達するのに必要な時間に関しては、方程式が実際に到達することはなく、代わりに最大速度に向かって漸近することに注意してください。ただし、指数の引数が-5に等しい場合、速度は最大速度の約98%であり、おそらくそれが等しいと見なすのに十分に近いです。次に、最大速度までの時間を次のように概算できます。

t_max = 5/f

次に、これら2つの方程式を使用して、目的のvmaxおよびtmaxが与えられた場合にfおよびaを解くことができます。


二次抗力:

速度を更新するための方程式は次のようになります。

velocity += acceleration - friction*velocity*velocity

これは次の微分方程式を表します。

dv/dt = a - f*v^2

この積分テーブル の最初のエントリを使用して、解を見つけることができます(t = 0でv = 0と仮定):

v = sqrt(a/f)*(exp(2*sqrt(a*f)*t) - 1)/(exp(2*sqrt(a*f)*t) + 1)

最大(つまり終端)速度はt >> 0のときに発生するため、指数項は1よりはるかに大きく、方程式は次のようになります。

v_max = sqrt(a/f)

最大速度に到達するのに必要な時間に関しては、方程式が実際に到達することはなく、代わりに最大速度に向かって漸近することに注意してください。ただし、指数の引数が5に等しい場合、速度は最大速度の約99%であり、おそらくそれが等しいと見なすのに十分に近いです。次に、最大速度までの時間を次のように概算できます。

t_max = 2.5/sqrt(a*f)

これは次と同等です:

t_max = 2.5/(f*v_max)

目的のvmaxおよびtmaxの場合、tmaxの2番目の式は、fがどうあるべきかを示し、次にこれをvmaxの式に代入して、aの値を取得できます。


これは少しやり過ぎのように見えますが、これらは実際にはドラッグをモデル化する最も簡単な方法のいくつかです! 本当に統合手順を見たい人は誰でも私にメールを送ることができます。私はそれらをあなたに送ります。ここに入力するには少し複雑すぎます。

別のポイント:これはすぐにはわかりませんでしたが、代わりにv(t)で導出した式を使用する場合は、速度を更新する必要はありません。静止状態からの加速をモデル化するだけで、加速が開始されてからの時間を追跡している場合、コードは次のようになります。

position += velocity_function(timeSinceStart)

ここで、「velocity_function」はv(t)の2つの式のいずれかであり、速度変数は不要になります。一般に、ここにはトレードオフがあります。v(t)の計算は、単純に反復スキームで速度を更新するよりも計算コストが高くなる可能性があります(指数項のため)が、安定していて、制限があります。特定の条件下(非常に短いtmaxを取得しようとするなど)では、反復が不安定になり、爆発する可能性があります。これは、フォワードオイラー法の一般的な問題です。ただし、変数の制限(0 <f <1など)を維持することで、これらの不安定性を防ぐことができます。

さらに、ややマゾヒスティックに感じている場合は、v(t)の式を統合して、p(t)の閉じた形の解を得ることができる場合があります。したがって、ニュートン反復の必要性を完全に先取りします。他の人が試すためにこれを残しておきます。 =)

37
gnovice

警告:部分的な解決策

述べたように物理学に従う場合、最大速度はありません。純粋に物理的な観点から、加速度を一定値に固定しました。これは、速度が常に増加していることを意味します。

別の方法として、オブジェクトに作用する2つの力を考慮してください。

  • それを加速する傾向がある一定の外力[〜#〜] f [〜#〜]、および
  • 抗力dは、速度に比例し、速度を低下させる傾向があります。

したがって、反復nでの速度は次のようになります:vn =v + n[〜#〜] f [〜#〜]-dvn-1

最大速度を選択するように要求しました、vnmax、反復nmaxで発生します。

問題は制約不足であることに注意してください。つまり、[〜#〜] f [〜#〜]およびdは関連しているので、一方の値を任意に選択して、もう一方の値を計算できます。

ボールが転がっている今、誰かが数学を喜んで手に入れますか?

警告:それは醜くて べき級数 を含みます!


編集:最初の方程式のシーケンスn**F**は、nの後にスペースがない限り、文字通り表示されるのはなぜですか?

3
Adam Liss

これはあなたの質問に答えるものではありませんが、このようなシミュレーションで行うべきではないことの1つは、固定フレームレートに依存することです。最後の更新からの時間を計算し、方程式でdelta-Tを使用します。何かのようなもの:

static double lastUpdate=0;
if (lastUpdate!=0) {
  deltaT = time() - lastUpdate;
  velocity += acceleration * deltaT;
  position += velocity * deltaT;
}
lastUpdate = time();

また、フォーカスを失って更新を停止したかどうかを確認し、フォーカスを取得したときにlastUpdateを0に設定することもお勧めします。そうすれば、戻ったときに処理する巨大なdeltaTを取得できません。

2
GoatRider
velocity *= friction;

これは、速度が特定のポイントを回るのを妨げるものではありません...

摩擦は、速度が増加するにつれて指数関数的に増加し(それについては引用しないでください)、静止時には0になります。最終的には、摩擦=加速度になるポイントに到達します。

したがって、次のようなものが必要です。

velocity += (acceleration - friction);
position += velocity;
friction = a*exp(b*velocity);

Aとbの値を選択する場所。 bは最高速度に到達するのにかかる時間を制御し、aは摩擦が急激に増加する時間を制御します。 (繰り返しになりますが、これについて独自の調査を行わないでください。私は12年生の物理学で覚えていることから始めます。)

2
Ryan Fox

これはおそらくあなたが探しているものではありませんが、あなたが取り組んでいるエンジンによっては、 farseer (C#の場合)のような他の誰かによって構築されたエンジンを使用する方が良いかもしれません。 Codeplexはメンテナンスのためダウンしています。

1
Diones

veryで何ができるかを知りたい場合は、veryを使用した単純な物理モデル-)簡単な数学、Scratchプロジェクトのいくつかを見てください http://scratch.mit.edu/ -あなたはいくつかの有用なアイデアを得るかもしれません、そしてあなたは確かに楽しいでしょう。

1
anon