1724097300
2024-08-19 13:14:31
≤ a[1] ≤ a[2] ≤ … ≤ a[n-1]” src=”https://leanrada.com/notes/sweep-and-prune/sorted.png” caption=”The inequality relationships of elements in a sorted list.”/>ソートされたリスト内の要素の不等関係。
フレームごとにオブジェクトのリストをソートしなければならない場合でも、最も高速な一般的なソートアルゴリズムは O(n log n) 時間は確かに の上2)。
上記の 3 つのオブジェクトの例で示されているように、テストをスキップする機能を実現するには、オブジェクトのリストを x 位置で並べ替える必要があります。
しかし、オブジェクトはゼロ幅の点ではありません。 幅広のつまり、サイズがあり、x 軸の間隔を占めることを意味します。これは「幅」とも呼ばれます。オブジェクトが x 軸の間隔にまたがっている場合、x 位置で明確に並べ替えるにはどうすればよいでしょうか。
最小値で並べ替え x
幅の広いオブジェクトを並べ替える解決策は、 最小x (左端の x 座標)。この手法は、単純なアプローチを改善するために適用できます。
O(n)への最小限の変更のみで済みます。2) ソリューションです。ただし、かなりのテストがスキップされることになります。これについては後で説明します。
まず、変更されたコード:
+
+ sortByLeft(balls);
+
for (let i = 0; i balls.length; i++) {
const ball1 = balls[i];
for (let j = i + 1; j balls.length; j++) {
const ball2 = balls[j];
+
+
+ if (ball2.left > ball1.right) break;
+
if (intersects(ball1, ball2)) {
bounce(ball1, ball2);
}
}
}
これは単純なソリューションとほとんど同じですが、コードが 2 行追加されている点のみが異なります。
最初の行 sortByLeft(balls) ボールの左端の x 座標に基づいてランキング付けし、リストを単純に並べ替えます。
function sortByLeft(balls) {
balls.sort((a,b) => a.left - b.left);
}
そして、内側のループには、次のブレークがあります。
if (ball2.left > ball1.right) break;
それを詳しく見てみましょう。
まず、リストはソートされていることがわかっているので、次の文は任意の正の整数に対して成り立ちます。
c:
balls[j + c].left >= balls[j].left
交差テストの最初のオペランドから導出されるブレーク条件が true の場合、交差をテストしている現在のペアが失敗する可能性が早期に示されます。
balls2.left > ball1.right
または balls[j].left > ball1.right
しかし、さらに意味があります。もしそれが本当なら、上記の 2 つの不等式を組み合わせると…
balls[j + c].left >= balls[j].left > ball1.right
そして推移的性質により、次の文も真となります。
balls[j + c].left > ball1.right
つまり、ボールの交差テストは
balls[j + c]
不合格になる可能性もあります。ボールを個別にテストしなくても、このことはわかります。さまざまなボールがテストから除外されました。
結論として、現在の ボール2
balls[j]
現在のものと重なり合うのを止める ボール1、その後さらに ボール2反復中のs
balls[j + c]
重複しないことが保証される ボール1 同様に。言い換えると、内側のループが遠すぎる場合は停止します。
最後に、デモを紹介します。
強調表示されたペア テストされたとき intersects()。
かなりすごいですよね! かなり速くなりました。
いくつかの観察:
- リストはソートされているため、テストは左から右に実行されます。
- さらに重要なのは、単純なアプローチよりも明らかにテストが少なくなることです。📉 これは、ペアを x 軸で重なるものに効果的に制限する上記の最適化によるものです。
時間の複雑さを分析してみましょう。👓
ソートは、マージソートやクイックソートのような「最速」のソートアルゴリズムを採用すると、 O(n log n) 学期。
2レベルのループは、早期のブレークにより平均すると O(n+m) の場合 どこ メートル はxの重なりの総数です。これはnに縮退する可能性があります2 しかし、上で述べたように、平均と最良のケースを見る方が有用です。最良の場合、ループは次のようになります。 の上)重複がない場合には余分な処理を無駄にしません。平均的には O(n+m) の場合。
平均的なケースとは、オブジェクトがほぼ均等に分散され、オブジェクトごとに交差が 2、3 回しか発生しない世界を指します。これは、プラットフォーム ゲームや横スクロール ゲームなどの比較的単純なビデオ ゲームでは妥当な仮定だと思います。
実行時間の注釈が付いたコードは次のとおりです。
sortByLeft(balls);
for (let i = 0; i balls.length; i++) {
const ball1 = balls[i];
for (let j = i + 1; j balls.length; j++) {
const ball2 = balls[j];
if (ball2.left > ball1.right) break;
if (intersects(ball1, ball2)) {
bounce(ball1, ball2);
}
}
}
これらを足すと O(nlogn+m) は、。
これは、単純なアプローチに比べて非常に優れた改善です。 の上2)、 なぜなら [1] n 対数 n は はるかに小さい よりも ん2 そして [2] 部分的に出力ベースであり、重複の数に応じて、必要以上に処理することはありません。
ビッグチートシート
さらに、ソートアルゴリズムの選択も改善できる可能性があります。次の部分でそれについて検討します( n 対数 n!)。
適切な衝突検出アルゴリズムを見つけようとしてここまで来たのなら、読むのをやめて上記の設計を採用してください。これはプログラミングの労力と実行時のパフォーマンスの完璧なバランスです。これがどのように開発されるのか知りたい場合、またはもっとインタラクティブなデモを見たい場合は、次の部分を読んでください。
視覚的な比較
これまでに説明した戦略を並べて比較してみましょう。フレームごとに必要な交差テストの数を確認してください。🔍 n = 10
(表示されていないもの: ソートのコスト。交差テストは十分にコストがかかるとだけ言っておきます。)
これで最初の部分は終わりです。この 2 行のコードが間違いなく MVP でした。
より高度なバージョンと比較するとどうなりますか?
パート2に続きます。
#衝突検出アルゴリズム #leanrada.com0 #2023年8月5日span #13分で読めます #pタグ #span #classtagcomponent #pcategory #titlealgorithm #stylebackground #6bfbfa #color #097d7c何かspan #span #classtagcomponent #pcategory #stylebackground #b7eaa6 #color #336920ゲームspan #pスイープ #アンド #プルーンはゲームの衝突検出をすばやく実装したいときに私がよく使うアルゴリズムですこれは素晴らしくエレガントなアルゴリズムだと思うのでそれについて記事を書きましたp #pこの投稿は多くの例と説明を含む長い記事であるため2 #つの部分に分かれています次の特別なスプリングボードを使用して特定の部分にジャンプできますp #p残りの投稿では私が第一原理と考えるものを絵に描きそれを次のように示そうとします #strongインタラクティブデモstrong #さあ行こうp #idcollisiondetection衝突検出h2 #pご存知のとおり衝突検出の問題はビデオ #ゲーム #プログラミングでは非常に一般的ですこれは特定のゲーム #メカニクスやシミュレーションを実装するための前提条件ですp #div #classblogmedia #blogmediadefault #img #loadinglazy #width100 #dataplaceholder #styleaspectratio #1.3333333333333333background #6888f8 #classblogmediaelement #altマリオとクリボーがぶつかり合うビデオ #srchttpsleanrada.comnotessweepandprunemario.gif #captionGoombas #collidingspan #classblogmediacaption衝突するクリボーspan #div #pこれらのメカニズムにはキャラクター同士が通り抜けるのを防ぐ #target_blank #target_blank #classtextlink #hrefhttpsyoutu.beKy69PjyHCqgグンバa #ぶつかったときに向きを変え大きな細胞が小さな細胞を食べる #target_blank #target_blank #classtextlink #hrefhttpsagar.ioアガーaまたはほぼすべてのゲーム物理これらすべてに何らかの衝突検出が必要ですp #div #classblogmedia #blogmediadefault #img #loadinglazy #width100 #dataplaceholder #styleaspectratio #1.3333333333333333background #f8f8f8 #classblogmediaelement #alt細胞が小さな細胞を食べる #agar.io #のビデオ #srchttpsleanrada.comnotessweepandpruneagario.gif #captionCells #consuming #smaller #cells #contactspan #classblogmediacaption接触すると細胞が小さな細胞を消費するspan #div #pここでは最も単純なものから始めて #target_blank #target_blank #classtextlink #hrefhttpsen.wikipedia.orgwikiSweep_and_prunestrong掃除と剪定stronga #アルゴリズム空間分割や空間ツリーの細分化などの他のアプローチについては説明しませんp #pボールp #pこれを使うよ #strong剛体ボールシミュレーションstrong #記事全体を通してアルゴリズムを説明するために繰り返し使用される例として次のものがありますp #pでは始めましょう #これらの衝突をどのように検出するのでしょうかp #idnaiveapproach素朴なアプローチ #p最も簡単な解決法は衝突の可能性があるすべての物体のペアをテストすることですつまり #emすべてのボールを他のすべてのボールと比較するemp #pre #classcodeblock #code #classcodeblockcodespan #classtoken #keywordforspan #span #classtoken #punctuationspanspan #classtoken #keywordletspan #span #classtoken #operatorspan #span #classtoken #number0spanspan #classtoken #punctuationspan #span #classtoken #operator #ballsspan #classtoken #punctuation.spanlengthspan #classtoken #punctuationspan #ispan #classtoken #operatorspanspan #classtoken #punctuationspan #span #classtoken #punctuationspan #span #classtoken #keywordconstspan #ball1 #span #classtoken #operatorspan #ballsspan #classtoken #punctuationspanispan #classtoken #punctuationspanspan #classtoken #punctuationspan #span #classtoken #keywordforspan #span #classtoken #punctuationspanspan #classtoken #keywordletspan #span #classtoken #operatorspan #span #classtoken #operatorspan #span #classtoken #number1spanspan #classtoken #punctuationspan #span #classtoken #operator #ballsspan #classtoken #punctuation.spanlengthspan #classtoken #punctuationspan #jspan #classtoken #operatorspanspan #classtoken #punctuationspan #span #classtoken #punctuationspan #span #classtoken #keywordconstspan #ball2 #span #classtoken #operatorspan #ballsspan #classtoken #punctuationspanjspan #classtoken #punctuationspanspan #classtoken #punctuationspan #span #classtoken #keywordifspan #span #classtoken #punctuationspanspan #classtoken #functionintersectsspanspan #classtoken #punctuationspanball1span #classtoken #punctuationspan #ball2span #classtoken #punctuationspanspan #classtoken #punctuationspan #span #classtoken #punctuationspan #span #classtoken #functionbouncespanspan #classtoken #punctuationspanball1span #classtoken #punctuationspan #ball2span #classtoken #punctuationspanspan #classtoken #punctuationspan #span #classtoken #punctuationspan #span #classtoken #punctuationspanspan #classtoken #punctuationspanspanspancodepre #p上記のコードでは内側のループが #codei #1code #重複したペアがカウントされるのを防ぐためです #と #BAそれ以外は非常にシンプルな解決策ですp #pこれらのチェックはタイムステップごとに実行されボールが衝突したときに正確に跳ね返ることが保証されますp #p以下は時間ステップごとに交差がテストされるペアを示す速度を落としたハイライト表示のシミュレーションですp #div #classdemorow #sapdemoclient #class #datarssinteractive #altdemo #collision #detection #algorithm #pairwise #strategy #strategypairwise #skipinterval4 #decorationschecks4c8 #ペアはハイライト表示されます #span #arialabela #connecting #green #line #stylecolor4c8 #classpairlegend #テストを受ける際 #codeintersectscode #div #pそしてそれは機能しますしかしボールが数個以上あるとパフォーマンスの問題が発生し始めますp #idperformanceorlackthereofパフォーマンスまたはその欠如h2 #pこの単純なアルゴリズムは #emstrongの上sup2supstrongem #時間 #target_blank #target_blank #classtextlink #hrefhttpsen.wikipedia.orgwikiBig_O_notationビッグオー用語aつまり入力が #emんem #ボールの数に応じてアルゴリズムの実行時間は増加します #em四角em #入力の #emんemたくさんですねp #pこれは #emんem #ボールは周りにあります #emn #n12em #テストするペアまたは #em0.5nsup2sup #0.5nemたとえばn #の場合ペアは合計 #個になりますn #の場合ペアは #個になりますn #の場合ペアは #個になります #などなど.. #Big #記法を使用するとこの情報を簡潔な式に簡略化できます #emの上sup2supemp #p入力が大きくなるとパフォーマンスが悪化することを苦痛を伴うが実証するためにn #のシミュレーションを示しますp #div #classdemorow #sapdemoclient #class #datarssinteractive #altdemo #collision #detection #algorithm #pairwise #strategy #balls20 #strategypairwise #skipinterval4 #decorationschecks4c8 #20個のボール #テストするペア190個 #div #pフレームごとに大量のテストが行われます明らかに単純なソリューションでは多数のオブジェクトに対しては適切にスケーリングできませんp #pこのソリューションをどのように改善できるでしょうかp #span #classboxnote #p最悪の場合の実行時間は #emどれでもem #衝突検出アルゴリズムは常に #emの上sup2supem全てのオブジェクトが同時に交差しn個のオブジェクトをそれぞれ処理する以外に選択肢がないときですsup2sup #衝突p #pしたがって平均的なケースと最良のケースを比較する方が実用的ですp #pそうは言っても素朴なアルゴリズムは依然として #emΘnsup2supem #のために #emどれでもem #実際の衝突回数に関係なく改善の余地は大いにありますp #span #idprologueimprovingthesolutionプロローグ #ソリューションの改善h2 #p通常アルゴリズムを最適化するときは #strong冗長または不必要な作業strong次にその冗長性を統合する方法を見つけます企業っぽいですねp #pまず最初に #codeintersectscode #この関数はすべての候補ペアに対して呼び出されます #target_blank #target_blank #classtextlink #hrefhttpsgdbooks.gitbooks.io3dcollisionscontentChapter2static_aabb_aabb.html典型的なオブジェクト交差テストa #その実装として私たちはこれらの束を手に入れます #strong不平等チェックstrongp #pre #classcodeblock #code #classcodeblockcodespan #classtoken #keywordfunctionspan #span #classtoken #functionintersectsspanspan #classtoken #punctuationspanspan #classtoken #parameterobject1span #classtoken #punctuationspan #object2spanspan #classtoken #punctuationspan #span #classtoken #punctuationspan #span #classtoken #keywordreturnspan #object1span #classtoken #punctuation.spanleft #span #classtoken #operator #object2span #classtoken #punctuation.spanright #span #classtoken #operatorspan #object1span #classtoken #punctuation.spanright #span #classtoken #operatorspan #object2span #classtoken #punctuation.spanleft #span #classtoken #operatorspan #object1span #classtoken #punctuation.spantop #span #classtoken #operator #object2span #classtoken #punctuation.spanbottom #span #classtoken #operatorspan #object1span #classtoken #punctuation.spanbottom #span #classtoken #operatorspan #object2span #classtoken #punctuation.spantopspan #classtoken #punctuationspanspan #classtoken #punctuationspanspanspancodepre #p上記のコードでは #codeintersectscode #関数は2つのオブジェクトが交差するかどうかをそれぞれの方向の反対の境界を比較してチェックします #target_blank #target_blank #classtextlink #hrefhttpsdeveloper.mozilla.orgenUSdocsGamesTechniques3D_collision_detectionaabb_vs._aabbこのMDNの記事a #より詳しい説明についてはこちらをご覧くださいp #pテストを構成要素のチェックに分解することができますp #licodeobject1.left #codeli #licodeobject1.right #object2.leftcodeli #licodeobject1.top #codeli #licodeobject1.bottom #object2.topcodeli #p各チェックは特定の方向の特定の軸のみを対象としますp #pここで重要なことは #codecode #オペレーターの #target_blank #target_blank #classtextlink #hrefhttpsen.wikipedia.orgwikiShortcircuit_evaluation短絡評価aこれらのチェックのいずれかが偽であることが判明した場合全体のテストは直ちに偽であると評価されますp #p私たちの目標は少なくとも #em1つem #これらのチェックは可能な限り多くのテストで誤りになりますp #pspan #classboxnote #これは #target_blank #target_blank #classtextlink #hrefhttpspersonal.math.vt.edumrlugosat.html分離軸定理aこれは影が重ならない軸が少なくとも #つある場合2 #つのオブジェクトが衝突することはないことを意味しますspanp #p2番目のチェックだけに焦点を当ててみましょう #codeobject1.right #object2.leftcode残りのチェックについては心配しないでください上で示唆したように1 #つの軸のみを最適化すると後で大きな違いが生じる可能性があるため今はこの #つのチェックに焦点を当てますp #div #classblogmedia #blogmediadefault #img #srcsethttpsleanrada.comgen_notes_sweep_and_prune_surprisetool_200.generated.jpg #200w #sizes #200px #spec200 #loadinglazy #width100 #dataplaceholder #styleaspectratio #1.2127659574468086background #classblogmediaelement #alt漫画のネズミがこれは後で役に立つサプライズツールだよと言っている静止画 #srchttpsleanrada.comnotessweepandprunesurprisetool.jpg #div #p複数のオブジェクトのコンテキストで考えてみましょう水平構成の #つのオブジェクト #ABC #を考えてみましょうp #div #classblogmedia #blogmediadefault #img #srcsethttpsleanrada.comnotessweepandpruneabc.png #664w #sizes #664px #spec100 #loadinglazy #width100 #dataplaceholder #styleaspectratio #2.034749034749035background #f8f8f8 #classblogmediaelement #altThree #objects #left #srchttpsleanrada.comnotessweepandpruneabc.png #div #pThere #potential #pairs #checked #Remember #find #redundant #work #Pretend #running #pairs #check #sop #pre #classcodeblock #code #classcodeblockcodespan #classtoken #constantAspanspan #classtoken #punctuation.spanright #span #classtoken #operatorspan #span #classtoken #constantBspanspan #classtoken #punctuation.spanleft #span #classtoken #constantBspanspan #classtoken #punctuation.spanright #span #classtoken #operatorspan #span #classtoken #constantCspanspan #classtoken #punctuation.spanleft #span #classtoken #constantAspanspan #classtoken #punctuation.spanright #span #classtoken #operatorspan #span #classtoken #constantCspanspan #classtoken #punctuation.spanleft #codepre #pSee #redundant #work #abstractify #littlep #pre #classcodeblock #code #classcodeblockcodespan #classtoken #constantAspan #span #classtoken #operatorspan #span #classtoken #constantBspan #span #classtoken #constantBspan #span #classtoken #operatorspan #span #classtoken #constantCspan #span #classtoken #constantAspan #span #classtoken #operatorspan #span #classtoken #constantCspan #codepre #pVoilà #Due #target_blank #target_blank #classtextlink #hrefhttpswww.mathwords.comttransitive_property_inequalities.htmstrongtransitive #property #inequalitystronga #realise #dont #run #strongthird #teststrong #emIf #codeABcode #codeBCcode #codefalsecode #codeACcode #codefalsecode #well.emp #blockquote #pIf #citethe #transitive #property #inequalitycite #blockquote #pSo #dont #run #codeintersectsA #Ccode.p #pre #classcodeblock #code #classcodeblockcodespan #classtoken #functionintersectsspanspan #classtoken #punctuationspanspan #classtoken #constantAspanspan #classtoken #punctuationspan #span #classtoken #constantBspanspan #classtoken #punctuationspan #span #classtoken #functionintersectsspanspan #classtoken #punctuationspanspan #classtoken #constantBspanspan #classtoken #punctuationspan #span #classtoken #constantCspanspan #classtoken #punctuationspan #codepre #pWeve #skipped #codeintersectscode #call #free #span #classboxnote #handwaving #fact #codeP.left #P.rightcode #implied #object #working #details #transitivity #span #pYou #wondering #contrived #apply #general #nbody #collision #detection #smart #reader #realised #skip #works #strongparticular #orderstrong.p #pWhat #order #span #classdraghintdraggingspan #balls #optimisation #applies #notp #div #classdemorow #sapdemoclient #class #sapdemodraggable #datarssinteractive #altinteractive #diagram #showing #specific #mechanism #idabcdemo #balls150250503001505545027560 #strategysapnativesort #static #draggable #labelsABC #rainbow #pre #classcodeblock #stylewidth #maxwidth #600pxcode #classcodeblockcodespan #classtoken #functionintersectsspanspan #classtoken #punctuationspanspan #classtoken #constantAspanspan #classtoken #punctuationspan #span #classtoken #constantBspanspan #classtoken #punctuationspan #span #classtoken #functionintersectsspanspan #classtoken #punctuationspanspan #classtoken #constantBspanspan #classtoken #punctuationspan #span #classtoken #constantCspanspan #classtoken #punctuationspan #span #classabcdemointersectsacrun #styledisplay #nonespan #classtoken #functionintersectsspanspan #classtoken #punctuationspanspan #classtoken #constantAspanspan #classtoken #punctuationspan #span #classtoken #constantCspanspan #classtoken #punctuationspan #spancodepre #div #pspan #classboxnote #strongヒントstrong #ボールをドラッグしてABCの順序で水平方向に並べますspanp #pこのスキップはABCの順序でのみ機能するのは事実ですがこれらのラベルは #em任意em #一番左のボールを常に #A真ん中のボールを #B一番右のボールを #と呼ぶことにしたらどうなるでしょうか #そうすれば最適化は常に適用可能になります #pでも待ってくださいオブジェクトに論理的な順序に従ってラベルを付けるというのは本質的にはstrong並べ替えstrong #オブジェクトのリストを毎回ソートしたらどうなるでしょうか #スキップされるテストの数はソートのコストに見合うでしょうかp #idchapter1sorting第1章 #ソートh2 #pソート不等式最適化は密接に関連しています #emソートされたリストを使用すると不等式の推移的性質をまとめて利用することができますemp #div #classblogmedia #blogmediadefault #img #srcsethttpsleanrada.comgen_notes_sweep_and_prune_sorted_664.generated.png #664w #sizes #664px #spec100 #loadinglazy #width100 #dataplaceholder #styleaspectratio #10background #f8f8f8 #classblogmediaelement #alt1つの