< Summary

Information
Class: Gravitas.CollisionHandling.CollisionDetection2D
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/CollisionHandling/Detection/2D/CollisionDetection2D.cs
Line coverage
100%
Covered lines: 465
Uncovered lines: 0
Coverable lines: 465
Total lines: 781
Line coverage: 100%
Branch coverage
100%
Covered branches: 142
Total branches: 142
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/CollisionHandling/Detection/2D/CollisionDetection2D.cs

#LineLine coverage
 1//=======================================================================
 2// CollisionDetection2D.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using FixedMathSharp.Geometry;
 10using Gravitas.Colliders;
 11using System;
 12using System.Runtime.CompilerServices;
 13
 14namespace Gravitas.CollisionHandling;
 15
 16/// <summary>
 17/// Deterministic pure 2D narrow-phase collision checks.
 18/// </summary>
 19internal static class CollisionDetection2D
 20{
 21    internal static bool TryCollide(LSCollider2D colliderA, LSCollider2D colliderB, out Contact2D contact)
 22    {
 237323        SwiftThrowHelper.ThrowIfNull(colliderA, nameof(colliderA));
 237324        SwiftThrowHelper.ThrowIfNull(colliderB, nameof(colliderB));
 25
 237326        CollisionType2D collisionType = ColliderSettings2D.GetCollisionType(colliderA.Shape, colliderB.Shape);
 237327        return TryCollide(new CollisionWorkItem2D(colliderA, colliderB, collisionType), out contact);
 28    }
 29
 30    internal static bool TryCollide(CollisionPair2D pair, ContactManifold2D manifold, int frame)
 31    {
 54632        SwiftThrowHelper.ThrowIfNull(pair, nameof(pair));
 54633        return TryCollide(CollisionWorkItem2D.Create(pair), manifold, frame);
 34    }
 35
 36    internal static bool TryCollide(CollisionWorkItem2D item, ContactManifold2D manifold, int frame)
 37    {
 62138        SwiftThrowHelper.ThrowIfNull(manifold, nameof(manifold));
 62139        manifold.BeginUpdate(frame);
 62140        return TryCollide(item, manifold);
 41    }
 42
 43    internal static bool TryCollide(CollisionWorkItem2D item, out Contact2D contact)
 44    {
 237545        LSCollider2D colliderA = item.ColliderA;
 237546        LSCollider2D colliderB = item.ColliderB;
 237547        if (!BoundsOverlap(colliderA, colliderB))
 48        {
 139949            contact = default;
 139950            return false;
 51        }
 52
 97653        switch (item.CollisionType)
 54        {
 55            case CollisionType2D.Circle_Circle:
 5856                return TryCircleCircle((LSCircleCollider2D)colliderA, (LSCircleCollider2D)colliderB, out contact);
 57            case CollisionType2D.Circle_Convex:
 3858                return TryCircleConvex((LSCircleCollider2D)colliderA, colliderB, out contact);
 59            case CollisionType2D.Convex_Circle:
 78560                bool result = TryCircleConvex((LSCircleCollider2D)colliderB, colliderA, out Contact2D reversed);
 78561                contact = result
 78562                    ? new Contact2D(
 78563                        reversed.AnchorB,
 78564                        reversed.AnchorA,
 78565                        -reversed.Normal,
 78566                        reversed.Depth,
 78567                        reversed.DepthIsClamped)
 78568                    : default;
 78569                return result;
 70            case CollisionType2D.Convex_Convex:
 5371                return TryConvexConvex(colliderA, colliderB, out contact);
 72            case CollisionType2D.Capsule_Circle:
 773                return TryCapsuleCircle((LSCapsuleCollider2D)colliderA, (LSCircleCollider2D)colliderB, out contact);
 74            case CollisionType2D.Circle_Capsule:
 475                bool circleCapsule = TryCapsuleCircle((LSCapsuleCollider2D)colliderB, (LSCircleCollider2D)colliderA, out
 476                contact = circleCapsule
 477                    ? new Contact2D(
 478                        circleCapsuleReversed.AnchorB,
 479                        circleCapsuleReversed.AnchorA,
 480                        -circleCapsuleReversed.Normal,
 481                        circleCapsuleReversed.Depth,
 482                        circleCapsuleReversed.DepthIsClamped)
 483                    : default;
 484                return circleCapsule;
 85            case CollisionType2D.Capsule_Convex:
 686                return TryCapsuleConvex((LSCapsuleCollider2D)colliderA, colliderB, out contact);
 87            case CollisionType2D.Convex_Capsule:
 488                bool convexCapsule = TryCapsuleConvex((LSCapsuleCollider2D)colliderB, colliderA, out Contact2D convexCap
 489                contact = convexCapsule
 490                    ? new Contact2D(
 491                        convexCapsuleReversed.AnchorB,
 492                        convexCapsuleReversed.AnchorA,
 493                        -convexCapsuleReversed.Normal,
 494                        convexCapsuleReversed.Depth,
 495                        convexCapsuleReversed.DepthIsClamped)
 496                    : default;
 497                return convexCapsule;
 98            case CollisionType2D.Capsule_Capsule:
 1099                return TryCapsuleCapsule((LSCapsuleCollider2D)colliderA, (LSCapsuleCollider2D)colliderB, out contact);
 100            case CollisionType2D.Compound:
 10101                return TryCompound(colliderA, colliderB, out contact);
 102            default:
 1103                contact = default;
 1104                return false;
 105        }
 106    }
 107
 108    private static bool TryCollide(CollisionWorkItem2D item, ContactManifold2D manifold)
 109    {
 649110        LSCollider2D colliderA = item.ColliderA;
 649111        LSCollider2D colliderB = item.ColliderB;
 649112        if (!BoundsOverlap(colliderA, colliderB))
 17113            return false;
 114
 632115        return item.CollisionType switch
 632116        {
 455117            CollisionType2D.Circle_Circle => TryCircleCircle((LSCircleCollider2D)colliderA, (LSCircleCollider2D)collider
 4118            CollisionType2D.Circle_Convex => TryCircleConvex((LSCircleCollider2D)colliderA, colliderB, manifold),
 89119            CollisionType2D.Convex_Circle => TryCircleConvexReversed((LSCircleCollider2D)colliderB, colliderA, manifold)
 25120            CollisionType2D.Convex_Convex => TryConvexConvex(colliderA, colliderB, manifold),
 11121            CollisionType2D.Capsule_Circle => TryCapsuleCircle((LSCapsuleCollider2D)colliderA, (LSCircleCollider2D)colli
 4122            CollisionType2D.Circle_Capsule => TryCapsuleCircleReversed((LSCapsuleCollider2D)colliderB, (LSCircleCollider
 10123            CollisionType2D.Capsule_Convex => TryCapsuleConvex((LSCapsuleCollider2D)colliderA, colliderB, manifold),
 9124            CollisionType2D.Convex_Capsule => TryCapsuleConvexReversed((LSCapsuleCollider2D)colliderB, colliderA, manifo
 7125            CollisionType2D.Capsule_Capsule => TryCapsuleCapsule((LSCapsuleCollider2D)colliderA, (LSCapsuleCollider2D)co
 17126            CollisionType2D.Compound => TryCompound(colliderA, colliderB, manifold),
 1127            _ => false
 632128        };
 129    }
 130
 131    private static bool TryCircleCircle(LSCircleCollider2D colliderA, LSCircleCollider2D colliderB, out Contact2D contac
 132    {
 513133        Vector2d delta = colliderB.Center - colliderA.Center;
 513134        Fixed64 radius = colliderA.ScaledRadius + colliderB.ScaledRadius;
 513135        Fixed64 distanceSquared = delta.MagnitudeSquared;
 513136        if (distanceSquared > radius * radius)
 137        {
 34138            contact = default;
 34139            return false;
 140        }
 141
 479142        Fixed64 distance = distanceSquared > Fixed64.Zero ? FixedMath.Sqrt(distanceSquared) : Fixed64.Zero;
 479143        Vector2d normal = distance > Fixed64.Zero ? delta / distance : Vector2d.Right;
 479144        Fixed64 depth = radius - distance;
 479145        contact = new Contact2D(
 479146            new ContactAnchor2D(
 479147                colliderA.Center,
 479148                normal * colliderA.ScaledRadius),
 479149            new ContactAnchor2D(
 479150                colliderB.Center,
 479151                -normal * colliderB.ScaledRadius),
 479152            normal,
 479153            depth);
 479154        return true;
 155    }
 156
 157    private static bool TryCircleCircle(
 158        LSCircleCollider2D colliderA,
 159        LSCircleCollider2D colliderB,
 160        ContactManifold2D manifold)
 161    {
 455162        if (!TryCircleCircle(colliderA, colliderB, out Contact2D contact))
 10163            return false;
 164
 445165        AddContact(manifold, contact, colliderA, colliderB);
 445166        return true;
 167    }
 168
 169    private static bool TryCircleConvex(LSCircleCollider2D circle, LSCollider2D convex, out Contact2D contact)
 170    {
 916171        Span<Vector2d> convexOffsets = stackalloc Vector2d[4];
 916172        ReadOnlySpan<Vector2d> convexVertexOffsets =
 916173            GetConvexVertexOffsets(convex, convexOffsets);
 916174        if (!FixedConvex2dRelations.TryGetCircleContact(
 916175                circle.Center,
 916176                circle.Rotation,
 916177                circle.ScaledRadius,
 916178                convex.Center,
 916179                convex.ConvexRotation,
 916180                convexVertexOffsets,
 916181                out FixedPointAnchor2d circleAnchor,
 916182                out FixedPointAnchor2d convexAnchor,
 916183                out Vector2d normal,
 916184                out Fixed64 depth,
 916185                out bool depthIsClamped))
 186        {
 387187            contact = default;
 387188            return false;
 189        }
 190
 529191        contact = new Contact2D(
 529192            new ContactAnchor2D(circleAnchor),
 529193            new ContactAnchor2D(convexAnchor),
 529194            normal,
 529195            depth,
 529196            depthIsClamped);
 529197        return true;
 198    }
 199
 200    private static bool TryCircleConvex(
 201        LSCircleCollider2D circle,
 202        LSCollider2D convex,
 203        ContactManifold2D manifold)
 204    {
 4205        if (!TryCircleConvex(circle, convex, out Contact2D contact))
 1206            return false;
 207
 3208        AddContact(manifold, contact, circle, convex);
 3209        return true;
 210    }
 211
 212    private static bool TryCircleConvexReversed(
 213        LSCircleCollider2D circle,
 214        LSCollider2D convex,
 215        ContactManifold2D manifold)
 216    {
 89217        if (!TryCircleConvex(circle, convex, out Contact2D contact))
 1218            return false;
 219
 88220        manifold.AddContact(
 88221            contact.AnchorB,
 88222            contact.AnchorA,
 88223            contact.Depth,
 88224            -contact.Normal,
 88225            convex.Material,
 88226            circle.Material,
 88227            contact.DepthIsClamped);
 88228        return true;
 229    }
 230
 231    private static bool TryCapsuleCircle(LSCapsuleCollider2D capsule, LSCircleCollider2D circle, out Contact2D contact)
 232    {
 26233        Vector2d fallbackNormal = capsule.GetNormalFromCenteredAxis(circle.Center);
 26234        if (!FixedSegment2d.TryGetCenteredCapsulesContact(
 26235                capsule.Center,
 26236                capsule.Rotation,
 26237                capsule.AxisLength,
 26238                capsule.ScaledRadius,
 26239                circle.Center,
 26240                circle.Rotation,
 26241                Fixed64.Zero,
 26242                circle.ScaledRadius,
 26243                fallbackNormal,
 26244                out FixedContactAnchors2d fixedContact))
 245        {
 4246            contact = default;
 4247            return false;
 248        }
 249
 22250        contact = new Contact2D(
 22251            new ContactAnchor2D(fixedContact.FirstAnchor),
 22252            new ContactAnchor2D(fixedContact.SecondAnchor),
 22253            fixedContact.Normal,
 22254            fixedContact.Depth,
 22255            fixedContact.DepthIsClamped);
 22256        return true;
 257    }
 258
 259    private static bool TryCapsuleCircle(
 260        LSCapsuleCollider2D capsule,
 261        LSCircleCollider2D circle,
 262        ContactManifold2D manifold)
 263    {
 11264        if (!TryCapsuleCircle(capsule, circle, out Contact2D contact))
 1265            return false;
 266
 10267        AddContact(manifold, contact, capsule, circle);
 10268        return true;
 269    }
 270
 271    private static bool TryCapsuleCircleReversed(
 272        LSCapsuleCollider2D capsule,
 273        LSCircleCollider2D circle,
 274        ContactManifold2D manifold)
 275    {
 4276        if (!TryCapsuleCircle(capsule, circle, out Contact2D contact))
 1277            return false;
 278
 3279        manifold.AddContact(
 3280            contact.AnchorB,
 3281            contact.AnchorA,
 3282            contact.Depth,
 3283            -contact.Normal,
 3284            circle.Material,
 3285            capsule.Material,
 3286            contact.DepthIsClamped);
 3287        return true;
 288    }
 289
 290    private static bool TryCapsuleCapsule(LSCapsuleCollider2D colliderA, LSCapsuleCollider2D colliderB, out Contact2D co
 291    {
 17292        Vector2d fallbackNormal = colliderB.AxisLength <= Fixed64.Epsilon
 17293            ? colliderA.GetNormalFromCenteredAxis(colliderB.Center)
 17294            : colliderA.AxisLength <= Fixed64.Epsilon
 17295                ? -colliderB.GetNormalFromCenteredAxis(colliderA.Center)
 17296                : OrientCoincidentCapsuleNormal(colliderB.Center - colliderA.Center);
 17297        if (!FixedSegment2d.TryGetCenteredCapsulesContact(
 17298                colliderA.Center,
 17299                colliderA.Rotation,
 17300                colliderA.AxisLength,
 17301                colliderA.ScaledRadius,
 17302                colliderB.Center,
 17303                colliderB.Rotation,
 17304                colliderB.AxisLength,
 17305                colliderB.ScaledRadius,
 17306                fallbackNormal,
 17307                out FixedContactAnchors2d fixedContact))
 308        {
 2309            contact = default;
 2310            return false;
 311        }
 312
 15313        contact = new Contact2D(
 15314            new ContactAnchor2D(fixedContact.FirstAnchor),
 15315            new ContactAnchor2D(fixedContact.SecondAnchor),
 15316            fixedContact.Normal,
 15317            fixedContact.Depth,
 15318            fixedContact.DepthIsClamped);
 15319        return true;
 320    }
 321
 322    private static bool TryCapsuleCapsule(
 323        LSCapsuleCollider2D colliderA,
 324        LSCapsuleCollider2D colliderB,
 325        ContactManifold2D manifold)
 326    {
 7327        if (!TryCapsuleCapsule(colliderA, colliderB, out Contact2D contact))
 1328            return false;
 329
 6330        AddContact(manifold, contact, colliderA, colliderB);
 6331        return true;
 332    }
 333
 334    private static bool TryCapsuleConvex(LSCapsuleCollider2D capsule, LSCollider2D convex, out Contact2D contact)
 335    {
 10336        Span<FixedPointAnchor2d> capsuleAnchors =
 10337            stackalloc FixedPointAnchor2d[2];
 10338        Span<FixedPointAnchor2d> convexAnchors =
 10339            stackalloc FixedPointAnchor2d[2];
 10340        if (!TryGetCapsuleConvexContacts(
 10341                capsule,
 10342                convex,
 10343                capsuleAnchors,
 10344                convexAnchors,
 10345                out _,
 10346                out Vector2d normal,
 10347                out Fixed64 depth,
 10348                out bool depthIsClamped))
 349        {
 3350            contact = default;
 3351            return false;
 352        }
 353
 7354        contact = new Contact2D(
 7355            new ContactAnchor2D(capsuleAnchors[0]),
 7356            new ContactAnchor2D(convexAnchors[0]),
 7357            normal,
 7358            depth,
 7359            depthIsClamped);
 7360        return true;
 361    }
 362
 363    private static bool TryGetCapsuleConvexContacts(
 364        LSCapsuleCollider2D capsule,
 365        LSCollider2D convex,
 366        Span<FixedPointAnchor2d> capsuleAnchors,
 367        Span<FixedPointAnchor2d> convexAnchors,
 368        out int contactCount,
 369        out Vector2d normal,
 370        out Fixed64 depth,
 371        out bool depthIsClamped)
 372    {
 29373        Span<Vector2d> vertexOffsets = stackalloc Vector2d[4];
 29374        ReadOnlySpan<Vector2d> convexVertexOffsets =
 29375            GetConvexVertexOffsets(convex, vertexOffsets);
 29376        return FixedSegment2d.TryGetCenteredCapsuleConvexContacts(
 29377            capsule.Center,
 29378            capsule.Rotation,
 29379            Vector2d.Forward,
 29380            capsule.AxisLength,
 29381            capsule.ScaledRadius,
 29382            convex.Center,
 29383            convex.ConvexRotation,
 29384            convexVertexOffsets,
 29385            capsuleAnchors,
 29386            convexAnchors,
 29387            out contactCount,
 29388            out normal,
 29389            out depth,
 29390            out depthIsClamped);
 391    }
 392
 393    private static ReadOnlySpan<Vector2d> GetConvexVertexOffsets(
 394        LSCollider2D convex,
 395        Span<Vector2d> scratch)
 396    {
 1101397        if (convex is LSPolygonCollider2D polygon)
 899398            return polygon.ScaledLocalVertices;
 399
 202400        int vertexCount = convex.VertexCount;
 2020401        for (int i = 0; i < vertexCount; i++)
 808402            scratch[i] = convex.GetScaledLocalVertexUnchecked(i);
 202403        return scratch.Slice(0, vertexCount);
 404    }
 405
 406    private static bool TryCapsuleConvex(
 407        LSCapsuleCollider2D capsule,
 408        LSCollider2D convex,
 409        ContactManifold2D manifold)
 410    {
 10411        Span<FixedPointAnchor2d> capsuleAnchors =
 10412            stackalloc FixedPointAnchor2d[2];
 10413        Span<FixedPointAnchor2d> convexAnchors =
 10414            stackalloc FixedPointAnchor2d[2];
 10415        if (!TryGetCapsuleConvexContacts(
 10416                capsule,
 10417                convex,
 10418                capsuleAnchors,
 10419                convexAnchors,
 10420                out int contactCount,
 10421                out Vector2d normal,
 10422                out Fixed64 depth,
 10423                out bool depthIsClamped))
 424        {
 1425            return false;
 426        }
 427
 48428        for (int i = 0; i < contactCount; i++)
 429        {
 15430            manifold.AddContact(
 15431                new ContactAnchor2D(capsuleAnchors[i]),
 15432                new ContactAnchor2D(convexAnchors[i]),
 15433                depth,
 15434                normal,
 15435                capsule.Material,
 15436                convex.Material,
 15437                depthIsClamped);
 438        }
 9439        return true;
 440    }
 441
 442    private static bool TryCapsuleConvexReversed(
 443        LSCapsuleCollider2D capsule,
 444        LSCollider2D convex,
 445        ContactManifold2D manifold)
 446    {
 9447        Span<FixedPointAnchor2d> capsuleAnchors =
 9448            stackalloc FixedPointAnchor2d[2];
 9449        Span<FixedPointAnchor2d> convexAnchors =
 9450            stackalloc FixedPointAnchor2d[2];
 9451        if (!TryGetCapsuleConvexContacts(
 9452                capsule,
 9453                convex,
 9454                capsuleAnchors,
 9455                convexAnchors,
 9456                out int contactCount,
 9457                out Vector2d normal,
 9458                out Fixed64 depth,
 9459                out bool depthIsClamped))
 460        {
 1461            return false;
 462        }
 463
 42464        for (int i = 0; i < contactCount; i++)
 465        {
 13466            manifold.AddContact(
 13467                new ContactAnchor2D(convexAnchors[i]),
 13468                new ContactAnchor2D(capsuleAnchors[i]),
 13469                depth,
 13470                -normal,
 13471                convex.Material,
 13472                capsule.Material,
 13473                depthIsClamped);
 474        }
 8475        return true;
 476    }
 477
 478    private static bool TryConvexConvex(LSCollider2D colliderA, LSCollider2D colliderB, out Contact2D contact)
 479    {
 53480        Span<Vector2d> firstVertexScratch = stackalloc Vector2d[4];
 53481        Span<Vector2d> secondVertexScratch = stackalloc Vector2d[4];
 53482        ReadOnlySpan<Vector2d> firstVertexOffsets =
 53483            GetConvexVertexOffsets(colliderA, firstVertexScratch);
 53484        ReadOnlySpan<Vector2d> secondVertexOffsets =
 53485            GetConvexVertexOffsets(colliderB, secondVertexScratch);
 53486        Span<FixedPointAnchor2d> firstContactAnchors =
 53487            stackalloc FixedPointAnchor2d[2];
 53488        Span<FixedPointAnchor2d> secondContactAnchors =
 53489            stackalloc FixedPointAnchor2d[2];
 53490        if (!FixedConvex2dRelations.TryGetConvexContacts(
 53491                colliderA.Center,
 53492                colliderA.ConvexRotation,
 53493                firstVertexOffsets,
 53494                colliderB.Center,
 53495                colliderB.ConvexRotation,
 53496                secondVertexOffsets,
 53497                firstContactAnchors,
 53498                secondContactAnchors,
 53499                out _,
 53500                out Vector2d normal,
 53501                out Fixed64 depth,
 53502                out bool depthIsClamped))
 503        {
 3504            contact = default;
 3505            return false;
 506        }
 507
 50508        contact = new Contact2D(
 50509            new ContactAnchor2D(colliderA.GetConvexSupportAnchor(normal)),
 50510            new ContactAnchor2D(colliderB.GetConvexSupportAnchor(-normal)),
 50511            normal,
 50512            depth,
 50513            depthIsClamped);
 50514        return true;
 515    }
 516
 517    private static bool TryConvexConvex(
 518        LSCollider2D colliderA,
 519        LSCollider2D colliderB,
 520        ContactManifold2D manifold)
 521    {
 25522        Span<Vector2d> firstVertexScratch = stackalloc Vector2d[4];
 25523        Span<Vector2d> secondVertexScratch = stackalloc Vector2d[4];
 25524        ReadOnlySpan<Vector2d> firstVertexOffsets =
 25525            GetConvexVertexOffsets(colliderA, firstVertexScratch);
 25526        ReadOnlySpan<Vector2d> secondVertexOffsets =
 25527            GetConvexVertexOffsets(colliderB, secondVertexScratch);
 25528        Span<FixedPointAnchor2d> firstContactAnchors =
 25529            stackalloc FixedPointAnchor2d[2];
 25530        Span<FixedPointAnchor2d> secondContactAnchors =
 25531            stackalloc FixedPointAnchor2d[2];
 25532        if (!FixedConvex2dRelations.TryGetConvexContacts(
 25533                colliderA.Center,
 25534                colliderA.ConvexRotation,
 25535                firstVertexOffsets,
 25536                colliderB.Center,
 25537                colliderB.ConvexRotation,
 25538                secondVertexOffsets,
 25539                firstContactAnchors,
 25540                secondContactAnchors,
 25541                out int contactCount,
 25542                out Vector2d normal,
 25543                out Fixed64 depth,
 25544                out bool depthIsClamped))
 545        {
 1546            return false;
 547        }
 548
 136549        for (int i = 0; i < contactCount; i++)
 550        {
 44551            manifold.AddContact(
 44552                new ContactAnchor2D(firstContactAnchors[i]),
 44553                new ContactAnchor2D(secondContactAnchors[i]),
 44554                depth,
 44555                normal,
 44556                colliderA.Material,
 44557                colliderB.Material,
 44558                depthIsClamped);
 559        }
 560
 24561        return true;
 562    }
 563
 564    private static bool TryCompound(LSCollider2D colliderA, LSCollider2D colliderB, out Contact2D contact)
 565    {
 10566        if (colliderA is LSCompoundCollider2D compoundA)
 567        {
 6568            if (colliderB is LSCompoundCollider2D compoundB)
 3569                return TryCompoundCompound(compoundA, compoundB, out contact);
 570
 3571            return TryCompoundOther(compoundA, colliderB, compoundIsA: true, out contact);
 572        }
 573
 4574        if (colliderB is LSCompoundCollider2D compound)
 3575            return TryCompoundOther(compound, colliderA, compoundIsA: false, out contact);
 576
 1577        contact = default;
 1578        return false;
 579    }
 580
 581    private static bool TryCompoundCompound(
 582        LSCompoundCollider2D compoundA,
 583        LSCompoundCollider2D compoundB,
 584        out Contact2D contact)
 585    {
 3586        bool found = false;
 3587        Contact2D best = default;
 588
 16589        for (int i = 0; i < compoundA.PartCount; i++)
 590        {
 5591            LSCollider2D partA = compoundA.GetPartCollider(i);
 26592            for (int j = 0; j < compoundB.PartCount; j++)
 593            {
 8594                LSCollider2D partB = compoundB.GetPartCollider(j);
 8595                if (!TryCollide(partA, partB, out Contact2D candidate))
 596                    continue;
 597
 3598                if (ContactSelectionPolicy.ShouldReplaceWithDeeper(candidate, found, best))
 599                {
 2600                    best = candidate;
 2601                    found = true;
 602                }
 603            }
 604        }
 605
 3606        if (!found)
 607        {
 1608            contact = default;
 1609            return false;
 610        }
 611
 2612        contact = best;
 2613        return true;
 614    }
 615
 616    private static bool TryCompoundOther(
 617        LSCompoundCollider2D compound,
 618        LSCollider2D other,
 619        bool compoundIsA,
 620        out Contact2D contact)
 621    {
 6622        bool found = false;
 6623        Contact2D best = default;
 624
 32625        for (int i = 0; i < compound.PartCount; i++)
 626        {
 10627            LSCollider2D part = compound.GetPartCollider(i);
 628            Contact2D candidate;
 10629            bool collided = compoundIsA
 10630                ? TryCollide(part, other, out candidate)
 10631                : TryCollide(other, part, out candidate);
 632
 10633            if (!collided)
 634                continue;
 635
 5636            if (ContactSelectionPolicy.ShouldReplaceWithDeeper(candidate, found, best))
 637            {
 4638                best = candidate;
 4639                found = true;
 640            }
 641        }
 642
 6643        if (!found)
 644        {
 2645            contact = default;
 2646            return false;
 647        }
 648
 4649        contact = best;
 4650        return true;
 651    }
 652
 653    private static bool TryCompound(
 654        LSCollider2D colliderA,
 655        LSCollider2D colliderB,
 656        ContactManifold2D manifold)
 657    {
 17658        if (colliderA is LSCompoundCollider2D compoundA)
 659        {
 14660            if (colliderB is LSCompoundCollider2D compoundB)
 4661                return TryCompoundCompound(compoundA, compoundB, manifold);
 662
 10663            return TryCompoundOther(compoundA, colliderB, compoundIsA: true, manifold);
 664        }
 665
 3666        if (colliderB is LSCompoundCollider2D compound)
 2667            return TryCompoundOther(compound, colliderA, compoundIsA: false, manifold);
 668
 1669        return false;
 670    }
 671
 672    private static bool TryCompoundCompound(
 673        LSCompoundCollider2D compoundA,
 674        LSCompoundCollider2D compoundB,
 675        ContactManifold2D manifold)
 676    {
 4677        bool found = false;
 4678        ContactManifold2D scratch = compoundA.PartManifoldScratch;
 22679        for (int i = 0; i < compoundA.PartCount; i++)
 680        {
 7681            LSCollider2D partA = compoundA.GetPartCollider(i);
 32682            for (int j = 0; j < compoundB.PartCount; j++)
 683            {
 9684                LSCollider2D partB = compoundB.GetPartCollider(j);
 9685                CollisionType2D collisionType = ColliderSettings2D.GetCollisionType(partA.Shape, partB.Shape);
 9686                scratch.BeginUpdate(manifold.LastUpdatedFrame);
 9687                if (!TryCollide(new CollisionWorkItem2D(partA, partB, collisionType), scratch))
 688                    continue;
 689
 2690                found = true;
 2691                AddCompoundPartContacts(
 2692                    manifold,
 2693                    scratch,
 2694                    featureNamespaceA: i + 1,
 2695                    featureNamespaceB: -(j + 1));
 696            }
 697        }
 698
 4699        return found;
 700    }
 701
 702    private static bool TryCompoundOther(
 703        LSCompoundCollider2D compound,
 704        LSCollider2D other,
 705        bool compoundIsA,
 706        ContactManifold2D manifold)
 707    {
 12708        bool found = false;
 12709        ContactManifold2D scratch = compound.PartManifoldScratch;
 62710        for (int i = 0; i < compound.PartCount; i++)
 711        {
 19712            LSCollider2D part = compound.GetPartCollider(i);
 19713            LSCollider2D colliderA = compoundIsA ? part : other;
 19714            LSCollider2D colliderB = compoundIsA ? other : part;
 19715            CollisionType2D collisionType = ColliderSettings2D.GetCollisionType(colliderA.Shape, colliderB.Shape);
 19716            scratch.BeginUpdate(manifold.LastUpdatedFrame);
 19717            if (!TryCollide(new CollisionWorkItem2D(colliderA, colliderB, collisionType), scratch))
 718                continue;
 719
 16720            found = true;
 16721            AddCompoundPartContacts(
 16722                manifold,
 16723                scratch,
 16724                featureNamespaceA: compoundIsA ? i + 1 : 0,
 16725                featureNamespaceB: compoundIsA ? 0 : -(i + 1));
 726        }
 727
 12728        return found;
 729    }
 730
 731    private static void AddCompoundPartContacts(
 732        ContactManifold2D destination,
 733        ContactManifold2D source,
 734        int featureNamespaceA,
 735        int featureNamespaceB)
 736    {
 76737        for (int i = 0; i < source.Count; i++)
 738        {
 20739            ManifoldContact2D contact = source[i];
 20740            destination.AddContact(
 20741                contact.AnchorA,
 20742                contact.AnchorB,
 20743                contact.Depth,
 20744                contact.Normal,
 20745                contact.MaterialA,
 20746                contact.MaterialB,
 20747                contact.DepthIsClamped,
 20748                featureNamespaceA,
 20749                featureNamespaceB);
 750        }
 18751    }
 752
 753    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 754    private static void AddContact(
 755        ContactManifold2D manifold,
 756        Contact2D contact,
 757        LSCollider2D colliderA,
 758        LSCollider2D colliderB) =>
 464759        manifold.AddContact(
 464760            contact.AnchorA,
 464761            contact.AnchorB,
 464762            contact.Depth,
 464763            contact.Normal,
 464764            colliderA.Material,
 464765            colliderB.Material,
 464766            contact.DepthIsClamped);
 767
 768    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 769    internal static bool BoundsOverlap(LSCollider2D colliderA, LSCollider2D colliderB) =>
 10356770        colliderA.MinX <= colliderB.MaxX
 10356771        && colliderA.MaxX >= colliderB.MinX
 10356772        && colliderA.MinY <= colliderB.MaxY
 10356773        && colliderA.MaxY >= colliderB.MinY;
 774
 775    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 776    private static Vector2d OrientCoincidentCapsuleNormal(Vector2d direction) =>
 9777        direction.MagnitudeSquared > Fixed64.Epsilon && direction.X < Fixed64.Zero
 9778            ? -Vector2d.Right
 9779            : Vector2d.Right;
 780
 781}

Methods/Properties

TryCollide(Gravitas.Colliders.LSCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.Contact2D&)
TryCollide(Gravitas.CollisionPair2D,Gravitas.CollisionHandling.ContactManifold2D,System.Int32)
TryCollide(Gravitas.CollisionHandling.CollisionWorkItem2D,Gravitas.CollisionHandling.ContactManifold2D,System.Int32)
TryCollide(Gravitas.CollisionHandling.CollisionWorkItem2D,Gravitas.CollisionHandling.Contact2D&)
TryCollide(Gravitas.CollisionHandling.CollisionWorkItem2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCircleCircle(Gravitas.Colliders.LSCircleCollider2D,Gravitas.Colliders.LSCircleCollider2D,Gravitas.CollisionHandling.Contact2D&)
TryCircleCircle(Gravitas.Colliders.LSCircleCollider2D,Gravitas.Colliders.LSCircleCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCircleConvex(Gravitas.Colliders.LSCircleCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.Contact2D&)
TryCircleConvex(Gravitas.Colliders.LSCircleCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCircleConvexReversed(Gravitas.Colliders.LSCircleCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCapsuleCircle(Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Colliders.LSCircleCollider2D,Gravitas.CollisionHandling.Contact2D&)
TryCapsuleCircle(Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Colliders.LSCircleCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCapsuleCircleReversed(Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Colliders.LSCircleCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCapsuleCapsule(Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.CollisionHandling.Contact2D&)
TryCapsuleCapsule(Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCapsuleConvex(Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.Contact2D&)
TryGetCapsuleConvexContacts(Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Colliders.LSCollider2D,System.Span`1<FixedMathSharp.Geometry.FixedPointAnchor2d>,System.Span`1<FixedMathSharp.Geometry.FixedPointAnchor2d>,System.Int32&,FixedMathSharp.Vector2d&,FixedMathSharp.Fixed64&,System.Boolean&)
GetConvexVertexOffsets(Gravitas.Colliders.LSCollider2D,System.Span`1<FixedMathSharp.Vector2d>)
TryCapsuleConvex(Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCapsuleConvexReversed(Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryConvexConvex(Gravitas.Colliders.LSCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.Contact2D&)
TryConvexConvex(Gravitas.Colliders.LSCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCompound(Gravitas.Colliders.LSCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.Contact2D&)
TryCompoundCompound(Gravitas.Colliders.LSCompoundCollider2D,Gravitas.Colliders.LSCompoundCollider2D,Gravitas.CollisionHandling.Contact2D&)
TryCompoundOther(Gravitas.Colliders.LSCompoundCollider2D,Gravitas.Colliders.LSCollider2D,System.Boolean,Gravitas.CollisionHandling.Contact2D&)
TryCompound(Gravitas.Colliders.LSCollider2D,Gravitas.Colliders.LSCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCompoundCompound(Gravitas.Colliders.LSCompoundCollider2D,Gravitas.Colliders.LSCompoundCollider2D,Gravitas.CollisionHandling.ContactManifold2D)
TryCompoundOther(Gravitas.Colliders.LSCompoundCollider2D,Gravitas.Colliders.LSCollider2D,System.Boolean,Gravitas.CollisionHandling.ContactManifold2D)
AddCompoundPartContacts(Gravitas.CollisionHandling.ContactManifold2D,Gravitas.CollisionHandling.ContactManifold2D,System.Int32,System.Int32)
AddContact(Gravitas.CollisionHandling.ContactManifold2D,Gravitas.CollisionHandling.Contact2D,Gravitas.Colliders.LSCollider2D,Gravitas.Colliders.LSCollider2D)
BoundsOverlap(Gravitas.Colliders.LSCollider2D,Gravitas.Colliders.LSCollider2D)
OrientCoincidentCapsuleNormal(FixedMathSharp.Vector2d)