< Summary

Information
Class: Gravitas.Colliders.ColliderShapeDefinition2D
Assembly: Gravitas
File(s): /home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/Definitions/ColliderShapeDefinition2D.cs
Line coverage
100%
Covered lines: 105
Uncovered lines: 0
Coverable lines: 105
Total lines: 279
Line coverage: 100%
Branch coverage
100%
Covered branches: 39
Total branches: 39
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%22100%
get_Material()100%22100%
get_HasMaterial()100%11100%
get_PolygonVertexCount()100%22100%
Circle(...)100%11100%
Capsule(...)100%11100%
AABBox(...)100%11100%
ConvexPolygon(...)100%11100%
ConvexPolygon(...)100%11100%
Triangle(...)100%11100%
GetPolygonVertex(...)100%11100%
CreateCollider()100%11100%
CreateRuntimeCollider()100%55100%
GetPolygonVerticesForRuntime()100%11100%
EnsureDefined()100%11100%
EnsureKind(...)100%22100%
EnsurePolygonDefinition()100%11100%
ValidateRadius(...)100%11100%
ValidateSize(...)100%22100%
ValidateCapsule(...)100%11100%
Equals(...)100%1818100%
Equals(...)100%22100%
GetHashCode()100%44100%
op_Equality(...)100%11100%
op_Inequality(...)100%11100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Colliders/Definitions/ColliderShapeDefinition2D.cs

#LineLine coverage
 1//=======================================================================
 2// ColliderShapeDefinition2D.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 Gravitas.Materials;
 10using System;
 11using System.Runtime.CompilerServices;
 12
 13namespace Gravitas.Colliders;
 14
 15/// <summary>
 16/// Describes authoritative pure 2D collider shape input without runtime
 17/// collider lifecycle state such as IDs, bodies, partitions, pairs, or events.
 18/// </summary>
 19public readonly struct ColliderShapeDefinition2D : IEquatable<ColliderShapeDefinition2D>
 20{
 21    private readonly Vector2d[]? _polygonVertices;
 22    private readonly PhysicsMaterial _material;
 23    private readonly bool _hasMaterial;
 24
 25    private ColliderShapeDefinition2D(
 26        ColliderShapeDefinition2DKind kind,
 27        Fixed64 radius,
 28        Vector2d size,
 29        Vector2d[]? polygonVertices,
 30        PhysicsMaterial? material)
 31    {
 29432        Kind = kind;
 29433        Radius = radius;
 29434        Size = size;
 29435        _polygonVertices = polygonVertices;
 29436        _material = material ?? PhysicsMaterial.Default;
 29437        _hasMaterial = material.HasValue;
 29438    }
 39
 40    /// <summary>
 41    /// Gets the shape family represented by this definition.
 42    /// </summary>
 43    public ColliderShapeDefinition2DKind Kind { get; }
 44
 45    /// <summary>
 46    /// Gets the unscaled radius used by circle definitions.
 47    /// </summary>
 48    public Fixed64 Radius { get; }
 49
 50    /// <summary>
 51    /// Gets the unscaled size used by sized definitions.
 52    /// </summary>
 53    public Vector2d Size { get; }
 54
 55    /// <summary>
 56    /// Gets the authored surface material used when this definition creates a
 57    /// runtime 2D collider directly.
 58    /// </summary>
 29059    public PhysicsMaterial Material => _hasMaterial ? _material : PhysicsMaterial.Default;
 60
 37461    internal bool HasMaterial => _hasMaterial;
 62
 63    /// <summary>
 64    /// Gets the number of local polygon vertices held by this definition.
 65    /// </summary>
 66    public int PolygonVertexCount
 67    {
 68        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 16569        get => _polygonVertices?.Length ?? 0;
 70    }
 71
 72    /// <summary>
 73    /// Creates a circle shape definition.
 74    /// </summary>
 75    public static ColliderShapeDefinition2D Circle(Fixed64 radius, PhysicsMaterial? material = null)
 76    {
 17677        ValidateRadius(radius);
 17678        Fixed64 diameter = radius * (Fixed64)2;
 17679        return new(
 17680            ColliderShapeDefinition2DKind.Circle,
 17681            radius,
 17682            new Vector2d(diameter, diameter),
 17683            null,
 17684            material);
 85    }
 86
 87    /// <summary>
 88    /// Creates a vertical local-axis capsule shape definition.
 89    /// </summary>
 90    public static ColliderShapeDefinition2D Capsule(Fixed64 radius, Fixed64 height, PhysicsMaterial? material = null)
 91    {
 3892        ValidateCapsule(radius, height);
 3593        return new(
 3594            ColliderShapeDefinition2DKind.Capsule,
 3595            radius,
 3596            new Vector2d(radius * (Fixed64)2, height),
 3597            null,
 3598            material);
 99    }
 100
 101    /// <summary>
 102    /// Creates an axis-aligned box shape definition.
 103    /// </summary>
 104    public static ColliderShapeDefinition2D AABBox(Vector2d size, PhysicsMaterial? material = null)
 105    {
 50106        ValidateSize(size);
 48107        return new(ColliderShapeDefinition2DKind.AABBox, Fixed64.Zero, size, null, material);
 108    }
 109
 110    /// <summary>
 111    /// Creates a convex polygon shape definition.
 112    /// </summary>
 113    public static ColliderShapeDefinition2D ConvexPolygon(params Vector2d[] vertices) =>
 28114        ConvexPolygon(null, vertices);
 115
 116    /// <summary>
 117    /// Creates a convex polygon shape definition.
 118    /// </summary>
 119    public static ColliderShapeDefinition2D ConvexPolygon(PhysicsMaterial? material, params Vector2d[] vertices)
 120    {
 36121        SwiftThrowHelper.ThrowIfNull(vertices, nameof(vertices));
 36122        LSPolygonCollider2D.ValidateConvexPolygon(vertices);
 123
 35124        var vertexSnapshot = new Vector2d[vertices.Length];
 35125        Array.Copy(vertices, vertexSnapshot, vertices.Length);
 35126        return new(
 35127            ColliderShapeDefinition2DKind.ConvexPolygon,
 35128            Fixed64.Zero,
 35129            Vector2d.Zero,
 35130            vertexSnapshot,
 35131            material);
 132    }
 133
 134    /// <summary>
 135    /// Creates a triangle authoring definition backed by the convex-polygon runtime shape.
 136    /// </summary>
 137    public static ColliderShapeDefinition2D Triangle(Vector2d a, Vector2d b, Vector2d c, PhysicsMaterial? material = nul
 4138        ConvexPolygon(material, a, b, c);
 139
 140    /// <summary>
 141    /// Gets a local polygon vertex by stable source order.
 142    /// </summary>
 143    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 144    public Vector2d GetPolygonVertex(int index)
 145    {
 33146        EnsurePolygonDefinition();
 31147        SwiftThrowHelper.ThrowIfArrayIndexInvalid(index, _polygonVertices!.Length, nameof(index));
 31148        return _polygonVertices[index];
 149    }
 150
 151    /// <summary>
 152    /// Creates a new unbound runtime 2D collider from this shape definition.
 153    /// </summary>
 154    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 12155    public LSCollider2D CreateCollider() => CreateRuntimeCollider();
 156
 157    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 158    internal LSCollider2D CreateRuntimeCollider()
 159    {
 259160        return Kind switch
 259161        {
 167162            ColliderShapeDefinition2DKind.Circle => new LSCircleCollider2D(this),
 40163            ColliderShapeDefinition2DKind.AABBox => new LSAABBoxCollider2D(this),
 25164            ColliderShapeDefinition2DKind.ConvexPolygon => new LSPolygonCollider2D(this),
 26165            ColliderShapeDefinition2DKind.Capsule => new LSCapsuleCollider2D(this),
 1166            _ => throw new ArgumentException(
 1167                "2D collider shape definition cannot be default.",
 1168                nameof(ColliderShapeDefinition2D))
 259169        };
 170    }
 171
 172    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 173    internal Vector2d[] GetPolygonVerticesForRuntime()
 174    {
 25175        EnsurePolygonDefinition();
 25176        return _polygonVertices!;
 177    }
 178
 179    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 180    internal void EnsureDefined()
 181    {
 576182        SwiftThrowHelper.ThrowIfArgument(
 576183            Kind == ColliderShapeDefinition2DKind.Undefined,
 576184            nameof(ColliderShapeDefinition2D),
 576185            "2D collider shape definition cannot be default.");
 575186    }
 187
 188    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 189    internal void EnsureKind(ColliderShapeDefinition2DKind expectedKind)
 190    {
 318191        EnsureDefined();
 317192        SwiftThrowHelper.ThrowIfArgument(
 317193            Kind != expectedKind,
 317194            nameof(ColliderShapeDefinition2D),
 317195            $"2D collider shape definition must be {expectedKind}.");
 315196    }
 197
 198    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 199    private void EnsurePolygonDefinition() =>
 58200        EnsureKind(ColliderShapeDefinition2DKind.ConvexPolygon);
 201
 202    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 203    private static void ValidateRadius(Fixed64 radius) =>
 214204        SwiftThrowHelper.ThrowIfArgument(
 214205            radius <= Fixed64.Zero,
 214206            nameof(radius),
 214207            "2D collider radius must be greater than zero.");
 208
 209    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 210    private static void ValidateSize(Vector2d size) =>
 50211        SwiftThrowHelper.ThrowIfArgument(
 50212            size.X <= Fixed64.Zero || size.Y <= Fixed64.Zero,
 50213            nameof(size),
 50214            "2D collider size components must be greater than zero.");
 215
 216    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 217    private static void ValidateCapsule(Fixed64 radius, Fixed64 height)
 218    {
 38219        ValidateRadius(radius);
 36220        SwiftThrowHelper.ThrowIfArgument(
 36221            height < radius * (Fixed64)2,
 36222            nameof(height),
 36223            "2D capsule height must be at least the capsule diameter.");
 35224    }
 225
 226    /// <inheritdoc/>
 227    public bool Equals(ColliderShapeDefinition2D other)
 228    {
 16229        if (Kind != other.Kind
 16230            || Radius != other.Radius
 16231            || Size != other.Size
 16232            || _hasMaterial != other._hasMaterial
 16233            || (_hasMaterial && _material != other._material)
 16234            || PolygonVertexCount != other.PolygonVertexCount)
 235        {
 9236            return false;
 237        }
 238
 46239        for (int i = 0; i < PolygonVertexCount; i++)
 240        {
 17241            if (_polygonVertices![i] != other._polygonVertices![i])
 1242                return false;
 243        }
 244
 6245        return true;
 246    }
 247
 248    /// <inheritdoc/>
 249    public override bool Equals(object? obj) =>
 16250        obj is ColliderShapeDefinition2D other && Equals(other);
 251
 252    /// <inheritdoc/>
 253    public override int GetHashCode()
 254    {
 255        unchecked
 256        {
 6257            int hash = 17;
 6258            hash = hash * 31 + Kind.GetHashCode();
 6259            hash = hash * 31 + Radius.GetHashCode();
 6260            hash = hash * 31 + Size.GetHashCode();
 6261            hash = hash * 31 + _hasMaterial.GetHashCode();
 6262            if (_hasMaterial)
 2263                hash = hash * 31 + _material.GetHashCode();
 264
 28265            for (int i = 0; i < PolygonVertexCount; i++)
 8266                hash = hash * 31 + _polygonVertices![i].GetHashCode();
 267
 6268            return hash;
 269        }
 270    }
 271
 272    /// <summary>Determines whether two authored 2D shape definitions are equal.</summary>
 273    public static bool operator ==(ColliderShapeDefinition2D left, ColliderShapeDefinition2D right) =>
 1274        left.Equals(right);
 275
 276    /// <summary>Determines whether two authored 2D shape definitions are not equal.</summary>
 277    public static bool operator !=(ColliderShapeDefinition2D left, ColliderShapeDefinition2D right) =>
 1278        !left.Equals(right);
 279}