ラグドールの日曜大工物理学。 パート1

一度ゲームを書くことにしました。 あなた自身とあなたの喜びのために。 私が選択する前に-既製の別名Box2Dをすべて使用するか、自分で物理学を書きます。 2番目の選択肢は私にとってより興味深く思えたので、必要なものをすべて書くのに役立つ情報をネットワークの広大さで探し始めました。 検索しました。 その結果、非常に柔軟で(ゲームの場合)、シンプルな物理エンジンであることが判明しました。 エンジンは、Verlet数値積分法に基づいていました。









Verletメソッドは、物質的なポイントの動きを時間で記述します。 これにはさまざまな方法があります。 たとえば、そのような連立方程式。





2つの方程式を組み合わせて、





Verletの式は、上記の表記法と大差ありません。





ご覧のように、Verletメソッドでは、ポイントの速度は、現在の座標と古い座標の差で表されます。 まあ、私たちはトラブルが少ないです。 これからの計算の精度は低下していますが、原子炉に頼っていません。 さらに、衝突の計算が途方もなく簡単になります。 例を使用してポイントの移動を検討します。





ポイントの現在の座標と古い座標が、青い正方形に向かって必然的に右に移動するように選択されていることがわかります。 少し先を見ると、正方形との衝突が検出されたとき、この衝突を処理するには、点の現在の座標を正方形から外すだけで十分だと言えます。 それだけです ここでの速度は座標の違いによって表されるため、現在の座標または古い座標の変化は、ポイントの速度の変化に自動的につながります。





これらすべてをC ++コードに入れると、次のようになります



struct Point { Vec2 Position; Vec2 OldPosition; Vec2 Acceleration; }; class Physics { int PointCount; Point* Points[ MAX_VERTICES ]; float Timestep; public: void UpdateVerlet(); }; void Physics::UpdateVerlet() { for( int I = 0; I < PointCount; I++ ) { Point& P = *Points[ I ]; Vec2 Temp = P.Position; P.Position += P.Position - P.OldPosition + P.Acceleration*Timestep*Timestep; P.OldPosition = Temp; } }
      
      





これは、質点の動きを記述するのに十分です。 そして、あなたのゲームでポイントのみが計画されているのは良いことです。 もっと面白いものが必要な場合は、ソリッドを作成する必要があります。 自然界では、固体は自然の神秘的な力によって相互接続された多くの原子点です。 残念ながら、このような方法はゲームの物理学をシミュレートするのには適していません。何十億ものポイントの計算とそれらの間の接続に耐えられるコンピューターはありません。 したがって、身体の頂点をモデリングすることで取得します。 このように正方形の場合、4つのポイントとそれらの間の接続で十分です。 これらの接続を説明するだけです。 明らかに、頂点間の距離は一定でなければなりません。 頂点間の距離が変化すると、体は変形しますが、私たちはそれを望みません(それを望む人はまだ静かです)。 ピーク間の距離を一定に保つ方法は? 実際には、この問題を解決するには、頂点間に適切な長さのアーマチュアを配置するだけで十分です。 さらに苦労せずに、シミュレーションで同じことを行います。 必要な距離に頂点を保持して、この架空の強化を記述するクラスを作成しましょう。 この作業を実行するアルゴリズムは、頂点の移動を処理した直後に呼び出されます。 本質的に、それは非常に簡単です。 架空の鉄筋で接続された2つの頂点間のベクトルを計算し、このベクトルの長さと参照長を比較します。 長さが異なる場合、必要な距離まで頂点を移動/プッシュすることしかできません。その結果、長さが再び一致し、出来上がりです-それは帽子の中にあります。

これはすべてコードでどのように見えるかです:



 struct Edge { Vertex* V1; Vertex* V2; float OriginalLength; }; void Physics::UpdateEdges() { for( int I = 0; I < EdgeCount; I++ ) { Edge& E = *Edges[ I ]; //    Vec2 V1V2 = E.V2->Position - E.V1->Position; float V1V2Length = V1V2.Length(); //    float Diff = V1V2Length - E.OriginalLength; V1V2.Normalize(); //  E.V1->Position += V1V2*Diff*0.5f; E.V2->Position -= V1V2*Diff*0.5f; } }
      
      





ここにある。 複数の頂点を作成し、そのような側面でそれらを接続すると、結果のボディは、他のボディや床との衝突によって生じる回転など、ソリッドのプロパティを示します。 どのように機能しますか? 結局のところ、ポイント間の距離を保持するための新しいルールを追加しただけで、すぐにソリッドボディになりました。 その秘密はまさにVerlet統合方法にあります。 覚えているように、このメソッドは速度では動作せず、代わりに、ポイントの現在の位置と古い位置の座標の差を使用します。 その結果、速度も変わります。 そして、頂点間の長さを一定に保つために、座標を変更するだけです。 結果として生じるピークの速度の変化は、固体の挙動にほぼ似た効果をもたらします。 より正確には、ほとんど固体です。 コードが現在あるフォームでは、ボディは床にぶつかり、互いにぶつかったときに変形します。 なんで? すべてが非常に簡単です。 頂点が複数の辺に接続されており、通常これが発生する場合、辺の1つの長さを調整すると、自動的に反対側の長さが変更されます。





この病気の唯一の治療法は、辺の長さを修正する多重呼び出し機能です。 呼び出す回数が多いほど、近似はより正確になります。 これが何回行われるかは、あなたの想像力に依存します。 これは記事の最初の部分です。 次のパートでは、身体間の衝突の検出と処理、およびこの方法を使用して行うことができる耳付きのフェイントなどの側面を検討します。




All Articles