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 delegateOnBehaviourAddedToController = null!; private readonly Event.EventHandler delegateOnBehaviourRemovedFromController = null!; private readonly Event.EventHandler delegateSetNeedsRecalculationFromPosition = null!; private readonly Event.EventHandler delegateSetNeedsRecalculationFromRotation = null!; private readonly Event.EventHandler delegateSetNeedsRecalculationFromScale = null!; private readonly Event.EventHandler delegateUpdateRigidBody2D = null!; protected bool NeedsRecalculation { get; set; } = true; protected IRigidBody2D? _rigidBody2D = null; protected Collider2DBehaviourBase() { delegateOnBehaviourAddedToController = OnBehaviourAddedToController; delegateOnBehaviourRemovedFromController = OnBehaviourRemovedFromController; delegateSetNeedsRecalculationFromPosition = SetNeedsRecalculationFromPosition; delegateSetNeedsRecalculationFromRotation = SetNeedsRecalculationFromRotation; delegateSetNeedsRecalculationFromScale = SetNeedsRecalculationFromScale; delegateUpdateRigidBody2D = 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(delegateOnBehaviourAddedToController); BehaviourController.OnBehaviourRemoved.AddListener(delegateOnBehaviourRemovedFromController); Transform.OnPositionChanged.AddListener(delegateSetNeedsRecalculationFromPosition); Transform.OnRotationChanged.AddListener(delegateSetNeedsRecalculationFromRotation); Transform.OnScaleChanged.AddListener(delegateSetNeedsRecalculationFromScale); UniverseObject.OnParentChanged.AddListener(delegateUpdateRigidBody2D); } private void UpdateRigidBody2D(IUniverseObject sender, IUniverseObject.ParentChangedArguments args) { BehaviourController.TryGetBehaviourInParent(out _rigidBody2D); } private void OnBehaviourAddedToController(IBehaviourController sender, IBehaviourController.BehaviourAddedArguments args) { if (args.BehaviourAdded is IRigidBody2D rigidBody) _rigidBody2D = rigidBody; } private void OnBehaviourRemovedFromController(IBehaviourController sender, IBehaviourController.BehaviourRemovedArguments args) { if (args.BehaviourRemoved is IRigidBody2D) _rigidBody2D = null; } private void SetNeedsRecalculationFromPosition(ITransform2D sender, ITransform2D.PositionChangedArguments args) => NeedsRecalculation = true; private void SetNeedsRecalculationFromScale(ITransform2D sender, ITransform2D.ScaleChangedArguments args) => NeedsRecalculation = true; private void SetNeedsRecalculationFromRotation(ITransform2D sender, ITransform2D.RotationChangedArguments args) => NeedsRecalculation = true; protected override void OnFinalize() { BehaviourController.OnBehaviourAdded.RemoveListener(delegateOnBehaviourAddedToController); BehaviourController.OnBehaviourRemoved.RemoveListener(delegateOnBehaviourRemovedFromController); Transform.OnScaleChanged.RemoveListener(delegateSetNeedsRecalculationFromScale); Transform.OnPositionChanged.RemoveListener(delegateSetNeedsRecalculationFromPosition); Transform.OnRotationChanged.RemoveListener(delegateSetNeedsRecalculationFromRotation); } 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); }