特定のアクションが衝突を引き起こすことがわかっている場合、とにかくそのアクションの発生を許可する必要がありますか?


7

ゲームエンジンのプログラミングが完了し、テストを行ったので、グラフィックスの問題に気づきました。

大きな問題は、プレーヤーが壁を押し付けようとすると、常に壁のスペースに入ろうとし、衝突検出によって壁を外側に押し戻すため、キャラクターが壁に対して「揺れ動く」ことです。

そのような状況に対処する適切な方法は何ですか?

私の最初の本能は、特定の方向に移動すると衝突が発生する場合、エンティティの位置が変更されるまでその方向の移動を無効にしました。つまり、オブジェクトがプラットフォームに落ちたら、オブジェクトがプラットフォームの上になくなるまで重力を無効にします。

同じオーバーラップスペースにある同じ2つのオブジェクト間の繰り返し衝突検出を解決するより良い方法はありますか?

回答:


5

たとえば、壁とのキャラクターの衝突について(例として任意の値を使用します):壁から10ユニット(ピクセルなど)離れていて、通常1ステップでその方向に20ユニット移動すると、正しい動作は、キャラクターが10ユニット移動してそこで停止することです。代わりにアクションをキャンセルした場合、壁から10ユニット離れたままになり、希望どおりにはなりません。

これを行う1つの方法は、キャラクターを完全に移動し、衝突とその深度、つまりキャラクターと壁の境界ボックスがどの程度重なっているかを検出し、同じ量だけキャラクターを戻すことです。これを正しく行うと、キャラクターから「揺れ」の動作が得られないはずです。壁に押し付けてそこで停止します。彼が揺れている場合は、おそらく彼を過度に動かしている(おそらく、壁の境界にクランプするのではなく、衝突前の位置に彼を戻している)。

そうは言っても、私は通常、重力が特別なケースとして扱われるのを見ます。私が見たほとんどの実装では、キャラクターはonFloorフラグを格納し、そのフラグがfalseの場合にのみ重力が適用されます。

編集:この最後のコンセプトを拡張して、touchingRightWallまたはなどの追加のフラグを作成できると思いますがtouchingLeftWall、これはキャラクターと壁の境界が正確に一致する場合に限られます。その場合、おそらく動きを完全にバイパスすることができます。ただし、境界が正確に一致しない場合は、動きを起こさせて、衝突検出システムに交差を解決させます。


これが現在、衝突を処理する方法です。「ジグル」は、検出可能な量の前進/後退よりもスプライトが振動しているように見えます。
レイヴンドリーマー

2
交差深度を正しく計算していますか?キャラクターの位置の値と交差の深さを、予想した値と比較してデバッグしてみてください。私はこれまでにまったく振動なしでこれをやったことがあります。サブピクセル浮動小数点問題のいくつかのケースである可能性もありますか?その場合は、値を丸めてみてください。そして最後に、XNAのplatformerサンプルを確認してください。
David Gouveia

正直なところ、それは、IO(エンティティを移動する)が衝突検出とは異なるタイミングで発生するためだと思います。つまり、ゲームエンジンが衝突サブシステムの更新ループに到達するまで、2つのエンティティがオーバーラップします。
レイヴンドリーマー

しかし、IOと衝突検出サブシステムは、更新ループの同じ反復で更新されていませんか?これが違いを生むのを見ることができる唯一の方法は、レンダリングループが完全に分離していて、サブシステムの更新間で何らかの方法で呼び出すことができるか、またはこの処理を複数のフレーム間で引き伸ばしている場合です。
David Gouveia

通常、プロセス全体は[IO->衝突検出->衝突解決]-> [レンダリング]になります。Update部分とRender部分が異なるレートで呼び出されても、レンダリングされたオブジェクトを中間状態(つまり、IOの後、衝突検出の前、または衝突検出の後、衝突解決の前)で表示することはできません。Updateのすべてのステージが適用された後は、常にレンダリングされたキャラクターが表示されるので、それらが異なるステップで処理されるかどうかは問題になりません。
David Gouveia

2

この問題は通常、コードが衝突を検出する前に位置をクランプするときに発生します。すなわち:

MoveCharacter();
ClampPosition();
CheckCollision();
DrawFrame();

の代わりに

MoveCharacer();
CheckCollision();
ClampPosition();
DrawFrame();

「ジグル」する理由は、チェックが行われるのは、キャラクターが「安全な」場所に固定された後ですが、チェック時にキャラクターが衝突しない場所にあるため、エンジンはキャラクターに移動すると、キャラクターが描画され、次のフレームのチェックが失敗します。Clampが呼び出され、キャラクターが安全な場所に「スナップ」されます。


1
これがどうして意味があるのか​​、私にはよくわかりません。衝突の結果から、最初にクランプする値を知る必要がある場合、衝突をチェックする前にクランプがどのように発生する可能性がありますか?
David Gouveia

実際に起こっていることは、現在のフレームが描画される前に正しい位置移動するのではなく、次のフレームの正しい位置に移動するに文字が描画されていることです。
ケーシー

0

私は最近同じ問題を抱えており、次のように修正しました:

オブジェクトを移動して衝突をチェックし、衝突が見つかった場合は、オブジェクトを衝突オブジェクトの外側に配置します。オブジェクトを描画します。

プレイヤーは、描画される前にオブジェクトの横に配置されるため、揺れずに壁に走り続けることができます。


0

ベクトル/平面数学を使用して、次のフレームで発生する壁との正確な衝突点を計算できます。これは、次のフレームで発生する動きベクトルの計算に使用できる速度がキャラクターにあることを前提としています。衝突点を見つけた後、壁に沿ってキャラクターを動かすスライディングベクトルを計算できます。このベクトルは、実際には別の壁と衝突する可能性があります。

したがって、あなたの質問に戻って、あなたはあなたのキャラクターが配置されるべき衝突の正確な位置と実際に何が起こったのかを計算するべきです。これが壁とそのFPSゲームの場合、キャラクターをそれに沿ってスライドさせます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.