Syntriax.Engine/Engine.Physics2D/Collider2DBehaviourBase.cs

93 lines
4.8 KiB
C#

using Syntriax.Engine.Core;
namespace Syntriax.Engine.Physics2D;
public abstract class Collider2DBehaviourBase : Behaviour2D, ICollider2D
{
public Event<ICollider2D, CollisionDetectionInformation> OnCollisionDetected { get; } = new();
public Event<ICollider2D, CollisionDetectionInformation> OnCollisionResolved { get; } = new();
public Event<ICollider2D, ICollider2D> OnTriggered { get; } = new();
private readonly Event<IBehaviourController, IBehaviourController.BehaviourAddedArguments>.EventHandler cachedOnBehaviourAddedToController = null!;
private readonly Event<IBehaviourController, IBehaviourController.BehaviourRemovedArguments>.EventHandler cachedOnBehaviourRemovedFromController = null!;
private readonly Event<ITransform2D, ITransform2D.PositionChangedArguments>.EventHandler cachedSetNeedsRecalculationFromPosition = null!;
private readonly Event<ITransform2D, ITransform2D.RotationChangedArguments>.EventHandler cachedSetNeedsRecalculationFromRotation = null!;
private readonly Event<ITransform2D, ITransform2D.ScaleChangedArguments>.EventHandler cachedSetNeedsRecalculationFromScale = null!;
private readonly Event<IUniverseObject, IUniverseObject.ParentChangedArguments>.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);
}