プラットフォーマーのキャラクターが壁のタイルでクリッピングしないようにするにはどうすればよいですか?


9

現在、私は地形のタイル(Cave Storyから借りたグラフィック)を備えたプラットフォーマーを持っています。ゲームはXNAを使用してゼロから作成されているため、既存のエンジンや物理エンジンは使用していません。

タイルの衝突はこの回答で説明されているとおりに正確に説明され(長方形と円の単純なSATを使用)、すべてが正常に機能します。

落下/ジャンプ中にプレーヤーが壁にぶつかった場合を除きます。その場合、彼らはタイルに引っ掛かり、実際にはない床や天井にぶつかったと思い始めます。

キャラクターキャッチのイメージ

このスクリーンショットでは、プレーヤーは右に移動しており、下に落ちています。したがって、移動後、衝突がチェックされます-そして最初に、プレイヤーキャラクターが床から3番目のタイルに衝突し、上に押し出されていることがわかります。第二に、彼は自分の隣のタイルと衝突して横に押されていることがわかりました-最終的にプレイヤーキャラクターは自分が地面にいて落下していないと考え、タイルに走っている限り「キャッチ」します。 。

タイルを上から下に定義することでこれを解決でき、スムーズに落下しますが、逆のケースが発生し、壁に上向きにジャンプすると、そこにない天井にぶつかります。

これを解決して、プレイヤーキャラクターが壁に沿って落下するようにするにはどうすればよいですか?


この質問に似ていますか?gamedev.stackexchange.com/questions/14486/...
MichaelHouse

@ Byte56質問は同じではありませんが、答えは役立つかもしれません。
doppelgreener

注:ここ数週間、ここで答えを試す時間はほとんどありませんでした。@ Byte56リンクされた質問で回答されているように、世界の衝突解決を実装しました。これには、高速で別個のバグがあり、この質問への回答をまだ試すことができません。可能な場合はそれらを試し、可能な場合は回答を受け入れるか、自分で解決した場合は自分で投稿します。
doppelgreener

回答:


8

最も単純でフェイルプルーフのアプローチは、隠れたエッジの衝突をチェックしないことです。2つの壁タイルがあり、一方が他方の真上にある場合、上部タイルの下端と下部タイルの上端をプレーヤーとの衝突についてチェックしないでください。

タイルマップを単純に通過するときに有効なエッジを判別し、外側のエッジを各タイル位置のフラグとして保存できます。衝突検出中に隣接するタイルをチェックすることで、実行時にこれを実行することもできます。

これと同じ手法のより高度なバージョンがあり、非正方形のタイルのサポートも簡単かつ高速になります。

以下の記事を読むことをお勧めします。それらは、現代のプラットフォーマー(Cave Storyなど)で基本的な物理学と衝突検出を行うためのまともな簡単な紹介です。より古風なマリオフィールを求める場合は、気にする必要があるトリックがいくつかありますが、それらのほとんどは、衝突ではなくジャンプとアニメーションの処理を伴います。

http://www.metanetsoftware.com/technique/tutorialA.html http://www.metanetsoftware.com/technique/tutorialB.html


衝突時に一部のエッジを無視する方法を明確にできますか?通常、衝突は2つの長方形(プレーヤーの境界とタイルの境界)の交差として検出されます。個々のエッジとの衝突をチェックしないと言うとき、それは衝突アルゴリズムが長方形と長方形の交差ではなく、他の何かであることを意味しますか?あなたの説明は理にかなっていますが、実装がどのようになるかわかりません。
David Gouveia

ええ、長方形の線の衝突を行います。線は常に軸合わせされているため、単純化されています。ボックスチェックを分解するだけです。
Sean Middleditch

5

ここで私が物事をする順序....

1)文字の現在のX、Yを保存

2)X方向に移動します

3)タイルデータを取得して文字のすべてのコーナーを確認し、次の操作を行ってそれが固体かどうかを確認します(XとYは文字の位置です)

  • 左上:floor(X / tileWidth)、floor(Y / tileHeight);
  • 右上の場合:floor((X + characterWidth)/ tileWidth)、floor(Y / tileHeight);
  • 左下の場合:floor(X + / tileWidth)、floor((Y + characterHeight)/ tileHeight);
  • 右下の場合:floor((X + characterWidth)/ tileWidth)、floor((Y + characterHeight)/ tileHeight);

...マップデータから正しいタイルデータを取得する

4)タイルのいずれかが無地の場合、保存したXを復元して、Xを可能な限り最適な位置に強制し、...

  • 左に移動する場合:X = floor(X / tileWidth)* tileWidth;
  • 右へ移動する場合:X =((floor((X + characterWidth)/ tileWidth)+ 1)* tileWidth)-characterWidth;

5)Yを使用して2〜4を繰り返す

キャラクターがタイルよりも高い場合は、さらにタイルを確認する必要があります。これを行うには、ループしてtileHeightをcharacterY位置に追加してタイルを取得する必要があります

int characterBlockHeight = 3;

// check all tiles and intermediate tiles down the character body
for (int y = 0; y < characterBlockHeight - 1; y++) {
    tile = getTile(floor(characterX / tileWidth), floor((characterY + (y * tileHeight)) / tileHeight));
    ... check tile OK....
}

// finally check bottom
tile = getTile(floor(characterX / tileWidth), floor((characterY + characterHeight) / tileHeight);
... check tile OK....

文字が1ブロックより広い場合は、同じようにしますが、characterY、characterHeight、tileHeightなどをcharacterX、characterWidthなどに置き換えます。


2

プレーヤーの移動方法の一部として衝突の可能性をチェックし、プレーヤーを別のオブジェクトにスライドさせる移動を拒否した場合はどうなりますか?これにより、プレーヤーはブロックの「内側」に入ることができなくなり、そのため、その下のブロックの「上」になることはできません。


1

現在取り組んでいるゲームでほぼ同じ問題に遭遇しました。私が解決した方法は、衝突をテストするときに重複部分の領域を保存し、優先順位に基づいてそれらの衝突を処理し(最初に最大の領域)、次に各衝突を再確認して、以前の衝突によってすでに解決されているかどうかを確認することでした。取り扱い。

あなたの例では、x軸の衝突の領域はy軸よりも大きいため、最初に処理されます。次に、y軸の衝突を処理する前に、x軸上で移動した後、衝突していないことを確認します。:)


1

単純ではあるが完全ではない修正方法は、プレーヤーの衝突ボックスの形状を変更して、正方形にならないようにすることです。角を切り取って八角形のようなものにします。このようにして、彼が壁のタイルのようなタイルと衝突したとき、彼はそれから滑り落ち、引っ掛かることはありません。彼が少しコーナーでキャッチしていることにまだ気づくことができるので、これは完璧ではありませんが、彼は動けなくなることはなく、実装は非常に簡単です。


1

このチュートリアルでは、非常によく似た問題について説明しました:ゲーム開発入門。ビデオの関連部分は1:44にあります、図とコードスニペットで説明しています。

お知らせ14-tilemap.pyクリッピングの問題は、それが中に固定されている展示15-blocker-sides.py

最後のチュートリアルの例がコードの実行中にクリップされない理由を正確に説明することはできませんが、次のように関係していると思います。

  • タイルのタイプ(実際にアクティブなエッジ)に基づく条件付き衝突応答
  • プレーヤーは常に「落下」しています。プレーヤーはタイルの上で休んでいるように見えますが、プレーヤーは実際にはタイルを何度も落下してから、上に押し戻されています。(self.restingコード内のメンバーは、プレーヤーがジャンプできるかどうかを確認するためだけに使用されます。それにもかかわらず、壁からプレーヤーに「ダブル」ジャンプをさせることはできません。理論的には、それは可能かもしれません)

0

別の方法(Byte56のリンク先の質問に答えました)は、衝突の解決によって文字が空のスポットに配置されるかどうかを確認することです。したがって、問題では、長方形の天井の内側から衝突して上に移動しますが、これは違法です(まだ別のタイルと衝突しているため)。代わりに、フリースペースに移動した場合(上部のタイルからの衝突によってどのように左に移動するかなど)にのみ移動し、その衝突を見つけたら完了です。

私が出した答えにはコードがありましたが、それは過度に複雑になりました。その時間枠内のすべての衝突を追跡し、空き領域につながる衝突のみを取得します。しかし、何もない場合は、キャラクターの位置を最後の位置にリセットすることに頼ったと思いますが、それは本当に醜いです。おそらく、元のマリオのようなものを実装することをお勧めします。可能だ。また、衝突解決のリストをソートして、最短距離の空きスペースにのみ移動することもできます(そのためのコーディングはしていませんが、ソリューションが最も望ましいと思います)。


0

私は3SATを3Dで実行しただけなので、これを正しく行っていない可能性があります。問題を理解できれば、接触軸との接触が不可能になり、プレーヤーが床のように振る舞うことが原因である可能性があります。回避策の1つとして、キャラクターに円形を使用することが考えられます。そうすると、壁にぶつかったときにx軸方向の接触軸のみが取得されます。

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