わかりました、この問題を解決できると私が考える方法について、いくつかのルーズな疑似コードを示します。
z オーダーで並べ替えられたカードのリストから始めます。各カードには、カードの完全な境界ボックスに設定された 1 つの四角形から開始する必要がある、可視四角形のリスト (後で説明します) があります。ループは、最初に最も低い z オーダーのカードから開始されます。
Cards.SortZOrder();
foreach Card in Cards do
Card.ResetVisibleRects; // VisibleRects.DeleteAll; VisibleRects.Add(BoundingBox);
CurrentCard = Cards.Last;
TestCard = CurrentCard;
ここでの考え方は、「現在の」カードから上に向かって作業し、それぞれのより高いカードがどのような影響を与えるかを確認するというものです。上位の各カードをテストすると、3 つの可能性があります。完全に見逃すか、完全に覆い隠すか、部分的に覆い隠すかのいずれかです。完全なミスの場合、現在のカードには影響しないため、テスト カードを無視します。完全にあいまいにするために、現在のカードはカリングされます。部分的なオーバーラップは、(潜在的に) 下の四角形を 2 つに分割する可能性があるため、可視の四角形のリストの出番です。(2枚のトランプまたはインデックスカードをつかむだけで、これがどのように展開するかを簡単に確認できます。上のカードは、エッジを共有している場合、下のカードがその辺の1つを調整するか、下のカードが分割されます。エッジを共有していない場合は、2 つの四角形に分割されます)。
警告: これは非常に最適化されておらず、展開されていないコードです...原則について話すためだけに。そして、はい、私は「goto」を使用しようとしています...必要に応じて私をからかってください。
[GetNextCard]
TestCard = Cards.NextHighest(TestCard);
[OverlapTest]
// Test the overlap of TestCard against all our VisibleRects.
// The first time through this test, CurrentCard will have only one
// rect in the VisibleRect list, but that rect may get split up later.
// OverlapTests() checks each rect in the VisibleRects list, and
// creates an Overlap record for any of the rects that do overlap,
// like: Overlap.RectIndex, Overlap.Type. It also summarizes the
// results into the .Summary field.
Result = CurrentCard.OverlapTests(TestCard);
case Result.Summary
none:
goto [GetNextCard];
complete:
CurrentCard.Culled = true;
// we're now done with this CurrentCard, so we move upwards
CurrentCard = TestCard;
goto [GetNextCard]
partial:
// since there was some overlap, we need to adjust,
// split, or delete some or all of our visible rectangles.
// (we won't delete them all, that would have been caught above)
foreach Overlap in Result.Overlaps
R = CurrentCard.VisibleRects[Overlap.RectIndex];
case Overlap.Type
partial: CurrentCard.SplitOrAdjust(R, TestCard);
complete: CurrentCard.Delete(R);
end case
// so we've either added new rects, or deleted some, but either
// way, we're done with this test card. We leave CurrentCard
// where it is and loop to look at the next higher card.
goto [GetNextCard]
CurrentCard = Cards.First
最上部のカードが常に完全に表示されるため、テストが行われます。
ここでさらにいくつかの考え...
これは、実際のコードではかなり簡単だと思います。それについて最も複雑なことは、長方形を 2 つに分割することであり、それがすべて整数演算であるという事実を考えると、たとえそれが些細なことであってもです。
また、これはすべてのペイント サイクルで実行する必要はありません。コンテンツ、位置、または z オーダーに変更がある場合にのみ実行する必要があります。
リストを通過すると、カードのペイント準備完了リストが残ります。カリングされていない各カードには、ディスプレイのクリッピング/ダーティ領域内に収まる可能性のある長方形が少なくとも 1 つあります。カードをペイントすると、表示されている長方形のリストを調べることができ、レンダリングにコストがかかる可能性のあるカードの部分の描画をスキップできる可能性があります。