From 37f4f56cd66e762bba0b470ba3591d5f18fca15c Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sat, 4 Apr 2026 19:38:24 +0300 Subject: [PATCH] feat(physics): IRigidbody Intertia and Inverse Mass & Intertia fields added --- Engine.Physics2D/Abstract/IRigidBody2D.cs | 15 +++++ Engine.Physics2D/RigidBody2D.cs | 67 +++++++++++++++++++++-- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/Engine.Physics2D/Abstract/IRigidBody2D.cs b/Engine.Physics2D/Abstract/IRigidBody2D.cs index 871fc0e..5c0fa27 100644 --- a/Engine.Physics2D/Abstract/IRigidBody2D.cs +++ b/Engine.Physics2D/Abstract/IRigidBody2D.cs @@ -27,6 +27,21 @@ public interface IRigidBody2D : IBehaviour2D /// float Mass { get; set; } + /// + /// The inverse mass (1 / Mass) of the . + /// + float InverseMass { get; } + + /// + /// The Invertia of the . + /// + float Inertia { get; } + + /// + /// The inverse Invertia (1 / Invertia) of the . + /// + float InverseInertia { get; } + /// /// The value indicating whether the is static/immovable. /// diff --git a/Engine.Physics2D/RigidBody2D.cs b/Engine.Physics2D/RigidBody2D.cs index dbf97be..92d54d2 100644 --- a/Engine.Physics2D/RigidBody2D.cs +++ b/Engine.Physics2D/RigidBody2D.cs @@ -1,16 +1,75 @@ +using System.Collections.Generic; + using Engine.Core; namespace Engine.Physics2D; -public class RigidBody2D : Behaviour2D, IRigidBody2D +public class RigidBody2D : Behaviour2D, IRigidBody2D, IFirstFrameUpdate, ILastFrameUpdate { private const float LOWEST_ALLOWED_MASS = 0.00001f; - public IPhysicsMaterial2D Material { get; set; } = ReadOnlyPhysicsMaterial2D.Default; + public IPhysicsMaterial2D Material { get; set; } = new PhysicsMaterial2D(0f, 0f); - public Vector2D Velocity { get; set; } = Vector2D.Zero; + public Vector2D Velocity { get => IsStatic ? Vector2D.Zero : field; set => field = IsStatic ? Vector2D.Zero : value; } = Vector2D.Zero; public float AngularVelocity { get; set; } = 0f; public bool IsStatic { get; set; } = false; - public float Mass { get; set => field = Math.Max(value, LOWEST_ALLOWED_MASS); } = 1f; + public float Mass { get; set { field = Math.Max(value, LOWEST_ALLOWED_MASS); } } = 1f; + public float InverseMass { get; protected set; } = 1f; + + public float Inertia { get; protected set; } = 1f; + public float InverseInertia { get; protected set; } = 1f; + + private readonly List childColliders = []; + + public void LastActiveFrame() => DisconnectColliders(); + public void FirstActiveFrame() + { + ReconnectColliders(); + UpdateValues(); + } + + private void ReconnectColliders() + { + DisconnectColliders(); + + BehaviourController.GetBehavioursInChildren(childColliders); + + foreach (ICollider2D collider in childColliders) + collider.OnRecalculated.AddListener(RecalculateCallback); + } + + private void DisconnectColliders() + { + foreach (ICollider2D collider in childColliders) + collider.OnRecalculated.RemoveListener(RecalculateCallback); + } + + private void RecalculateCallback(ICollider2D _) => UpdateValues(); + private void UpdateValues() + { + InverseMass = Mass.OneOver(); + + Vector2D center = Transform.Position; + Inertia = 0f; + + float totalColliderArea = 0f; + + foreach (ICollider2D collider in childColliders) + totalColliderArea += collider.Area; + + foreach (ICollider2D collider in childColliders) + { + float colliderMass = Mass * (collider.Area / totalColliderArea); + float colliderInertia = collider.GeometricInertia * colliderMass; + float distanceSquared = center.FromTo(collider.Transform.Position).MagnitudeSquared; + + Inertia += colliderInertia + colliderMass * distanceSquared; + } + + if (childColliders.Count == 0) + Inertia = 1f; + + InverseInertia = Inertia.OneOver(); + } }