perf: Drastically Improved Memory Usage
TIL, records are not value types and are actually just reference types. So I was pretty much allocating from heap every time I used any of my data types (Like Vector2D). Needless to say, they are all now readonly structs as I originally intended them to be.
This commit is contained in:
parent
c32add40ff
commit
b14d10db0c
|
@ -2,8 +2,8 @@ using System;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
public record EngineTime
|
public readonly struct EngineTime(TimeSpan Total, TimeSpan Elapsed)
|
||||||
(
|
{
|
||||||
TimeSpan Total,
|
public readonly TimeSpan Total { get; init; } = Total;
|
||||||
TimeSpan Elapsed
|
public readonly TimeSpan Elapsed { get; init; } = Elapsed;
|
||||||
);
|
}
|
||||||
|
|
|
@ -3,11 +3,14 @@ using System;
|
||||||
namespace Syntriax.Engine.Core;
|
namespace Syntriax.Engine.Core;
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized}")]
|
[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized}")]
|
||||||
public record Vector2D(float X, float Y)
|
public readonly struct Vector2D(float X, float Y)
|
||||||
{
|
{
|
||||||
public float Magnitude => Length(this);
|
public readonly float X { get; init; } = X;
|
||||||
public float MagnitudeSquared => LengthSquared(this);
|
public readonly float Y { get; init; } = Y;
|
||||||
public Vector2D Normalized => Normalize(this);
|
|
||||||
|
public readonly float Magnitude => Length(this);
|
||||||
|
public readonly float MagnitudeSquared => LengthSquared(this);
|
||||||
|
public readonly Vector2D Normalized => Normalize(this);
|
||||||
|
|
||||||
public readonly static Vector2D Up = new(0f, 1f);
|
public readonly static Vector2D Up = new(0f, 1f);
|
||||||
public readonly static Vector2D Down = new(0f, -1f);
|
public readonly static Vector2D Down = new(0f, -1f);
|
||||||
|
@ -22,6 +25,8 @@ public record Vector2D(float X, float Y)
|
||||||
public static Vector2D operator *(Vector2D vector, float value) => new(vector.X * value, vector.Y * value);
|
public static Vector2D operator *(Vector2D vector, float value) => new(vector.X * value, vector.Y * value);
|
||||||
public static Vector2D operator *(float value, Vector2D vector) => new(vector.X * value, vector.Y * value);
|
public static Vector2D operator *(float value, Vector2D vector) => new(vector.X * value, vector.Y * value);
|
||||||
public static Vector2D operator /(Vector2D vector, float value) => new(vector.X / value, vector.Y / value);
|
public static Vector2D operator /(Vector2D vector, float value) => new(vector.X / value, vector.Y / value);
|
||||||
|
public static bool operator ==(Vector2D left, Vector2D right) => left.X == right.X && left.Y == right.Y;
|
||||||
|
public static bool operator !=(Vector2D left, Vector2D right) => left.X != right.X || left.Y != right.Y;
|
||||||
|
|
||||||
public static float Length(Vector2D vector) => MathF.Sqrt(LengthSquared(vector));
|
public static float Length(Vector2D vector) => MathF.Sqrt(LengthSquared(vector));
|
||||||
public static float LengthSquared(Vector2D vector) => vector.X * vector.X + vector.Y * vector.Y;
|
public static float LengthSquared(Vector2D vector) => vector.X * vector.X + vector.Y * vector.Y;
|
||||||
|
@ -72,4 +77,7 @@ public record Vector2D(float X, float Y)
|
||||||
=> left.X.ApproximatelyEquals(right.X, epsilon) && left.Y.ApproximatelyEquals(right.Y, epsilon);
|
=> left.X.ApproximatelyEquals(right.X, epsilon) && left.Y.ApproximatelyEquals(right.Y, epsilon);
|
||||||
|
|
||||||
public override string ToString() => $"{nameof(Vector2D)}({X}, {Y})";
|
public override string ToString() => $"{nameof(Vector2D)}({X}, {Y})";
|
||||||
|
|
||||||
|
public override bool Equals(object? obj) => obj is Vector2D objVec && X.Equals(objVec.X) && Y.Equals(objVec.Y);
|
||||||
|
public override int GetHashCode() => HashCode.Combine(X, Y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,16 @@ using Syntriax.Engine.Physics2D.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
namespace Syntriax.Engine.Physics2D;
|
||||||
|
|
||||||
public record CollisionDetectionInformation
|
public readonly struct CollisionDetectionInformation
|
||||||
(
|
(
|
||||||
ICollider2D Left,
|
ICollider2D Left,
|
||||||
ICollider2D Right,
|
ICollider2D Right,
|
||||||
Vector2D Normal,
|
Vector2D Normal,
|
||||||
float Penetration
|
float Penetration
|
||||||
);
|
)
|
||||||
|
{
|
||||||
|
public ICollider2D Left { get; init; } = Left;
|
||||||
|
public ICollider2D Right { get; init; } = Right;
|
||||||
|
public Vector2D Normal { get; init; } = Normal;
|
||||||
|
public float Penetration { get; init; } = Penetration;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Core;
|
using Syntriax.Engine.Core;
|
||||||
using Syntriax.Engine.Physics2D.Abstract;
|
using Syntriax.Engine.Physics2D.Abstract;
|
||||||
using Syntriax.Engine.Physics2D.Primitives;
|
using Syntriax.Engine.Physics2D.Primitives;
|
||||||
|
@ -8,7 +6,7 @@ namespace Syntriax.Engine.Physics2D;
|
||||||
|
|
||||||
public class CollisionDetector : ICollisionDetector
|
public class CollisionDetector : ICollisionDetector
|
||||||
{
|
{
|
||||||
public bool TryDetect<T1, T2>(T1 left, T2 right, [NotNullWhen(true)] out CollisionDetectionInformation? collisionInformation)
|
public bool TryDetect<T1, T2>(T1 left, T2 right, out CollisionDetectionInformation collisionInformation)
|
||||||
where T1 : ICollider2D
|
where T1 : ICollider2D
|
||||||
where T2 : ICollider2D
|
where T2 : ICollider2D
|
||||||
{
|
{
|
||||||
|
@ -31,18 +29,18 @@ public class CollisionDetector : ICollisionDetector
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DetectCircleShape(ICircleCollider2D circleCollider, IShapeCollider2D shapeCollider, out CollisionDetectionInformation? collisionInformation)
|
private static bool DetectCircleShape(ICircleCollider2D circleCollider, IShapeCollider2D shapeCollider, out CollisionDetectionInformation collisionInformation)
|
||||||
{
|
{
|
||||||
return DetectShapeCircle(shapeCollider, circleCollider, out collisionInformation);
|
return DetectShapeCircle(shapeCollider, circleCollider, out collisionInformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DetectShapeShape(IShapeCollider2D left, IShapeCollider2D right, out CollisionDetectionInformation? collisionInformation)
|
private static bool DetectShapeShape(IShapeCollider2D left, IShapeCollider2D right, out CollisionDetectionInformation collisionInformation)
|
||||||
{
|
{
|
||||||
collisionInformation = default;
|
collisionInformation = default;
|
||||||
return DetectShapeShapeOneWay(left, right, ref collisionInformation) && DetectShapeShapeOneWay(right, left, ref collisionInformation);
|
return DetectShapeShapeOneWay(left, right, ref collisionInformation) && DetectShapeShapeOneWay(right, left, ref collisionInformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DetectShapeShapeOneWay(IShapeCollider2D left, IShapeCollider2D right, ref CollisionDetectionInformation? collisionInformation)
|
private static bool DetectShapeShapeOneWay(IShapeCollider2D left, IShapeCollider2D right, ref CollisionDetectionInformation collisionInformation)
|
||||||
{
|
{
|
||||||
var vertices = left.ShapeWorld.Vertices;
|
var vertices = left.ShapeWorld.Vertices;
|
||||||
int count = vertices.Count;
|
int count = vertices.Count;
|
||||||
|
@ -57,14 +55,14 @@ public class CollisionDetector : ICollisionDetector
|
||||||
if (!leftProjection.Overlaps(rightProjection, out float depth))
|
if (!leftProjection.Overlaps(rightProjection, out float depth))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (collisionInformation == default || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth))
|
if (collisionInformation.Left is null || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth))
|
||||||
collisionInformation = new(left, right, projectionVector, depth);
|
collisionInformation = new(left, right, projectionVector, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DetectShapeCircle(IShapeCollider2D shapeCollider, ICircleCollider2D circleCollider, out CollisionDetectionInformation? collisionInformation)
|
private static bool DetectShapeCircle(IShapeCollider2D shapeCollider, ICircleCollider2D circleCollider, out CollisionDetectionInformation collisionInformation)
|
||||||
{
|
{
|
||||||
collisionInformation = default;
|
collisionInformation = default;
|
||||||
|
|
||||||
|
@ -77,7 +75,7 @@ public class CollisionDetector : ICollisionDetector
|
||||||
if (!shapeProjection.Overlaps(circleProjection, out float depth))
|
if (!shapeProjection.Overlaps(circleProjection, out float depth))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (collisionInformation == default || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth))
|
if (Math.Abs(collisionInformation.Penetration) > Math.Abs(depth))
|
||||||
collisionInformation = new(shapeCollider, circleCollider, shapeToCircleProjectionVector, depth);
|
collisionInformation = new(shapeCollider, circleCollider, shapeToCircleProjectionVector, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,14 +92,14 @@ public class CollisionDetector : ICollisionDetector
|
||||||
if (!shapeProjection.Overlaps(circleProjection, out float depth))
|
if (!shapeProjection.Overlaps(circleProjection, out float depth))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (collisionInformation == default || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth))
|
if (collisionInformation.Left is null || Math.Abs(collisionInformation.Penetration) > Math.Abs(depth))
|
||||||
collisionInformation = new(shapeCollider, circleCollider, projectionVector, depth);
|
collisionInformation = new(shapeCollider, circleCollider, projectionVector, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool DetectCircleCircle(ICircleCollider2D left, ICircleCollider2D right, out CollisionDetectionInformation? collisionInformation)
|
private static bool DetectCircleCircle(ICircleCollider2D left, ICircleCollider2D right, out CollisionDetectionInformation collisionInformation)
|
||||||
{
|
{
|
||||||
collisionInformation = default;
|
collisionInformation = default;
|
||||||
|
|
||||||
|
@ -118,7 +116,7 @@ public class CollisionDetector : ICollisionDetector
|
||||||
return collision;
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static bool DetectCircleCircle(ICircleCollider2D left, ICircleCollider2D right, out CollisionDetectionInformation? collisionInformation)
|
// private static bool DetectCircleCircle(ICircleCollider2D left, ICircleCollider2D right, out CollisionDetectionInformation collisionInformation)
|
||||||
// {
|
// {
|
||||||
// collisionInformation = default;
|
// collisionInformation = default;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
using Syntriax.Engine.Physics2D.Abstract;
|
using Syntriax.Engine.Physics2D.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
namespace Syntriax.Engine.Physics2D;
|
||||||
|
|
||||||
public interface ICollisionDetector
|
public interface ICollisionDetector
|
||||||
{
|
{
|
||||||
bool TryDetect<T1, T2>(T1 left, T2 right, [NotNullWhen(returnValue: true)] out CollisionDetectionInformation? collisionInformation) where T1 : ICollider2D where T2 : ICollider2D;
|
bool TryDetect<T1, T2>(T1 left, T2 right, out CollisionDetectionInformation collisionInformation) where T1 : ICollider2D where T2 : ICollider2D;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D
|
||||||
if (colliderX.RigidBody2D == colliderY.RigidBody2D)
|
if (colliderX.RigidBody2D == colliderY.RigidBody2D)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (collisionDetector.TryDetect(colliderX, colliderY, out CollisionDetectionInformation? information))
|
if (collisionDetector.TryDetect(colliderX, colliderY, out CollisionDetectionInformation information))
|
||||||
{
|
{
|
||||||
Vector2D displacementVector = .5f * information.Normal * information.Penetration;
|
Vector2D displacementVector = .5f * information.Normal * information.Penetration;
|
||||||
information.Left.Transform.Position -= displacementVector;
|
information.Left.Transform.Position -= displacementVector;
|
||||||
|
|
|
@ -2,4 +2,8 @@ using Syntriax.Engine.Physics2D.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
namespace Syntriax.Engine.Physics2D;
|
||||||
|
|
||||||
public record PhysicsMaterial2D(float Friction, float Restitution) : IPhysicsMaterial2D { }
|
public readonly struct PhysicsMaterial2D(float Friction, float Restitution) : IPhysicsMaterial2D
|
||||||
|
{
|
||||||
|
public readonly float Friction { get; init; } = Friction;
|
||||||
|
public readonly float Restitution { get; init; } = Restitution;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
using Syntriax.Engine.Physics2D.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D;
|
namespace Syntriax.Engine.Physics2D;
|
||||||
|
|
||||||
public record PhysicsMaterial2DDefault : PhysicsMaterial2D
|
public readonly struct PhysicsMaterial2DDefault : IPhysicsMaterial2D
|
||||||
{
|
{
|
||||||
public PhysicsMaterial2DDefault() : base(.1f, .1f) { }
|
public readonly float Friction => .1f;
|
||||||
|
|
||||||
|
public readonly float Restitution => .1f;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,14 @@ using Syntriax.Engine.Core;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||||
|
|
||||||
public record AABB(Vector2D LowerBoundary, Vector2D UpperBoundary)
|
public readonly struct AABB(Vector2D LowerBoundary, Vector2D UpperBoundary)
|
||||||
{
|
{
|
||||||
public Vector2D Center => (LowerBoundary + UpperBoundary) * .5f;
|
public readonly Vector2D LowerBoundary { get; init; } = LowerBoundary;
|
||||||
public Vector2D Size => LowerBoundary.FromTo(UpperBoundary).Abs();
|
public readonly Vector2D UpperBoundary { get; init; } = UpperBoundary;
|
||||||
public Vector2D SizeHalf => Size * .5f;
|
|
||||||
|
public readonly Vector2D Center => (LowerBoundary + UpperBoundary) * .5f;
|
||||||
|
public readonly Vector2D Size => LowerBoundary.FromTo(UpperBoundary).Abs();
|
||||||
|
public readonly Vector2D SizeHalf => Size * .5f;
|
||||||
|
|
||||||
public static AABB FromVectors(IEnumerable<Vector2D> vectors)
|
public static AABB FromVectors(IEnumerable<Vector2D> vectors)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,10 +3,13 @@ using Syntriax.Engine.Core.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||||
|
|
||||||
public record Circle(Vector2D Center, float Radius)
|
public readonly struct Circle(Vector2D Center, float Radius)
|
||||||
{
|
{
|
||||||
public float RadiusSquared => Radius * Radius;
|
public readonly Vector2D Center { get; init; } = Center;
|
||||||
public float Diameter => 2f * Radius;
|
public readonly float Radius { get; init; } = Radius;
|
||||||
|
|
||||||
|
public readonly float RadiusSquared => Radius * Radius;
|
||||||
|
public readonly float Diameter => 2f * Radius;
|
||||||
|
|
||||||
public static Circle SetCenter(Circle circle, Vector2D center) => new(center, circle.Radius);
|
public static Circle SetCenter(Circle circle, Vector2D center) => new(center, circle.Radius);
|
||||||
public static Circle SetRadius(Circle circle, float radius) => new(circle.Center, radius);
|
public static Circle SetRadius(Circle circle, float radius) => new(circle.Center, radius);
|
||||||
|
|
|
@ -6,12 +6,15 @@ using Syntriax.Engine.Core;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||||
|
|
||||||
public record Line(Vector2D From, Vector2D To)
|
public readonly struct Line(Vector2D From, Vector2D To)
|
||||||
{
|
{
|
||||||
public Line Reversed => new(To, From);
|
public readonly Vector2D From { get; init; } = From;
|
||||||
public Vector2D Direction => From.FromTo(To).Normalize();
|
public readonly Vector2D To { get; init; } = To;
|
||||||
public float Length => From.FromTo(To).Length();
|
|
||||||
public float LengthSquared => From.FromTo(To).LengthSquared();
|
public readonly Line Reversed => new(To, From);
|
||||||
|
public readonly Vector2D Direction => From.FromTo(To).Normalize();
|
||||||
|
public readonly float Length => From.FromTo(To).Length();
|
||||||
|
public readonly float LengthSquared => From.FromTo(To).LengthSquared();
|
||||||
|
|
||||||
public static LineEquation GetLineEquation(Line line)
|
public static LineEquation GetLineEquation(Line line)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,11 @@ using Syntriax.Engine.Core;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||||
|
|
||||||
public record LineEquation(float Slope, float OffsetY)
|
public readonly struct LineEquation(float Slope, float OffsetY)
|
||||||
{
|
{
|
||||||
|
public readonly float Slope { get; init; } = Slope;
|
||||||
|
public readonly float OffsetY { get; init; } = OffsetY;
|
||||||
|
|
||||||
public static float Resolve(LineEquation lineEquation, float x) => lineEquation.Slope * x + lineEquation.OffsetY; // y = mx + b
|
public static float Resolve(LineEquation lineEquation, float x) => lineEquation.Slope * x + lineEquation.OffsetY; // y = mx + b
|
||||||
|
|
||||||
public static bool ApproximatelyEquals(LineEquation left, LineEquation right)
|
public static bool ApproximatelyEquals(LineEquation left, LineEquation right)
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||||
|
|
||||||
public record Projection(float Min, float Max)
|
public readonly struct Projection(float Min, float Max)
|
||||||
{
|
{
|
||||||
|
public readonly float Min { get; init; } = Min;
|
||||||
|
public readonly float Max { get; init; } = Max;
|
||||||
|
|
||||||
public static bool Overlaps(Projection left, Projection right) => Overlaps(left, right, out var _);
|
public static bool Overlaps(Projection left, Projection right) => Overlaps(left, right, out var _);
|
||||||
public static bool Overlaps(Projection left, Projection right, out float depth)
|
public static bool Overlaps(Projection left, Projection right, out float depth)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,13 +6,15 @@ using Syntriax.Engine.Core.Abstract;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||||
|
|
||||||
public record Shape(IList<Vector2D> Vertices) : IEnumerable<Vector2D>
|
public readonly struct Shape(IList<Vector2D> Vertices) : IEnumerable<Vector2D>
|
||||||
{
|
{
|
||||||
public static readonly Shape Triangle = CreateNgon(3, Vector2D.Up);
|
public static readonly Shape Triangle = CreateNgon(3, Vector2D.Up);
|
||||||
public static readonly Shape Box = CreateNgon(4, Vector2D.One);
|
public static readonly Shape Box = CreateNgon(4, Vector2D.One);
|
||||||
public static readonly Shape Pentagon = CreateNgon(5, Vector2D.Up);
|
public static readonly Shape Pentagon = CreateNgon(5, Vector2D.Up);
|
||||||
public static readonly Shape Hexagon = CreateNgon(6, Vector2D.Right);
|
public static readonly Shape Hexagon = CreateNgon(6, Vector2D.Right);
|
||||||
|
|
||||||
|
public readonly IList<Vector2D> Vertices { get; init; } = Vertices;
|
||||||
|
|
||||||
|
|
||||||
public Vector2D this[System.Index index] => Vertices[index];
|
public Vector2D this[System.Index index] => Vertices[index];
|
||||||
|
|
||||||
|
@ -89,9 +91,9 @@ public record Shape(IList<Vector2D> Vertices) : IEnumerable<Vector2D>
|
||||||
float min = float.MaxValue;
|
float min = float.MaxValue;
|
||||||
float max = float.MinValue;
|
float max = float.MinValue;
|
||||||
|
|
||||||
foreach (var vertex in shape)
|
for (int i = 0; i < shape.Vertices.Count; i++)
|
||||||
{
|
{
|
||||||
float projectedLength = projectionVector.Dot(vertex);
|
float projectedLength = projectionVector.Dot(shape.Vertices[i]);
|
||||||
min = Math.Min(projectedLength, min);
|
min = Math.Min(projectedLength, min);
|
||||||
max = Math.Max(projectedLength, max);
|
max = Math.Max(projectedLength, max);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,13 @@ using Syntriax.Engine.Core;
|
||||||
|
|
||||||
namespace Syntriax.Engine.Physics2D.Primitives;
|
namespace Syntriax.Engine.Physics2D.Primitives;
|
||||||
|
|
||||||
public record Triangle(Vector2D A, Vector2D B, Vector2D C)
|
public readonly struct Triangle(Vector2D A, Vector2D B, Vector2D C)
|
||||||
{
|
{
|
||||||
public float Area
|
public readonly Vector2D A { get; init; } = A;
|
||||||
|
public readonly Vector2D B { get; init; } = B;
|
||||||
|
public readonly Vector2D C { get; init; } = C;
|
||||||
|
|
||||||
|
public readonly float Area
|
||||||
=> .5f * MathF.Abs(
|
=> .5f * MathF.Abs(
|
||||||
A.X * (B.Y - C.Y) +
|
A.X * (B.Y - C.Y) +
|
||||||
B.X * (C.Y - A.Y) +
|
B.X * (C.Y - A.Y) +
|
||||||
|
|
Loading…
Reference in New Issue