From 8619778d52c0b98c6fbf2dd09b7a99a39f443661 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 30 Jan 2024 19:31:01 +0300 Subject: [PATCH] feat: PhysicsEngine2DCacher This class uses BehaviourCacher to track IGameManager's Rigidbody2D & Collider2Ds --- Engine.Physics2D/PhysicsEngine2DCacher.cs | 126 ++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 Engine.Physics2D/PhysicsEngine2DCacher.cs diff --git a/Engine.Physics2D/PhysicsEngine2DCacher.cs b/Engine.Physics2D/PhysicsEngine2DCacher.cs new file mode 100644 index 0000000..30b3f95 --- /dev/null +++ b/Engine.Physics2D/PhysicsEngine2DCacher.cs @@ -0,0 +1,126 @@ +using System; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Physics2D.Abstract; + +namespace Syntriax.Engine.Physics2D; + +public class PhysicsEngine2DCacher : IPhysicsEngine2D, IAssignableGameManager +{ + public Action? OnUnassigned { get; set; } = null; + public Action? OnGameManagerAssigned { get; set; } = null; + + + private int _iterationCount = 1; + + protected ICollisionDetector2D collisionDetector = new CollisionDetector2D(); // TODO Dependency Injection or Reversion + protected ICollisionResolver2D collisionResolver = new CollisionResolver2D(); // TODO Dependency Injection or Reversion + protected BehaviourCacher rigidBodyCacher = new(); + protected BehaviourCacher colliderCacher = new(); + + + public int IterationCount { get => _iterationCount; set => _iterationCount = value < 1 ? 1 : value; } + public IGameManager GameManager { get; private set; } = null!; + + public void Step(float deltaTime) + { + float intervalDeltaTime = deltaTime / IterationCount; + + for (int iterationIndex = 0; iterationIndex < IterationCount; iterationIndex++) + { + // Can Parallel + foreach (var rigidBody in rigidBodyCacher) + StepRigidBody(rigidBody, intervalDeltaTime); + + // Can Parallel + foreach (var collider in colliderCacher) + collider.Recalculate(); + + // Can Parallel + for (int x = 0; x < colliderCacher.Behaviours.Count; x++) + { + ICollider2D? colliderX = colliderCacher.Behaviours[x]; + if (!colliderX.IsActive) + return; + + for (int y = x + 1; y < colliderCacher.Behaviours.Count; y++) + { + ICollider2D? colliderY = colliderCacher.Behaviours[y]; + + if (!colliderY.IsActive) + return; + + if (colliderX.RigidBody2D == colliderY.RigidBody2D) + continue; + + bool bothCollidersAreTriggers = colliderX.IsTrigger && colliderX.IsTrigger == colliderY.IsTrigger; + if (bothCollidersAreTriggers) + continue; + + bool bothCollidersAreStatic = colliderX.RigidBody2D?.IsStatic ?? true && colliderX.RigidBody2D?.IsStatic == colliderY.RigidBody2D?.IsStatic; + if (bothCollidersAreStatic) + continue; + + if (collisionDetector.TryDetect(colliderX, colliderY, out CollisionDetectionInformation information)) + { + if (colliderX.IsTrigger) + { + colliderX.OnTriggered?.Invoke(colliderX, colliderY); + continue; + } + else if (colliderY.IsTrigger) + { + colliderY.OnTriggered?.Invoke(colliderY, colliderY); + continue; + } + + colliderX.OnCollisionDetected?.Invoke(colliderX, information); + colliderY.OnCollisionDetected?.Invoke(colliderY, information); + + collisionResolver?.Resolve(information); + } + } + } + } + } + + private static void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime) + { + if (rigidBody.IsStatic || !rigidBody.IsActive) + return; + + rigidBody.Transform.Position += rigidBody.Velocity * intervalDeltaTime; + rigidBody.Transform.Rotation += rigidBody.AngularVelocity * intervalDeltaTime; + } + + public bool Assign(IGameManager gameManager) + { + if (GameManager is not null) + return false; + + colliderCacher.Assign(gameManager); + rigidBodyCacher.Assign(gameManager); + + GameManager = gameManager; + OnGameManagerAssigned?.Invoke(this); + + return true; + } + + public bool Unassign() + { + if (GameManager is null) + return false; + + colliderCacher.Unassign(); + rigidBodyCacher.Unassign(); + + GameManager = null!; + OnUnassigned?.Invoke(this); + return true; + } + + public PhysicsEngine2DCacher() { } + public PhysicsEngine2DCacher(IGameManager gameManager) => Assign(gameManager); +}