using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D; public abstract class Collider2DBehaviourBase : Behaviour2D, ICollider2D { public Event OnCollisionDetected { get; } = new(); public Event OnCollisionResolved { get; } = new(); public Event OnTriggered { get; } = new(); private readonly Event.EventHandler cachedOnBehaviourAddedToController = null!; private readonly Event.EventHandler cachedOnBehaviourRemovedFromController = null!; private readonly Event.EventHandler cachedSetNeedsRecalculationFromPosition = null!; private readonly Event.EventHandler cachedSetNeedsRecalculationFromRotation = null!; private readonly Event.EventHandler cachedSetNeedsRecalculationFromScale = null!; private readonly Event.EventHandler cachedUpdateRigidBody2D = null!; protected bool NeedsRecalculation { get; set; } = true; protected IRigidBody2D? _rigidBody2D = null; protected Collider2DBehaviourBase() { cachedOnBehaviourAddedToController = OnBehaviourAddedToController; cachedOnBehaviourRemovedFromController = OnBehaviourRemovedFromController; cachedSetNeedsRecalculationFromPosition = SetNeedsRecalculationFromPosition; cachedSetNeedsRecalculationFromRotation = SetNeedsRecalculationFromRotation; cachedSetNeedsRecalculationFromScale = SetNeedsRecalculationFromScale; cachedUpdateRigidBody2D = UpdateRigidBody2D; } public IRigidBody2D? RigidBody2D => _rigidBody2D; public bool IsTrigger { get; set; } = false; public void Recalculate() { if (!NeedsRecalculation) return; CalculateCollider(); NeedsRecalculation = false; } public abstract void CalculateCollider(); protected override void OnInitialize() { BehaviourController.TryGetBehaviourInParent(out _rigidBody2D); BehaviourController.OnBehaviourAdded.AddListener(cachedOnBehaviourAddedToController); BehaviourController.OnBehaviourRemoved.AddListener(cachedOnBehaviourRemovedFromController); Transform.OnPositionChanged.AddListener(cachedSetNeedsRecalculationFromPosition); Transform.OnRotationChanged.AddListener(cachedSetNeedsRecalculationFromRotation); Transform.OnScaleChanged.AddListener(cachedSetNeedsRecalculationFromScale); UniverseObject.OnParentChanged.AddListener(cachedUpdateRigidBody2D); } private void UpdateRigidBody2D(IUniverseObject sender, IUniverseObject.ParentChangedArguments arguments) { BehaviourController.TryGetBehaviourInParent(out _rigidBody2D); } private void OnBehaviourAddedToController(IBehaviourController sender, IBehaviourController.BehaviourAddedArguments arguments) { if (arguments.BehaviourAdded is IRigidBody2D rigidBody) _rigidBody2D = rigidBody; } private void OnBehaviourRemovedFromController(IBehaviourController sender, IBehaviourController.BehaviourRemovedArguments arguments) { if (arguments.BehaviourRemoved is IRigidBody2D) _rigidBody2D = null; } private void SetNeedsRecalculationFromPosition(ITransform2D sender, ITransform2D.PositionChangedArguments arguments) => NeedsRecalculation = true; private void SetNeedsRecalculationFromScale(ITransform2D sender, ITransform2D.ScaleChangedArguments arguments) => NeedsRecalculation = true; private void SetNeedsRecalculationFromRotation(ITransform2D sender, ITransform2D.RotationChangedArguments arguments) => NeedsRecalculation = true; protected override void OnFinalize() { BehaviourController.OnBehaviourAdded.RemoveListener(cachedOnBehaviourAddedToController); BehaviourController.OnBehaviourRemoved.RemoveListener(cachedOnBehaviourRemovedFromController); Transform.OnScaleChanged.RemoveListener(cachedSetNeedsRecalculationFromScale); Transform.OnPositionChanged.RemoveListener(cachedSetNeedsRecalculationFromPosition); Transform.OnRotationChanged.RemoveListener(cachedSetNeedsRecalculationFromRotation); } public void Detect(CollisionDetectionInformation collisionDetectionInformation) => OnCollisionDetected?.Invoke(this, collisionDetectionInformation); public void Resolve(CollisionDetectionInformation collisionDetectionInformation) => OnCollisionResolved?.Invoke(this, collisionDetectionInformation); public void Trigger(ICollider2D initiator) => OnTriggered?.Invoke(this, initiator); }